comparison CoCoOS9/level2v3/MODULES/pipeman_named.asm @ 31:bd2b07db8917 cocoos9lv2v3

CoCoOS9 version
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Sat, 14 Jul 2018 15:16:13 +0900
parents
children
comparison
equal deleted inserted replaced
30:7b1b25ff010a 31:bd2b07db8917
1 ********************************************************************
2 * PipeMan - OS-9 Level Two Named Pipe File Manager
3 *
4 * $Id: pipeman_named.asm,v 1.1.1.1 2001/02/21 23:30:55 boisy Exp $
5 *
6 * Ed. Comments Who YY/MM/DD
7 * ------------------------------------------------------------------
8 * Pipeman Modified to Include the SS.Ready KDM 86/02/23
9 * I$GETSTT Call.
10 * Major Bug Corrected KDM 86/03/26
11 * Upgraded to Level II version KDM 88/06/29
12 * Added new labels and special defs
13 * Added code to detect EOF in SS.Ready
14 * Reformatted to make the module easier CJB 88/11/11
15 * to understand during coding
16 * Added named pipes, etc for Level 2 upgrade CJB 88/12/03
17 * Includes SS.SSig, SS.Relea, SS.Attr, SS.FD
18 * 1 Release 1.0 for Tandy CoCo OS9 CJB 88/12/26
19
20 nam PipeMan
21 ttl OS9 Level Two Named Pipe File Manager
22
23 *
24 * Copyright 1981, 1985, 1986, 1988 by Microware Systems Corporation
25 * All Rights Reserved
26 *
27 * Named pipe code by Burke & Burke.
28 * All rights assigned to Microware Systems Corporation.
29 *
30 * This file contains proprietary information of Microware Systems
31 * Corporation. Persons accessing this file will be held strictly
32 * accountable for their use of the information herein.
33 *
34
35 *
36 * PIPEMAN
37 *
38 * Pipe File Manager
39 *
40 * WARNING
41 * -------
42 *
43 * Opening an existing named pipe emulates IOMan's I$Close and
44 * I$Dup calls. This file manager contains subroutines that
45 * mimic the current operation of IOMan. Any changes to IOMan's
46 * FMEXEC, I$Close or I$Dup calls must also be made to this code.
47 *
48 * Device Driver Static Storage Layout
49 * -----------------------------------
50 *
51 * $00-$01 V.List Pointer in system map to pipe buffer for 1st
52 * pipe (16 bits).
53 *
54 * Pipe Buffer Data Structure
55 * --------------------------
56 *
57 * $00-$01 PP.PD Pointer to shared path descriptor
58 * $02-$03 PP.Next Pointer to next pipe buffer in system map
59 * $04-$05 PP.Prev Pointer to previous pipe buffer in system map
60 * $06-$07 PP.Rsv2 Reserved
61 *
62 * $08 PP.Data Data buffer begins at this offset
63 *
64 * Path Descriptor Data Structure
65 * ------------------------------
66 *
67 * $00 PD.PD Path number
68 * $01 PD.MOD Access permissions
69 * $02 PD.CNT Number of open images (e.g. I$DUP)
70 * $05 PD.CPR Current process ID
71 * $06-$07 PD.RGS Address of caller's register stack
72 * $08-$09 PD.BUF System space pipe buffer base pointer
73 *** PP.Read must have bit 4 clear; PP.Writ must be PP.Read XOR 4
74 * $0A PD.Read No bytes -- offset only
75 * $0A PD.RPID Process ID of reader waiting on signal
76 * $0B PD.RCT Number of blocked readers
77 * $0C PD.RSIG Signal to send reader
78 * $0D PD.REOR Read EOR character
79 * $0E PD.Writ No bytes -- offset only
80 * $0E PD.WPID Process ID of writer waiting on signal
81 * $0F PD.WCT Number of blocked writers
82 * $10 PD.WSIG Signal to send writer
83 * $11 PD.WEOR Write EOR character (dummy)
84 *** End of special section
85 * $12-$13 PD.End Pointer to end of pipe buffer
86 * $14-$15 PD.NxtI Next in pointer
87 * $16-$17 PD.NxtO Next out pointer
88 * $18 PD.RFlg "Ready" flag
89 * $19 PD.Wrtn "Written" flag
90 * $1A-$1B PD.BCnt # queue elements currently bufered
91 * $1C PD.Own Process ID of pipe original creator
92 * $1D PD.Keep Non-zero if this pipe has been kept open artificially
93 * $1E-$1F PD.QSiz Max. size of queue (in elements)
94 * .
95 * .
96 * $20 PD.DTP Device type $02 = PIPE
97 * $21 PD.ESiz Size of each queue element
98 * $22-$23 PD.ECnt Max. elements in queue
99 * $23-$3F PD.Name Pipe name (after moving PD.ECnt to PD.QSiz)
100 *
101
102 page
103 *
104 * Global equates
105 *
106 ifp1
107 use defsfile
108 use pipedefs.l2v3
109 * use rbfdefs
110 endc
111
112 *
113 * Local Equates
114 *
115
116 XVER equ 3 ;Version
117
118 * ASCII CONTROL CHARACTERS
119
120 CR equ $0D
121
122 * CONDITION CODES
123
124 NCARRY equ $00FE
125
126 * PIPEMAN SPECIAL OFFSETS.
127
128 PM.CPR equ PD.RPID-PD.READ
129 PM.CNT equ PD.RCT-PD.READ
130 PM.SIG equ PD.RSIG-PD.READ
131 PM.EOR equ PD.REOR-PD.READ
132
133 * IOMAN special offsets.
134 *
135 * This constant is IOMAN release-dependent.
136 * It is the number of bytes between the entry stack
137 * pointer and the stacked PD pointer saved by *IOMAN*.
138 * Currently, the stack looks like this:
139 *
140 * A PL
141 * 9 PH <IOMAN post-SOPEN return address>
142 * 8 UL
143 * 7 UH
144 * 6 YL +
145 * 5 YH <PD pointer saved by IOMAN>
146 * 4 XL
147 * 3 XH
148 * 2 A
149 * 1 PL
150 * SP-> 0 PH <post OPEN/CREATE return address>
151 * <start of stack to be used by PIPEMAN>
152
153 IOMAGIC equ 5 ;5 bytes to PD pointer
154
155 * Local pipe buffer equates
156
157 CInit equ %00100000 ;Set this bit to override PD queue parameters
158
159 * Conditional assembly
160
161 ANON set 0 ;Anonymous pipes only
162 NAMED set 1 ;Anonymous and named pipes
163 MSGS set 2 ;Both types of pipes, and message queues
164 WIZBANG set NAMED ;What features are we providing?
165
166 NODIR set 0 ;Don't allow DIR on pipe devices
167 YESDIR set 1 ;Allow DIR on pipe devices
168 PIPEDIR set YESDIR ;Does DIR work on pipes?
169
170 SLOWPD set 0 ;Slow PD location algorithm
171 QUICKPD set 1 ;Fast PD location algorithm
172 PDALGO set QUICKPD ;How to convert PD to system path #
173
174 RECKLES set 0 ;Don't check for certain errors
175 CAREFUL set 1 ;Check for certain errors
176 CAUTION set CAREFUL
177
178 page
179 *
180 * Module Header
181 *
182
183 edition set 1
184
185 mod MODSIZE,MODNAM,FlMgr+Objct,ReEnt+XVER,JmpTbl,$0000
186
187 * Module Name
188
189 MODNAM fcs "PipeMan"
190 fcb edition
191
192 * Jump table
193
194 JmpTbl lbra Create
195 lbra Open
196 lbra MakDir
197 lbra ChgDir
198 lbra Delete
199 lbra Seek
200 lbra Read
201 lbra Write
202 lbra ReadLn
203 lbra WriteLn
204 lbra GetStt
205 lbra SetStt
206 lbra Close
207
208 page
209 *
210 * Create a named or anonymous pipe
211 *
212 * The size of the queue is determined by examining
213 * the path descriptor, since this information has
214 * been copied there from the device descriptor.
215 *
216 * Reg-U points to stacked registers of user.
217 * Reg-Y points to path descriptor
218 *
219 * If success, carry clear and X points to pipe buffer
220 *
221
222 * Create function allows user to override both element
223 * count and element size. Override is enabled if if bit
224 * 5 of the access mode is set. For override, if MS bit
225 * of Reg-Y is clear, just use Reg-Y as queue element
226 * count. If MS bit of Reg-Y is set, use LS byte of
227 * Reg-Y as element size ($00 = no change) and bottom 7
228 * bits of MS byte of Reg-Y as element count ($00 = no change)
229
230 Create equ *
231
232 lda R$A,U ;Get access mode
233 bita #CInit
234 beq Open
235
236 * Handle queue size override
237
238 ldd R$Y,U ;Get queue size initializer
239 bpl SetCnt ; (branch if just setting count)
240
241 * Set element size and count
242
243 tstb
244 beq Creat00 ; (branch if using default size)
245
246 stb PD.ESiz,Y ;Reg-B = size of each element
247
248 Creat00 anda #$7F
249 beq Open ; (branch if using default count)
250
251 tfr a,B
252 clra
253
254 * Set number of elements in queue from Reg-D
255
256 SetCnt std PD.ECnt,Y ;Reg-D = number of elements
257
258 * Enter here for normal OPEN
259
260 Open equ *
261
262 * Move number of elements in queue to make room for name
263
264 ldd PD.ECnt,Y
265 std PD.QSiz,Y
266
267 * Parse pathname
268
269 clrb ;Assume anonymous pipe
270 clra ;Assume not 1st pipe
271 ldx R$X,U ;Point at file name in user's space
272 pshs U,Y,X,D ;Save file name, PD, reg. base, 1st & anon flag
273
274 * Caller's Regs Ptr
275 * PD Ptr
276 * Path name uptr
277 * Named flag
278 * SP-> First flag
279
280 os9 F$PrsNam ;Error if driver name (e.g. /pipe) invalid
281 bcs BadName
282
283 * See if named or anonymous pipe requested.
284
285 lbsr GtNext ;Return CC=MI if at end of path name
286 cmpa #'/
287 beq HasName
288
289 * /pipe____
290 * X Y
291 * Pipe is anonymous -- set up dummy name in PD.
292 * Stack must match the named pipe setup
293
294 NotName tfr Y,X ;Skip any trailing blanks
295 os9 F$PrsNam ; (should return carry set)
296 ldd #1 ;Length of dummy name
297 pshs Y,X,D
298
299 ldy 10,S ;Get PD pointer
300 clr PD.Name,Y ; and set dummy name
301
302 bra GoCheck
303
304 * /pipe/foo____
305 * X Y
306 * Pipe is named -- check length and flag on stack
307
308 HasName tfr Y,X
309 os9 F$PrsNam ;Scan off the name
310 bcs BadName
311
312 cmpb #NameMax ;Check length of name
313 bhi BadName
314
315 * Length OK. X points to start of name, Y to end of name,
316 * B has name length.
317 * Save registers & length, and do final parse to skip white
318
319 com 1,S ;Set "named" flag
320 clra
321 pshs Y,X,D
322
323 tfr Y,X
324 os9 F$PrsNam ;Error if trying for pipe subdirectory
325 bcc BadNam2
326
327 * /pipe/foo____
328 * X Y
329 * Need to get the pipe name into our address space
330 * Use the PD for a temporary buffer.
331
332 NameOK ldx <D.Proc ;Pointer to caller's PD
333 lda P$Task,X ; get caller's DAT image #
334 ldx <D.SysPrc ;Pointer to our PD
335 ldb P$Task,X ; get system's DAT image #
336 ldy 0,S ;Byte count
337 ldx 2,S ;Source address
338 ldu 10,S ;Get PD pointer and convert to . . .
339 leau PD.Name,U ;Destination address
340 lbsr MovSet ;Move block, set MSB of last byte.
341
342 * Wow! Everybody's in the same address space now.
343
344 * Since this is a named pipe, force mode to UPDATE.
345 * Also, do not permit DIR. access
346
347 ldx 10,S
348 lda PD.MOD,X
349 bita #DIR.
350 bne BadNam2
351
352 ora #(READ.+WRITE.)
353 sta PD.MOD,X
354
355 * See if this is an existing pipe. To do this, we
356 * must get the linked list head pointer from the
357 * device driver's static storage.
358 *
359 * Stack looks like this:
360 *
361 * C 2 Sysmap Reg Pointer
362 * A 2 Sysmap PD Pointer
363 * 8 2 Usrmap Path name pointer
364 * 7 1 Named pipe flag
365 * 6 1 First pipe flag
366 * 4 2 Usrmap Pipe name end pointer
367 * 2 2 Usrmap Pipe name start pointer
368 * 0 2 Name length
369 * sp->
370
371 GoCheck ldx 10,S ;Get PD pointer
372 ldx PD.DEV,X ;Get device table pointer
373 ldu V$Stat,X ;Get static storage pointer
374 ldx V.List,U ;Get pointer to head of pipe bfr linked list
375 bne Not1st ; (reg-X = $0000 if no previous pipes)
376
377 * This is the 1st pipe for this descriptor.
378 * Reg-X = $0000
379 * Set flag and process as a new pipe.
380
381 com 6,S ;This is the first pipe
382 bra NewPipe ;This is a new pipe
383
384 * No time like the present for some error handlers
385
386 * Generic error, cleaning stack
387
388 BadXit2 leas 8,S
389 coma ;Set carry
390 rts
391
392 * Bad Pathname -- 2 versions, depending on
393 * how much junk is on the stack.
394
395 BadNam2 leas 6,S ;Clean stack
396 BadName ldb #E$BPNam
397 bra BadXit2
398
399 * Not Enough System RAM
400
401 TooBig ldb #E$NoRAM
402 BadExit leas 6,S ;Clean stack
403 bra BadXit2
404
405 * Look up the pipe name, unless the pipe is anonymous.
406 *
407 * Reg-U points to driver static storage.
408 * Reg-X points to next pipe buffer to check.
409
410 Not1st tst 7,S ;Unnamed pipes are always new
411 beq NewPipe
412
413 ldy 10,S ;point at PD
414 leay PD.Name,Y ; then point at name in PD
415
416 * Main loop. Always at least 1 pipe buffer to check first time through.
417 * Reg-X points to buffer to check, or $0000 if none.
418 * Reg-Y points to desired pipe name.
419
420 ChkLoop pshs X
421 ldx PP.PD,X ;Point at PD for this pipe buffer
422 leax PD.Name,X ; and then point at name stored in PD
423 lbsr Compare
424 puls X
425 lbeq OldPipe ; (got a match)
426
427 ldd PP.Next,X ;Don't fall off the edge
428 beq NewPipe ; (end of list)
429
430 tfr D,X ;Advance to next buffer
431 bra ChkLoop
432
433 * Pipe name not found. Create a new pipe.
434 *
435 * Reg-U points to driver static storage.
436 * Reg-X points to last pipe buffer checked ($0000 if 1st pipe)
437
438 NewPipe ldy 10,S ;Get PD pointer
439
440 ifeq (PIPEDIR-YESDIR)
441 lda PD.MOD,Y ;Check pipe attributes
442 bita #DIR.
443 beq NEWP1
444
445 * Initialize pipe characteristics for DIR. bit set
446
447 lbsr SizDirP
448 * beq XYZZY ;Special if no pipes created
449 endc
450
451 * Normal (non-dir) processing
452
453 NewP1 ldd PD.QSiz,Y ;Get max element count
454 bne DoNew ; (graceful operation if no count)
455
456 * Default pipe parameters if none in PD.
457
458 ldd #$0100 ;Assume 256 byte buffer, 1 byte element
459 sta PD.ESiz,Y ;Reg-A = 1
460 subd #PP.Data ;Compute elements for total size = 256
461 std PD.QSiz,Y Use parameters in PD
462
463 DoNew lbsr ECtoBC ;Convert element count to byte count in D
464 bcs TooBig ; (carry set if too big)
465
466 * Carry has exit status
467 * Reg-D = # bytes for queue, w/o overhead
468 * Reg-X = previous buffer
469 * Reg-U = driver static storage
470
471 tfr U,Y ;Save static storage pointer
472
473 addd #PP.Data ;Add in overhead
474 bcs TooBig
475
476 pshs D ;Save buffer size
477 os9 F$SrqMem ;Attempt to allocate buffer
478 puls D ;Recover size, clean stack, lose error msg
479 bcs TooBig
480
481 * Found enough memory for pipe buffer.
482 *
483 * Pointer in Reg-U
484 * Size in Reg-D
485 * Previous buffer in Reg-X.
486 * Driver static storage in Reg-Y.
487 *
488 * Initialize the buffer
489
490 pshs U,D ;Save buffer pointer & size
491
492 * Clear pipe buffer header
493
494 ldb #PP.Data ;Size of header
495 ClrBuf clr ,U+
496 decb
497 bne ClrBuf
498
499 puls D,U
500
501 * Initialize path descriptor and other fields of pipe buffer
502 * for new pipe.
503 *
504 * Pointer in Reg-U
505 * Size in Reg-D
506 * Previous buffer in Reg-X.
507 * Driver static storage in Reg-Y.
508 *
509 * IOMan has already prefilled the PD to $00 and
510 * has set PD.CNT for this path to 1.
511
512 pshs Y,X ;Save static storage pointer & prev.buff
513
514 ldy (4+10),S ;Get PD pointer to Reg-Y
515 sty PP.PD,U ;Save pointer to PD in pipe buffer
516
517 leax D,U ;Point to end of pipe.buff + 1
518 stx PD.End,Y
519
520 leax PP.Data,U ;Initial Next in & Next out pointers
521 stx PD.NxtI,Y
522 stx PD.NxtO,Y
523
524 ldx <D.Proc ;Save ID of original creator
525 lda P$ID,X
526 sta PD.Own,Y
527
528 puls Y,X ;Recover static storage pointer and prev.buff
529
530 stx PP.Prev,U ;Save address of previous buffer ($0 if none)
531 bne LinkIn ; (branch if this isn't the 1st pipe)
532
533 * Special -- this is the first pipe.
534 * Set PP.Next to $0000 and store buffer address in device memory.
535 *
536 * Reg-U = pointer to new buffer.
537 * Reg-X = $0000.
538 * Reg-Y = static storage
539
540 ** Zero prefill of PP header covers this
541 ** stx PP.Next,U ;No next buffer
542 ** stx PP.Prev,U ;No previous buffer
543 stu V.List,Y ;Point driver static at this buffer
544 bra IsAsOld
545
546 * There are other named pipes. Link this one in correctly
547 * after the last one checked.
548 *
549 * Reg-U = pointer to new buffer.
550 * Reg-X = Pointer to previous buffer.
551 * Reg-Y = static storage.
552
553 LinkIn ldd PP.Next,X ;Get old's next (could be $0000)
554 stu PP.Next,X ;Set old's next pointing at new
555 std PP.Next,U ;Set new's next where old's was
556 stx PP.Prev,U ;Set new's prev pointing at old
557 pshs X,D
558 ldx 0,S ;Point X at original old's next
559 beq Link9 ; (branch if no next -- $0000 set already)
560 stu PP.Prev,X ;Set prev of old's original next to new
561 Link9 puls D,X
562
563 * Now we look pretty much like a new access to an old pipe.
564 * Fix up pointers to match "old pipe" code
565
566 IsAsOld tfr U,X ;Point Reg-X at pipe buffer
567 tfr Y,U ;Point Reg-U at driver static storage
568 ldy 10,S ;Recover PD pointer
569 stx PD.BUF,Y ;Set up buffer pointer in PD
570 bra OpnXit ; (go to common trailer code)
571
572 * Pipe name found. Set up to access an old pipe.
573 *
574 * Reg-U points to driver static storage.
575 * Reg-X points to matching pipe buffer.
576 *
577 * We need to make this look like a DUP call, so
578 * there's some nasty code here to give back the
579 * PD allocated by IOMan and go get the "original"
580 * PD for this named pipe.
581
582 OldPipe equ *
583
584 *** ***
585 * WARNING -- This code emulates IOMan's I$Close and I$Dup *
586 *** ***
587
588 *
589 * Processing to give back the new path descriptor and use
590 * the original PD that the pipe was opened with.
591 *
592 * Fake close of PD passed by IOMan
593 * Fake dup of named pipe's "master" PD
594 * Fix PD pointer saved on IOMAN's stack
595 *
596 * All of the subroutines preserve all regs, except as noted
597 * This section MUST preserve Reg-X and Reg-U. There must
598 * be exactly 14 bytes on the stack at this point.
599
600 ldy 10,S ;Get IOMAN PD pointer (original Reg-Y)
601
602 * Detach the path.
603
604 pshs U
605 ldu PD.DEV,Y ; Get device pointer
606 os9 I$Detach ; Detach to compensate for IOMAN Attach
607 puls U
608
609 * Decrement use count
610
611 dec PD.CNT,Y ;Decrement use count
612
613 * Give back unwanted PD
614
615 *** This is the way I did it originally
616 pshs X
617 lda PD.PD,Y ;Get system path number
618 ldx <D.PthDBT ;Point at path table index
619 os9 F$Ret64 ; and give back descriptor
620 puls X
621 *** This is the way the OSK named pipe manager does it.
622 *** I had to translate, of course, but the translated
623 *** version doesn't work right.
624 * pshs U,X
625 * lda PD.PD,Y ;Get system path #
626 * ldx <D.PthDBT ;Point at path table index
627 * ldu <D.SysDis ;Point at system SVC dispatch table
628 * jsr [(F$Ret64*2),U] ;Do a RET64
629 * puls X,U
630
631 * Stack clean.
632 * Update IOMAN variables.
633 * Reg-Y = where IOMAN thinks the PD is.
634
635 ifeq (CAUTION-CAREFUL)
636 cmpy (14+IOMAGIC),S ;Make sure the stack looks right (PD matches)
637 beq OKMagic
638
639 * Stack is wrong; declare bad magic!
640
641 comb
642 ldb #E$Bug
643 leas 14,S
644 rts
645 endc
646
647 * Stack is right; go fix PD pointers
648
649 OKMagic ldy PP.PD,X ;Get PD pointer of existing named pipe PD.
650 sty 10,S ;Point PD pointer at existing PD
651 sty (14+IOMAGIC),S ;Save new IOMAN PD pointer in IOMAN stack
652 inc PD.CNT,Y ;Increment use count
653
654 * End of dangerous code
655 * This section MUST have preserved Reg-X and Reg-U
656
657 * Exit code.
658 *
659 * Reg-U points to driver static storage.
660 * Reg-Y points to PD.
661 * Reg-X points to matching pipe buffer.
662 *
663 * Advance caller's path name pointer
664
665 OpnXit equ *
666
667 * Fix use count based on PD.Keep
668
669 lda PD.CNT,Y
670 suba PD.Keep,Y
671 sta PD.CNT,Y ;Get rid of any artificial openings
672 clr PD.Keep,Y
673
674 ifeq (PIPEDIR-YESDIR)
675 * Handle prefill of pipe directory buffer
676
677 lda PD.Mod,Y ;Is this a DIR. open?
678 bita #DIR.
679 beq OpnXt2
680
681 lbsr FilDirP ;Send directory info to pipe
682 endc
683
684 OpnXt2 ldu 12,S ;Point at caller's registers
685 ldd 4,S ;Get revised path name pointer
686 std R$X,U
687
688 leas 14,S ;Clean the stack
689
690 * Successful exit. Reg-X points to pipe buffer.
691
692 clrb
693 rts
694
695 page
696 *
697 * Compare pipe names.
698 *
699 * Can't use F$CmpNam here because the strings
700 * are in system space.
701 *
702 * Path names are pointed to by Reg-X and Reg-Y.
703 * Case is ignored. Returns NE if not equal, else
704 * EQ.
705 *
706
707 Compare pshs Y,X,A ;Reg-A is temp. storage
708
709 * Main comparison loop
710
711 Cmp001 lda ,X+
712 anda #%11011111 ;Cheap and fast TOUPPER
713 sta 0,S
714
715 lda ,Y+
716 anda #%11011111 ;Cheap and fast TOUPPER
717 bmi Cmp.Y ; (exit if we find end of Y-string)
718
719 cmpa 0,S
720 beq Cmp001
721
722 * Names don't match. Return CC=NE
723
724 puls A,X,Y,PC
725
726 * End of "Y" string. "X" character either matches or
727 * it doesn't. Return CC accordingly.
728
729 Cmp.Y cmpa 0,S
730 puls A,X,Y,PC
731
732 *
733 * Convert element count in D to byte count in D.
734 * Return carry set if too big.
735 *
736 * Reg-Y = PD pointer
737 * Reg-D = Element count
738 *
739
740 ECtoBC pshs D
741 lda PD.ESiz,Y ;Get size of each element
742 ldb 0,S ;Get MSB of element count
743 mul
744 pshs D
745 lda PD.ESiz,Y ;Get size of each element
746 ldb (2+1),S ;Get LSB of element count
747 mul
748 adda 1,S ;C-bit set if too big
749 tst ,S++ ;Z-bit clear if too big, C-bit OK
750 leas 2,S
751 bcs EB.err
752 bne EB.err
753
754 * OK exit
755 andcc #$FE
756 rts
757
758 * Error exit
759 EB.err orcc #$01
760 rts
761
762 * Get next character of path name.
763 * Reg-Y set up as if just did a PRSNAM.
764
765 GtNext ldx <D.Proc
766 ldb P$Task,X
767 tfr Y,X
768 os9 F$LDABX
769 rts
770
771 page
772 *
773 * Error hook
774 *
775 MAKDIR equ *
776 CHGDIR equ *
777 UNKNOWN comb
778 ldb #E$UNKSVC
779 rts
780
781 page
782 *
783 * Close a pipe
784 *
785 * If there are any other pipe users, leave the pipe
786 * around. Also, if the pipe is named and contains
787 * any data, leave the pipe around even if there are
788 * no remaining pipe users.
789 *
790 * PD.Keep will be non-zero if the pipe has been kept
791 * open artificially.
792 *
793 * This routine is called each time a path to the pipe
794 * is closed.
795 *
796
797 CLOSE equ *
798
799 * Account for extra use count if pipe artificially kept open.
800 * Then see if this is the last user of the pipe
801
802 lda PD.Keep,Y ;Account for extra pipe images
803 nega
804 clr PD.Keep,Y
805 adda PD.CNT,Y
806 sta PD.CNT,Y ;Set correct PD.CNT value
807 bne READERS ; and branch if any users left
808
809 * No open paths to this pipe.
810 * If it's named and not empty, leave it around anyway.
811
812 tst PD.Name,Y ;Named pipe?
813 beq CLOSE2
814
815 ldd PD.BCnt,Y ;How many elements buffered on named pipe?
816 beq CLOSE2
817
818 * Leave this named pipe around for a while
819
820 inc PD.CNT,Y ;Create an extra image
821 inc PD.Keep,Y ; and remember that we did it
822 bra CLOXIT
823
824 * Delete the pipe.
825 * Y = PD pointer.
826
827 CLOSE2 bsr ZapPipe
828 bra CloXit ;No error
829
830 * Open paths left. What kind?
831
832 READERS cmpa PD.RCT,Y ;Are all open paths readers?
833 bne WRITERS
834
835 * All other open paths are readers.
836 * Send signal to next reader (let him read a bit)
837
838 leax PD.Read,Y
839 bra SENDSIG
840
841 * Not all readers. What kind?
842
843 WRITERS cmpa PD.WCT,Y ;Are all open paths writers?
844 bne CloXit
845
846 * All other open paths are writers.
847 * Send signal to next writer (let him write a bit)
848
849 leax PD.Writ,Y
850
851 * Send signal to next reader or writer
852
853 SENDSIG lda PM.CPR,X ;Process ID to signal
854 beq CLOXIT
855
856 ldb PM.SIG,X ;Signal code to send
857 beq CLOXIT
858
859 * Committed to send signal: clear the flag and send it
860
861 clr PM.SIG,X ;Force no pending signal
862 os9 F$SEND
863
864 * Done with close
865
866 CLOXIT clrb
867 rts
868
869 page
870 *
871 * Delete a named pipe.
872 *
873 * Reg-Y = PD
874 * Reg-U = caller's registers
875 * Reg-X = path name
876 *
877
878 Delete lda #Read.
879 sta PD.MOD,Y ;Need only READ permission
880 pshs U,Y,X,A ;***Match stack set up by IOMAN
881 lbsr Open ;Try to open the pipe
882 puls U,Y,X,A ;***Clean up special stack
883 bcs BadDel
884
885 * Disconnect from pipe, but keep pointer.
886 * Then check to see if we're the only user.
887 *
888 * Note -- The call to OPEN updated PD.CNT
889 * and cleared PD.Keep.
890
891 dec PD.CNT,Y ;Don't count ourselves
892 beq DoDel ;If count is zero, OK to delete
893
894 * Pipe is in use. Return E$FNA
895
896 FNAXIT comb
897 ldb #E$FNA
898
899 * Exit w/ carry set and error code in B
900
901 BadDel rts
902
903 * Perform the delete.
904
905 DoDel bsr ZapPipe
906 clrb
907 rts
908
909 *
910 * Return all memory for the pipe buffer specified
911 * in the path descriptor, and remove it from the linked list.
912 *
913 * Reg-Y = PD pointer
914 * Pipe buffer pointer is at PD.BUF,Y
915 *
916
917 ZapPipe ldu PD.DEV,Y ;Get device table pointer
918 ldu V$Stat,U ;Get static storage pointer
919
920 ldx PD.BUF,Y ;Point to pipe's buffer
921 ldd PP.Next,X ;Save pointer to current and next in list
922 pshs D
923 ldd PP.Prev,X ;Save pointer to previous in list
924 pshs D
925
926 * Reg-D has pointer to previous. If zero, we're zapping head of list.
927 * Z-bit is already set accordingly
928
929 bne OldHead
930
931 * New head of list.
932 * Reg-X still points to buffer to be deleted
933
934 ldd 2,S ;Get pointer to next (may be $0000)
935 std V.List,U ; and set as new head
936 pshs X,D
937 ldx 0,S ;Point Reg-X at next, set CC
938 beq Zap9
939 clr (PP.Prev+0),X ; and set no prev for next
940 clr (PP.Prev+1),X
941 Zap9 puls D,X ;Point back at pipe to delete
942 bra ZapIt
943
944 * No new head of list. Just delete from linked list.
945 * We know there is a previous buffer.
946 *
947 * Reg-X points to buffer to be deleted.
948 * Reg-D points to previous buffer.
949
950 OldHead ldu PP.Next,X ;Get U pointing at our next (may be $0000)
951 exg D,X ;Point X at our prev, D at us
952 stu PP.Next,X ;Save new next for out prev
953 beq Zap8
954 stx PP.Prev,U ;Point our next's prev at our original prev
955 Zap8 exg D,X
956
957 * All cleaned up. Give back the buffer
958 * Reg-X points to buffer, Reg-Y points to PD.
959
960 ZapIt ldd PD.End,Y
961 pshs X
962 subd 0,S ;Get total bytes to Reg-D
963 puls U ;Point at buffer, clean stack
964 os9 F$SRtMem
965
966 * Exit with whatever error F$SRtMem produces
967
968 leas 4,S ;Clean stack
969 rts
970
971 page
972 *
973 * Dummy hook
974 *
975 SEEK equ *
976 Dummy clrb
977 rts
978
979 page
980 *
981 * GETSTT processing
982 *
983 * Supports the following codes:
984 *
985 * SS.Opt Option section
986 * SS.Ready # bytes in queue
987 * SS.Siz Size of queue
988 * SS.EOF Queue empty
989 * SS.FD Bogus file descriptor (WIZBANG==MSGS)
990 * SS.ScSiz Screen Size
991 *
992 * SS.Opt handled in IOMAN, etc.
993 * SS.Ready code by Kent Meyers, modified by Chris Burke
994 * SS.Siz, SS.EOF, SS.FD, SS.ScSiz by Chris Burke
995 *
996
997 GETSTT lda R$B,U Get User B Register ++
998 cmpa #SS.READY Test for Ready Call ++
999 bne NotSSRDY
1000
1001 * Process SS.Rdy -- return # elements in queue
1002 * If more than 255, return 255.
1003
1004 G.Rdy ldb #255
1005 tst (PD.BCnt+0),Y
1006 bne G.Rdy0 ;Accomodate large queues (256 or more bytes)
1007 ldb (PD.BCnt+1),X ;Get element count LSB
1008
1009 * Reg-B has LSB of element count, CC set based on value
1010
1011 beq RDNRDY ;Not Ready if no characters
1012
1013 G.Rdy0 stb R$B,U ;Return count in B
1014
1015 SST.OK equ *
1016 SST.Ign equ *
1017
1018 G.OK clrb No Error ++
1019 tfr CC,A
1020 sta R$CC,U
1021 rts Return ++
1022
1023 * No characters for SS.Ready
1024
1025 RDNRDY tst PD.Wrtn,Y Anybody writing to pipe?
1026 bne NOTEOF (not OK if so)
1027
1028 * No writer
1029
1030 ldb PD.CNT,Y Exactly one path open to pipe?
1031 decb
1032 bne NOTEOF (OK if no, e.g. nobody or > 1)
1033
1034 * Internal error
1035
1036 IntErr comb
1037 ldb #255
1038 rts
1039
1040 NOTEOF comb Set Error Flag ++
1041 ldb #E$NOTRDY Get Error Code ++
1042 rts Return ++
1043
1044 * Not SS.Ready. Check for SS.Siz
1045
1046 NotSSRdy cmpa #SS.Size Test for Size call
1047 bne NotSSSiz
1048
1049 * Process SS.Siz -- return size of queue in ELEMENTS.
1050
1051 G.Siz ldd PD.QSiz,Y ;Get max. # of queue elements
1052 std R$U,U
1053 clr (R$X+0),U Set 16 MSB's to $0000
1054 clr (R$X+1),U
1055 GOK001 bra G.OK
1056
1057 * Not SS.Siz. Check for SS.EOF
1058
1059 NotSSSiz cmpa #SS.EOF
1060 bne NotSSEOF
1061
1062 * Process SS.EOF
1063 * Handle like SS.Rdy, but preserve Reg-B
1064
1065 G.EOF bsr G.Siz
1066 ldb #0 ;NOT clrb -- preserve carry
1067 stb R$B,U
1068 bcc G.OK ;No error if ready
1069
1070 ldb #E$EOF ;Carry is already set
1071 rts
1072
1073 * Not SS.EOF. Check for SS.FD
1074
1075 ifeq (PIPEDIR-YESDIR)
1076 NotSSEOF cmpa #SS.FD
1077 bne NotSSFD
1078
1079 * Process SS.FD
1080
1081 lbsr DoSSFD
1082 bra G.OK ;Successful always
1083 else
1084 NotSSEOF equ *
1085 endc
1086
1087 * Not SS.FD. Check for SS.ScSiz
1088
1089 NotSSFD cmpa #SS.ScSiz ;Force UNKNOWN here
1090 lbeq UnKnown
1091
1092 NotSCSZ equ *
1093
1094 NotSSAT equ *
1095
1096 * Process unknown GETSTT
1097
1098 * lbra UNKNOWN
1099 bra G.OK
1100 * bra NotEOF
1101
1102 page
1103 *
1104 * SETSTT processing
1105 *
1106 * Supports the following codes:
1107 *
1108 * SS.Opt Option section
1109 * SS.Siz No effect unless size=0; then clears pipe buffer
1110 * SS.FD No effect
1111 * SS.SSig Set signal on data available
1112 * SS.Relea Release signal
1113 *
1114 * SS.Opt handled in IOMAN, etc.
1115 * SS.Siz, SS.SSig, SS.Relea by Chris Burke, modified
1116 * from OSK.
1117 *
1118
1119 SetStt lda R$B,U Get User B Register ++
1120 cmpa #SS.Opt
1121 beq SST.Ign ; (ignore)
1122 cmpa #SS.FD
1123 beq SST.Ign
1124
1125 * Check for SS.SIZ
1126
1127 cmpa #SS.Size
1128 bne NoS.Siz
1129
1130 ldd R$U,U ;Get caller's size
1131 bne SST.Ign
1132
1133 * Clear the pipe
1134
1135 ldx PD.Buf,Y
1136 leau PP.Data,X
1137 stu PD.NxtI,Y
1138 stu PD.NxtO,Y
1139 clr (PD.BCnt+0),Y
1140 clr (PD.BCnt+1),Y
1141 clr PD.RFlg,Y
1142 clr PD.Wrtn,Y
1143
1144 QST.OK bra SST.OK
1145
1146 * Check for SS.SSig
1147
1148 NoS.Siz cmpa #SS.SSig
1149 bne NoS.Sig
1150
1151 leax PD.Read,Y ;Point at read packet
1152 tst PM.Cpr,X ;Error if already somebody waiting
1153 bne NOTEOF
1154
1155 * Set signal trap
1156
1157 lda PD.CPR,Y ;Set process ID
1158 sta PM.CPR,X
1159 lda (R$X+1),U ;Get signal code
1160 sta PM.Sig,X
1161 tst PD.BCnt,Y ;Immediate signal if
1162 lbne SendSig
1163
1164 bra QST.OK
1165
1166 * Check for release of signal
1167
1168 NoS.Sig cmpa #SS.Relea
1169 bne NoS.Rel
1170
1171 leax PD.Read,Y ;Point at read packet
1172 lda PM.CPR,X
1173 cmpa PD.CPR,Y ;Our process set it?
1174 bne QST.OK
1175
1176 * Release signal trap
1177
1178 clrb
1179 lbra Switch
1180
1181 * Not SS.Relea. Check for SS.Attr
1182
1183 NoS.Rel cmpa #SS.Attr
1184 bne NoS.Atr
1185
1186 * Change attributes if allowed
1187
1188 ldx <D.Proc
1189 lda P$ID,X ;Are we superuser?
1190 beq SAT.OK
1191 tst PD.Own,Y ;Is creator still attached?
1192 bne SAT.XX
1193
1194 sta PD.Own,Y ;Inherit pipe if owner abandoned it
1195
1196 SAT.XX cmpa PD.Own,Y
1197 lbne FNAXit ;If can't match PID, E$FNA error
1198
1199 * Change attributes.
1200 * Reg-U points at caller's registers
1201
1202 SAT.OK lda R$A,U
1203 ora #(READ.+WRITE.) ;We insist . . .
1204 sta PD.MOD,Y
1205 bra QST.OK
1206
1207 * Unknown SETSTT
1208
1209 NoS.Atr lbra Unknown
1210
1211 page
1212 *
1213 * Read CR-terminated line or element count from
1214 * pipe with no editing. Note that this call is
1215 * not well defined for element sizes other than
1216 * 1 byte.
1217 *
1218
1219 READLN ldb PD.ESiz,Y
1220 decb
1221 bne RddEOF ;EOF error if more than 1 byte per element
1222
1223 ldb #CR
1224 stb PD.REOR,Y
1225 bra READ001
1226
1227 *
1228 * Read element count from pipe with no editing.
1229 *
1230 * Note that if there are fewer elements in the pipe
1231 * than the user wants to read, and there are no writers
1232 * for the pipe, we return all elements followed by E$EOF.
1233 *
1234
1235 READ clr PD.REOR,Y
1236
1237 * Generic read. PD.REOR = terminator if non-null
1238
1239 READ001 leax PD.Read,Y ;Get PID of reader (us)
1240 lbsr GETFREE
1241 bcs RddRTS
1242
1243 ldd R$Y,U ;Desired element count
1244 beq RddXit
1245
1246 * Set up for outer loop -- push zero element count
1247 * and space for buffer pointers on stack.
1248
1249 clra
1250 clrb
1251 pshs D ;Initial count of elements read
1252 leas -4,S
1253 ldx R$X,U ;Initial buffer start address
1254 bra RddNext
1255
1256 * Enter here to block on read. If there are no writers,
1257 * return E$EOF.
1258
1259 CantRdd pshs X ;Save buffer pointer
1260
1261 leax PD.Read,Y
1262 lbsr SigSlp
1263 lbcs RddDone
1264
1265 * Inner loop to read bytes.
1266 * Here for initial attempt to read,
1267 * or to retry after blocking
1268
1269 READOK ldx <D.PROC ;Point to our task descriptor
1270 ldb P$TASK,X ++LII
1271 puls X ++LII Recover current buffer pointer
1272
1273 * Inner read loop. Read one element.
1274 * Note that we could use F$Move for elements larger
1275 * than 1 byte, because queue size is always an even
1276 * multiple of element size.
1277
1278 RddMore lbsr DOREAD ;Get byte to A, or CS
1279 bcs CantRdd
1280
1281 os9 F$STABX ;Put byte in caller's buffer
1282 leax 1,X
1283 tst PD.REOR,Y ;Is there an EOR character?
1284 beq NotRdLn
1285
1286 cmpa PD.REOR,Y ;Did we match it?
1287 beq RddEOL
1288
1289 NotRdLn cmpx 0,S ;Compare current addr. to end addr
1290 blo RddMore ; and loop until done
1291
1292 * Done with element. Check for next.
1293
1294 pshs X ;Save buffer pointer
1295
1296 bsr CntDn ;Update queue count, etc
1297 cmpd R$Y,U ;Got all elements?
1298 bhs RddTail
1299
1300 * Outer loop -- read one element at a time.
1301 *
1302 * X = next data pointer
1303 * Y = PD pointer
1304
1305 RddNext stx 0,S ;Set new start address
1306 ldb PD.ESiz,Y ;Size of one element
1307 clra
1308 addd 0,S ;Compute end address of current element bfr
1309 std 2,S
1310 bra READOK ;Go to element reading loop
1311
1312 * Read an EOL. Advance element count
1313
1314 RddEOL pshs X ;Save buffer pointer
1315 bsr CntDn
1316
1317 * Read everything, or aborting
1318
1319 RddDone ldd 4,S ;Get element count
1320
1321 * Tail end of read
1322
1323 RddTail std R$Y,U
1324 leas 6,S ;Clean stack
1325 bne RddSome ;Success if read more than 0 elements
1326
1327 * EOF error if no bytes read
1328
1329 RddEOF comb
1330 ldb #E$EOF
1331 bra RddXit
1332
1333 * Successful exit
1334
1335 RddSome clrb
1336
1337 RddXit leax PD.Read,Y
1338 lbra SWITCH
1339
1340 * Decrement queued count, inc read count
1341
1342 CntDn ldd #-1
1343 bra CUpDn
1344
1345 * Increment queued count, inc written count
1346
1347 CntUp ldd #1
1348
1349 CUpDn addd PD.BCnt,Y ;Modify count of elements queued
1350 std PD.BCnt,Y
1351
1352 * Bump I/O count
1353
1354 IOCnt ldd (2+4),S ;Bump count of elements read/written
1355 addd #1
1356 std (2+4),S
1357 RDDRTS rts
1358
1359 page
1360 *
1361 * Write CR-terminated line or element count to
1362 * pipe with no editing
1363 *
1364
1365 WRITELN ldb PD.ESiz,Y
1366 decb
1367 bne RddEOF ;EOF error if more than 1 byte per element
1368
1369 ldb #CR
1370 stb PD.WEOR,Y
1371 bra Wrt001
1372
1373 *
1374 * Write byte count to pipe with no editing.
1375 *
1376
1377 WRITE clr PD.WEOR,Y
1378
1379 * Generic entry point
1380
1381 Wrt001 leax PD.Writ,Y
1382 lbsr GETFREE ;Check I/O queue
1383 bcs WrtXit
1384
1385 ldd R$Y,U ;Element count
1386 beq WrtXit
1387
1388 * Set up for outer loop -- push zero element count
1389 * and space for buffer pointers on stack.
1390
1391 clra
1392 clrb
1393 pshs D ;Initial count of elements read
1394 leas -4,S
1395 ldx R$X,U ;Initial buffer start address
1396 bra WrtNext
1397
1398 * Enter here to block on write
1399
1400 CantWrt pshs X
1401
1402 leax PD.Writ,Y
1403 lbsr SigSlp
1404 bcs WrtErr
1405
1406 * Begin (or resume) write
1407
1408 WRITOK ldx <D.PROC ++LII
1409 ldb P$TASK,X ;Get our DAT image #
1410 puls X ++LII
1411
1412 * Main write loop
1413
1414 WrtMore os9 F$LDABX ;Get a byte from caller's buffer
1415 lbsr DOWRITE
1416 bcs CantWrt
1417
1418 leax 1,X
1419 tst PD.WEOR,Y ;EOL character defined?
1420 beq NotWrLn
1421
1422 cmpa PD.WEOR,Y
1423 beq WrtEOL
1424
1425 * See if at end of buffer
1426
1427 NotWrLn cmpx 0,S
1428 blo WrtMore
1429
1430 * Done with element. Check for next.
1431
1432 pshs X ;Save buffer pointer
1433
1434 bsr CntUp
1435 cmpd R$Y,U ;Put all elements?
1436 bhs WrtTail
1437
1438 * Outer loop -- write one element at a time.
1439
1440 WrtNext stx 0,S ;Set new start address
1441 ldb PD.ESiz,Y ;Size of one element
1442 clra
1443 addd 0,S ;Compute end address of current element bfr
1444 std 2,S
1445 bra WRITOK ;Go to element reading loop
1446
1447 * Wrote an EOL. Advance element count
1448
1449 WrtEOL pshs X ;Save buffer pointer
1450 bsr CntUp
1451
1452 * Wrote everything, or aborting
1453
1454 WrtDone ldd 4,S ;Get element count
1455
1456 * Tail end of write
1457
1458 WrtTail std R$Y,U
1459 leas 6,S ;Clean stack
1460
1461 * Successful exit
1462
1463 WrtSome clrb
1464
1465 WrtXit leax PD.Writ,Y
1466 bra SWITCH
1467
1468 * Error exit
1469
1470 WrtErr pshs B
1471 ldd (4+1),S
1472 std R$Y,U
1473 puls B
1474
1475 leas 6,S
1476 bra WrtXit
1477
1478 page
1479 *
1480 * I/O queue manipulation routines
1481 *
1482
1483 GETFREE lda PM.CPR,X ;Is any process using this resource?
1484 beq SETPMCPR ; (branch if not)
1485
1486 cmpa PD.CPR,Y ;Does caller control this resource?
1487 beq OURDEVIC ; (branch if so)
1488
1489 inc PM.CNT,X ;Bump # of active r/w images
1490 ldb PM.CNT,X
1491 cmpb PD.CNT,Y ;See if equal to # of open images
1492 bne SETQUEUE ; (if not, run everybody else to free it)
1493
1494 lbsr SENDSIG ;Yes -- wake up next process
1495
1496 * Process number in Reg-A
1497 * Put the process into the I/O queue and
1498 * sleep until a signal wakes us up
1499
1500 SETQUEUE os9 F$IOQU
1501 dec PM.CNT,X ;Caller is asleep, so 1 less active
1502 pshs X
1503 ldx <D.PROC
1504 ldb P$SIGNAL,X ;Get caller's signal
1505 puls X
1506 beq GETFREE ;Loop until there's a signal
1507
1508 coma ;Error if caller is waiting
1509 rts
1510
1511 * Nobody using the resource. Grab it.
1512
1513 SETPMCPR ldb PD.CPR,Y
1514 stb PM.CPR,X ;Make caller "owner"
1515
1516 * Exit -- caller owns the pipe
1517
1518 OURDEVIC clrb
1519 rts
1520
1521 *
1522 * Set a wakeup signal for the calling process
1523 *
1524
1525 SigSlp ldb PM.CNT,X ;Active image count
1526 incb
1527 cmpb PD.CNT,Y ;Everybody active?
1528 bne SgSlp01 ; (if not, try sending signals)
1529
1530 * Nobody on the other end to signal.
1531 * Error if anonymous, else hang out a bit.
1532
1533 tst PD.Name,Y ;If anonymous pipe & nobody left, error
1534 beq WRITEROR
1535
1536 * Named pipe and nobody to signal. Not an error if data in pipe.
1537
1538 tst PD.BCnt,Y ;Number of items in pipe
1539 beq WRITEROR
1540
1541 * Send signal to other end of pipe (may not be one, though)
1542
1543 SgSlp01 stb PM.CNT,X
1544 ldb #S$WAKE
1545 stb PM.SIG,X ;Force caller's signal to "wakeup"
1546 clr PD.CPR,Y
1547 pshs X
1548 tfr X,D ;Switch from reader to writer or vis-a-vis
1549 eorb #4
1550 tfr D,X
1551 lbsr SENDSIG ;Send signal to opposite end of pipe
1552 ldx #0
1553 os9 F$SLEEP ;Caller sleeps until signaled
1554 ldx <D.PROC
1555 ldb P$SIGNAL,X
1556 puls X
1557 dec PM.CNT,X ;Caller is asleep, so 1 less active
1558 tstb
1559 bne GOTSIGNL ;Error if opposite end set no signal
1560
1561 clrb
1562 rts
1563
1564 * WRITE ERROR hook
1565
1566 WRITEROR ldb #E$WRITE
1567
1568 * Generic error hook
1569
1570 GOTSIGNL coma
1571 rts
1572
1573 *
1574 * Release this end of the pipe, and
1575 * send a signal to the other end.
1576 *
1577 * Enter pointing to variables for
1578 * this end; exit pointing to variables
1579 * for opposite end.
1580 *
1581
1582 SWITCH pshs CC,B,U
1583 clr PM.CPR,X ;No process controlling current end
1584 tfr X,D
1585 eorb #4 ;Switch to other end (MAGIC)
1586 tfr D,X
1587 lbsr SENDSIG ;Awaken other end
1588 puls CC,B,U,PC
1589
1590 *
1591 * Write one byte to queue described in path
1592 * descriptor. Return CS if queue full.
1593 * Doesn't update count of ELEMENTS queued.
1594 *
1595
1596 DOWRITE pshs B,X
1597 ldx PD.NxtI,Y
1598 ldb PD.RFlg,Y
1599 beq SETREADY ;(say data available)
1600
1601 cmpx PD.NxtO,Y
1602 bne STORDATA ;(branch if queue not full)
1603
1604 * Error -- queue is full
1605
1606 comb
1607 puls B,X,PC
1608
1609 * Mark data available in queue
1610
1611 SETREADY ldb #1
1612 stb PD.RFlg,Y
1613
1614 * Put data in Reg-A into queue, and advance
1615 * pointer to next in w/ wrap
1616
1617 STORDATA sta ,X+
1618 cmpx PD.End,Y
1619 blo WTNOWRAP
1620
1621 ldx PD.BUF,Y
1622 leax PP.Data,X
1623
1624 WTNOWRAP stx PD.NxtI,Y
1625
1626 * Don't step Character Input Counter.
1627
1628 clr PD.Wrtn,Y
1629 puls B,X,PC
1630
1631 *
1632 * Read one byte from queue described in path
1633 * descriptor. Return CS if none available.
1634 * Doesn't update count of ELEMENTS queued.
1635 *
1636
1637 DOREAD lda PD.RFlg,Y ;Any data?
1638 bne DATAREDY
1639
1640 * No data -- return CS
1641
1642 comb
1643 rts
1644
1645 * Get data from queue
1646
1647 DATAREDY pshs X
1648 ldx PD.NxtO,Y ;Get next out pointer
1649 lda ,X+
1650 cmpx PD.End,Y
1651 blo RDNOWRAP
1652
1653 ldx PD.BUF,Y
1654 leax PP.Data,X
1655
1656 * Save updated next out pointer
1657
1658 RDNOWRAP stx PD.NxtO,Y
1659 cmpx PD.NxtI,Y
1660 bne NOTEMPTY
1661
1662 clr PD.RFlg,Y ;Mark queue empty
1663
1664 * Don't decrement Character Input Counter.
1665
1666 NOTEMPTY equ *
1667
1668 * Exit with character in Reg-A
1669
1670 andcc #NCARRY ;Clear carry
1671 puls X,PC
1672
1673 page
1674 *
1675 * Utility placed here to not make assembly listing obsolete.
1676 *
1677
1678 MovSet os9 F$Move ;Do inter-process block move
1679
1680 * Force set MSB at end of name
1681
1682 tfr Y,D ;Byte count to D
1683 decb
1684 lda B,U ;Get last byte of name
1685 ora #%10000000
1686 sta B,U
1687
1688 rts
1689
1690 ifeq (PIPEDIR-YESDIR)
1691
1692 *
1693 * Find out how many pipes there are for the
1694 * current device, and set up device descriptor
1695 * so that pipe buffer will hold 32 bytes of
1696 * data for each.
1697 *
1698 * Reg-Y = PD pointer
1699 *
1700 * Exit with size set up in PD.
1701 * CC=EQ if no pipes.
1702 *
1703
1704 SizDirP pshs X,D
1705
1706 clrb ;Clear count of pipes
1707 ldx PD.Dev,Y
1708 ldx V$Stat,X ;Point at static storage
1709 ldx V.List,X ;Get head of linked list
1710 beq GotCnt
1711
1712 * There are some pipes. Count them.
1713
1714 PCount incb
1715 ldx PP.Next,X ;Track down linked list
1716 bne PCount
1717
1718 * Now Reg-B = pipe count. Need 32 bytes per pipe.
1719
1720 GotCnt incb ;Add one for us!
1721 lda #32
1722 mul
1723 std PD.QSiz,Y ;Set element count for this pipe
1724 lda #1
1725 sta PD.ESiz,Y ;Set element size to 1 byte
1726
1727 puls D,X,PC
1728
1729 *
1730 * Fill pipe buffer with directory data.
1731 *
1732 * The data is organized like an RBF directory:
1733 *
1734 * Offset Data
1735 * -------- --------------------------------
1736 * $00-$1C Pipe name
1737 * $1D DAT task number of pipe buffer
1738 * $1E-$1F Address of pipe buffer in task
1739 *
1740 *
1741 FilDirP pshs U,X,D
1742
1743 ldx PD.Dev,Y
1744 ldx V$Stat,X ;Point at static storage
1745 ldx V.List,X ;Get head of linked list
1746 beq GotFil
1747
1748 * Write data for pipe buffer @X to pipe with PD @Y
1749
1750 FD000 ldu PP.PD,X ;Point at PD for pipe to be dumped
1751 leau PD.Name,u
1752 ldb #NameMax
1753
1754 FD001 lda ,u+ ;Write pipe name
1755 bsr QWrite
1756 decb
1757 bne FD001
1758
1759 ldu <D.SysPrc ;Get system DAT image number
1760 lda P$Task,u
1761 bsr QWrite
1762
1763 pshs X ;Get pipe buffer pointer
1764 lda ,S+
1765 bsr QWrite
1766 lda ,S+
1767 bsr QWrite
1768
1769 * Advance to next pipe buffer
1770
1771 ldx PP.Next,X
1772 bne FD000
1773
1774 * All done. Restore regs & exit
1775
1776 GotFil puls D,X,U,PC
1777
1778 * Byte saver
1779
1780 QWrite lbra DoWrite
1781
1782 *
1783 * Immortal entry point
1784 *
1785 Immort coma
1786 sbcb #38
1787 lsrb
1788 fcb $42 ;SBCB op-code
1789
1790 * Fall through to SS.FD processing
1791
1792 *
1793 * Routine to process SS.FD call on an open pipe.
1794 * Creates a pseudo-FD in the user's buffer (@R$X).
1795 * Desired byte count in R$Y.
1796 *
1797 * The pseudo-file descriptor sector includes the following:
1798 *
1799 * Offset Description
1800 * -------- --------------------------------------
1801 * $00 Attributes
1802 * $01-$02 Owner's *PROCESS* ID
1803 * $03-$07 Zeros (date of last access)
1804 * $08 Use count
1805 * $09-$0C Number of items queued
1806 * $0D-$0F Zeros (creation date)
1807 * $10-$FF Zeros (segment list -- at least 5 zeros needed)
1808 *
1809
1810 DoSSFD pshs D,X,Y,U
1811
1812 ldb #(16+5) ;Clear data on stack
1813 SSFD01 clr ,-S
1814 decb
1815 bne SSFD01
1816
1817 * Set attributes
1818 lda PD.Mod,Y
1819 sta FD.ATT,S
1820
1821 * Set owner's process ID
1822 lda PD.Own,Y
1823 sta (FD.OWN+1),S
1824
1825 * Set use count
1826 lda PD.CNT,Y
1827 sta FD.LNK,S
1828
1829 * Set queue count
1830
1831 ldd PD.BCNT,Y
1832 std (FD.SIZ+2),S
1833
1834 * Now copy the data into the caller's buffer
1835
1836 ldx <D.SysPrc ;Pointer to our PD
1837 lda P$Task,X ; get system's DAT image # (source)
1838 ldx <D.Proc ;Pointer to caller's PD
1839 ldb P$Task,X ; get caller's DAT image # (dest)
1840 ldy R$Y,U ;Byte count
1841 leax 0,S ;Source address
1842 ldu R$X,U ;Destination address
1843 os9 F$Move ;Do the move
1844
1845 * All done.
1846
1847 leas (16+5),S
1848 puls U,X,Y,D,PC
1849
1850 endc
1851
1852 emod
1853
1854 MODSIZE equ *
1855
1856 end
1857