10 REM > USBPRN/src
   20 REM USB user printer driver
   30 :
   40 DIM mcode% &200
   50 load%=&FFFF0A29
   60 :
   70 PRCHAR=&FFBC
   80 OSWRCH=&FFEE:OSBYTE=&FFF4
   90 uptv=&0222:cnpv=&22E:remv=&22C
  100 usb_D=&FCF8:usb_S=&FCF9
  110 USBPRN=13:REM 13=USB printer driver number
  120 :
  130 FOR P=0 TO 1
  140   P%=load%:O%=mcode%
  150   [OPT P*3+4
  160   .go%
  170   PHP:SEI                          :\ Vectors changing
  180   LDA uptv+0:STA oldUPTV+0         :\ Claim UPTV
  190   LDA uptv+1:STA oldUPTV+1
  200   LDA newUPTV+0:STA uptv+0
  210   LDA newUPTV+1:STA uptv+1
  220   PLP
  230   LDA #5:LDX #13:JMP OSBYTE        :\ Select printer
  240   :
  250   :
  260   \ Low-level USB I/O
  270   \ -----------------
  280   .usb_Wr:BIT &FF:BMI usb_Wr2:BIT usb_S:BVS usb_Wr
  290   .usb_Wr2:STA usb_D:RTS
  300   .usb_Rd:BIT &FF:BMI usb_Rd2:BIT usb_S:BMI usb_Rd
  310   .usb_Rd2:LDA usb_D:RTS
  320   :
  330   .usb_Sync
  340   BIT usb_S:BMI usb_Sync1:BIT usb_D
  350   BIT &FF:BPL usb_Sync:RTS :\ Loop until no byte pending
  360   .usb_Sync1
  370   BIT usb_S:BVS usb_Sync   :\ Loop back if can't write
  380   PHA
  390   LDA #ASC"E":STA usb_D
  400   LDA #13:STA usb_D        :\ Send ECHO command
  410   .usb_Sync2:JSR usb_Rd:EOR #ASC"E":BNE usb_Sync2
  420   .usb_Sync3:JSR usb_Rd:EOR #13:BNE usb_Sync3
  430   PLA:BIT &FF:RTS          :\ Return MI if Escape
  440   :
  450   .usb_SCS:EQUB &10:EQUB 13
  460   .usb_IPH:EQUB &91:EQUB 13
  470   .usb_DSD:EQUB &83:EQUB &20
  480   :
  490   :
  500   \ USER PRINTER DRIVER
  510   \ ===================
  520   \ Print to user printer
  530   \ A=action, X=buffer, Y=printer
  540   \  0 = 100Hz poll
  550   \  1 = character entered buffer
  560   \  2 = VDU 2 - start print job
  570   \  3 = VDU 3 - end print job
  580   \  4 = NETV OSWRCH call
  590   \  5 = *FX5,n - select printer
  600   \  6 = NETV OSRDCH call
  610   \  7 = NETV OSBYTE call
  620   \  8 = NETV OSWORD call
  630   \ 13 = NETV RDLINE completed
  640   \
  650   .MyPrinter
  660   CPY #USBPRN:BNE NotMyPrinter     :\ Respond to printer 13
  670   CMP #3:CLC:BEQ PrintFlush        :\ VDU 3, CC=flush output
  680   CMP #1:BNE NotMyAction           :\ Not character written
  690   :                                :\ CS=don't flush
  700   .PrintFlush
  710   PHP                              :\ Save CC=print all
  720   LDX #3:CLV:CLC:JSR CallCNPV      :\ Count number in buffer 3
  730   TYA:BNE PrintSome                :\ >255 bytes, print some
  740   CPX #48:BCS PrintSome            :\ >47 bytes, print some
  750   PLP:BCC PrintBuff                :\ End of job, print all so far
  760   RTS                              :\ <48 bytes, return with CS
  770   .PrintSome
  780   LDX #48:PLP                      :\ Print 48 characters
  790   :
  800   .PrintBuff
  810   \ Print buffered characters
  820   \ X=number of bytes in buffer
  830   :
  840   TXA:BEQ PrintDone                :\ Nothing to print
  850   PHA:LDX #0
  860   .PrintUSBlp1
  870   JSR usb_Sync
  880   .PrintUSBlp2
  890   LDA usb_SCS,X:JSR usb_Wr
  900   INX:CMP #13:BEQ PrintUSBlp1
  910   CPX #6:BCC PrintUSBlp2
  920   PLA:PHA:JSR usb_Wr
  930   LDA #&0D:JSR usb_Wr
  940   :
  950   PLA:TAX
  960   .PrintLp
  970   TXA:PHA
  980   LDX #3:CLV:JSR CallREMV          :\ A=Y=byte
  990   JSR usb_Wr
 1000   PLA:TAX:DEX:BNE PrintLp          :\ Loop for all characters
 1010   .PrintDone
 1020   SEC                              :\ Printer dormant
 1030   .NotMyAction
 1040   RTS
 1050   .NotMyPrinter
 1060   JMP (oldUPTV)
 1070   .CallCNPV
 1080   JMP (cnpv)
 1090   .CallREMV
 1100   JMP (remv)
 1110   :
 1120   .newUPTV:EQUW MyPrinter
 1130   .oldUPTV:EQUW 0
 1140   :
 1150 ]:NEXT
 1160 IF (P%AND&FFFF)>&B00:PRINT"Code overrun":END
 1170 PRINT "*SAVE USBPRN ";~mcode%;" ";~O%;" ";~go%OR&FFFF0000;" ";~load%