;USB activity hook include "settings.inc" include "ti83plus.inc" include "equates.inc" SEGMENT Main GLOBALS ON EXTERN DispHexA,DispHexHL,GetControlPacket,WaitPort82,SetupOutPipe,SetupInPipe,SendInterruptData EXTERN debugStep,col1,col2,SmallWaitTimer,WaitTimerBms,SendBulkData,handleCalcData,RecycleUSB EXTERN DoDebug,ReceiveData,InitializePeriphUSB,receiveAndWriteUSBData,DoMassStorageHandle ;USB Activity Hook ;-------------------------------------------------------------------------------------------------- USBactivityHook: add a,e ; res debugOn,(iy+periph8xFlags) ;***TESTING ; ld a,(debugStep) ;***TESTING ; inc a ; ; ld (debugStep),a ; ; ld hl,(curRow) ; ; push hl ; ; ld hl,0707h ; ; ld (curRow),hl ; ; call DispHexA ; ; pop hl ; ; ld (curRow),hl ; in a,(55h) ; bit debugOn,(iy+periph8xFlags) ;*** TESTING ; call nz,DispHexA ; ld b,a in a,(56h) ; bit debugOn,(iy+periph8xFlags) ;*** TESTING ; call nz,DispHexA ; LOG Interrupt,b LOG Interrupt,a or a jr z,skipPort56h ;Port 56h has the event bit 6,a jr nz,BcablePluggedIn bit 4,a jr nz,cancelUSBHook ;exitUSBHook ;A cable plugged in bit 5,a jr nz,cancelUSBHook ;exitUSBHook ;A cable unplugged bit 7,a jr z,notBcableUnplugged ;cancelUSBHook ;exitUSBHook ;B cable unplugged ;kill USB device as peripheral call RecycleUSB jr cancelUSBHook xor a out (5Bh),a in a,(4Dh) bit 5,a jr nz,$F xor a out (4Ch),a res 6,(iy+41h) jr continueKill $$: ld b,8 in a,(4Dh) bit 6,a jr nz,$F ld b,0 $$: ld a,b out (4Ch),a continueKill: ld a,2 out (54h),a ld a,(39h) and 0F8h out (39h),a res 0,(iy+41h) in a,(4Dh) bit 5,a jr nz,continueKill2 ld de,0FFFFh $$: dec de ld a,d or e scf jr z,cancelUSBHook in a,(4Dh) bit 7,a jr z,$B in a,(4Dh) bit 0,a jr z,$B ld a,22h out (57h),a jr cancelUSBHook continueKill2: in a,(4Dh) bit 6,a jr nz,$F xor a out (4Ch),a ld a,50h jr finalKill $$: ld a,93h finalKill: out (57h),a jr cancelUSBHook notBcableUnplugged: bit 1,a jr z,skipPort56h ;1,(56h) was set call InitializePeriphUSB jr nc,cancelUSBHook LOG Custom,04h jr cancelUSBHook bit0Port56hSet: ;I have absolutely no idea what 0,(56h) being set means, and we will never know. ;I go ahead and re-initialize just because, though. Who knows, it might actually do the right thing. LOG Bit0Port56,a call InitializePeriphUSB jr cancelUSBHook skipPort56h: in a,(56h) bit 0,a jr nz,bit0Port56hSet in a,(55h) ld b,a and 11h xor 11h jr z,cancelUSBHook bit 4,b jr z,readData di bit 3,(iy+41h) jr nz,cancelUSBHook in a,(8Fh) bit 7,a jr nz,killUSBInterruptDisableError $$: xor a out (5Bh),a ld a,20h out (57h),a jr killUSBError bit0Port86hSet: in a,(8Fh) bit 7,a jr z,$B killUSBInterruptDisableError: xor a out (5Bh),a killUSBError: call unknownOutputs in a,(4Dh) bit 5,a jr nz,$F ld de,0FFFFh smallLoop: dec de ld a,d or e jr z,scfeiUSBError in a,(4Dh) bit 7,a jr z,smallLoop in a,(4Dh) bit 0,a jr z,smallLoop ld a,22h out (57h),a jr cancelUSBHook $$: in a,(4Dh) bit 6,a jr nz,$F xor a out (4Ch),a ld a,50h jr outPort57h $$: ld a,93h outPort57h: out (57h),a jr cancelUSBHook unknownOutputs: in a,(4Dh) bit 5,a jr nz,$F xor a res 6,(iy+41h) jr port54h39hOutput $$: ld b,8 in a,(4Dh) bit 6,a jr nz,$F ld b,0 $$: ld a,b out (4Ch),a port54h39hOutput: ld a,2 out (54h),a in a,(39h) and 0F8h out (39h),a ret scfeiUSBError: scf ei ld a,1 out (5Bh),a res 0,(iy+41h) jr cancelUSBHook ;Not sure whether this should run or not ld b,50 call WaitTimerBms LOG Custom,3 ;*** TESTING ei ld a,1 out (5Bh),a res 0,(iy+41h) jr cancelUSBHook BcablePluggedIn: LOG PeriphInit,0 call InitializePeriphUSB jr cancelUSBHook readData: di bit 0,(iy+41h) jr nz,cancelUSBHook in a,(8Fh) LOG IntPort8F,a ;*** TESTING in a,(86h) ld b,a LOG IntPort86,a ;*** TESTING bit 2,a jr nz,enableControlOutput in a,(82h) LOG IntPort82,a ;*** TESTING bit 0,a jr nz,controlDataReady in a,(84h) LOG IntPort84,a bit 2,a jr nz,bulkDataReady bit 0,b jr nz,bit0Port86hSet LOG Custom,2 ;*** TESTING jr cancelUSBHook ;*** INCOMPLETE - some sort of data enableControlOutput: LOG EnableOut,0 xor a ld (9C86h),a ld a,1 out (5Bh),a in a,(87h) or 1 out (87h),a jr cancelUSBHook controlDataReady: xor a out (8Eh),a in a,(91h) LOG ControlData,a cp 5 ;*** HACK: I have no idea why this is suddenly necessary... jr z,receiveControlPacket ; ld b,a and 4 jr z,$F ld a,b and 0FBh out (91h),a jr cancelUSBHook $$: ld a,b and 10h jr z,$F ld a,b or 80h out (91h),a $$: ld a,b and 1 jr nz,receiveControlPacket ld hl,USBflag bit setAddress,(hl) jr z,cancelUSBHook ;this should never happen (but apparently it does, OS ignores it) res setAddress,(hl) ld a,(USBaddress) LOG SetAddress,a out (80h),a jr cancelUSBHook receiveControlPacket: ld hl,inputBuffer ld b,8 call GetControlPacket ; bit debugOn,(iy+periph8xFlags) ;***TESTING ; call nz,DoDebug ;***TESTING ld a,(inputBuffer) LOG ControlData,a cp 80h jr z,deviceToHostReceived cp 81h jr z,deviceToHostReceived cp 02h jr z,endpointPacketReceived or a jr z,hostToDeviceReceived ld hl,USBflag bit msdActive,(hl) jr z,$F cp 0A1h jr z,getMaxLUNReceived $$: bit kbdActive,(hl) jr z,stallControlPipeEndHook cp 21h jr z,classSpecificRequestReceived cp 22h jr z,classSpecificRequestReceived stallControlPipeEndHook: ld hl,inputBuffer ld de,statVars+100h ld bc,8 ldir LOG IStallPipe,0 xor a out (8Eh),a ld a,60h out (91h),a cancelUSBHook: ld b,0 ret exitUSBHook: ld b,2Ch ret ;-------------------------------------------------------------------------------------------------- ;Control Requests ;-------------------------------------------------------------------------------------------------- endpointPacketReceived: ld a,(inputBuffer+1) cp 1 jr z,clearFeatureEndpoint cp 3 jr z,setFeatureEndpoint jr stallControlPipeEndHook deviceToHostReceived: ld a,(inputBuffer+1) cp 06h jr z,getDescriptorReceived jr stallControlPipeEndHook hostToDeviceReceived: ld a,(inputBuffer+1) cp 05h jr z,setAddressReceived cp 09h jr z,setConfigurationReceived cp 03h jr z,setFeatureReceived dec a jr nz,stallControlPipeEndHook ;Clear feature received jr finishControlRequest setFeatureReceived: jr finishControlRequest classSpecificRequestReceived: ld a,(inputBuffer+1) cp 0Ah jr z,setIdleRequest cp 09h jr z,setReportRequest jr stallControlPipeEndHook getMaxLUNReceived: ; LOG OutA0Start,0 xor a out (8Eh),a ld a,40h out (91h),a xor a out (0A0h),a finishControlOutput: ; bit debugOn,(iy+periph8xFlags) ;***TESTING ; call nz,DoDebug ;***TESTING xor a out (8Eh),a ld a,0Ah out (91h),a call WaitPort82 ; bit debugOn,(iy+periph8xFlags) ;***TESTING ; call nz,DoDebug ;***TESTING call WaitPort82 ; bit debugOn,(iy+periph8xFlags) ;***TESTING ; call nz,DoDebug ;***TESTING jr cancelUSBHook clearFeatureEndpoint: ;Something is telling the calculator to clear the halt condition on an endpoint. ld a,(inputBuffer+4) and 7Fh ld (USBaddress),a ld a,(inputBuffer+4) and 80h ld (USBaddress+1),a in a,(8Eh) push af ld a,(USBaddress) out (8Eh),a ld a,(USBaddress+1) or a jr z,$F in a,(91h) and 0EFh or 40h out (91h),a jr endpointReceivedDone $$: in a,(94h) and 0DFh or 80h out (94h),a endpointReceivedDone: pop af out (8Eh),a jr finishControlRequest setFeatureEndpoint: ;Something is telling the calculator to halt an endpoint. ld a,(inputBuffer+4) and 7Fh ld (USBaddress),a ld a,(inputBuffer+4) and 80h ld (USBaddress+1),a in a,(8Eh) push af ld a,(USBaddress) out (8Eh),a ld a,(USBaddress+1) or a jr nz,$F ld a,10h out (91h),a jr endpointReceivedDone $$: ld a,20h out (91h),a jr endpointReceivedDone setReportRequest: xor a out (8Eh),a ld a,40h out (91h),a ld de,0FFFFh $$: dec de ld a,d or e jr z,stallControlPipeEndHook in a,(82h) and 1 jr z,$B in a,(91h) and 1 jr z,stallControlPipeEndHook in a,(96h) dec a jr nz,stallControlPipeEndHook in a,(0A0h) ;this is probably 01, don't really care either way jr finishControlRequest setConfigurationReceived: LOG SetConfig,0 ld a,1 out (8Eh),a ld a,1 ld hl,USBflag set driverConfigured,(hl) ;HID/other communication can start now bit kbdActive,(hl) jr nz,$F ld a,8 $$: call SetupOutPipe ld a,2 out (8Eh),a bit kbdActive,(hl) jr nz,$F ld a,8 call SetupInPipe jr finishSetConfiguration $$: ld a,1 out (8Eh),a ld a,0Ah out (99h),a ld a,31h out (98h),a xor a in a,(98h) ld a,c out (90h),a xor a in a,(90h) finishSetConfiguration: xor a ld (bytesRemaining),a jr finishControlRequest setAddressReceived: ld a,(inputBuffer+2) LOG GotSetAddr,a ld (USBaddress),a ld hl,USBflag set setAddress,(hl) ld a,1 out (5Bh),a ld a,7Fh out (87h),a ld a,0Eh out (89h),a jr finishControlRequest getDescriptorReceived: ; xor a ;***TESTING ; ld (col1),a ;***TESTING ld a,(inputBuffer+3) ; call DispHexA LOG ReadDescriptor,a dec a ;cp 01h jr z,deviceDescriptorReceived dec a ;cp 02h jr z,configDescriptorReceived dec a ;cp 03h jr z,stringDescriptorReceived cp 22h-3 jr z,reportDescriptorReceived jr stallControlPipeEndHook reportDescriptorReceived: ;set debugOn,(iy+periph8xFlags) ;***TESTING ld a,(inputBuffer+4) or a ld de,HIDreportDescriptor jr nz,stallControlPipeEndHook ld a,(inputBuffer+6) ld (numOutBytes),a ld a,(de) inc de ld hl,numOutBytes ld b,(hl) cp b jr nc,$F ld (numOutBytes),a jr $F stringDescriptorReceived: ld a,(inputBuffer+2) ;***HACK - it should pull this from the API LOG StringDesc,a or a ld de,stringDescriptor jr z,descriptorReceived dec a ld de,manufacturerString jr z,descriptorReceived dec a jr nz,stallControlPipeEndHook ld de,productString in a,(21h) and 3 jr z,descriptorReceived ld de,productStringSE jr descriptorReceived configDescriptorReceived: ld a,(inputBuffer+6) ld (numOutBytes),a ld de,(configDescAddress) inc de inc de ld a,(de) dec de dec de ld hl,numOutBytes ld b,(hl) cp b jr nc,$F ld (numOutBytes),a jr $F deviceDescriptorReceived: ld de,(deviceDescAddress) descriptorReceived: ld a,(de) ld (numOutBytes),a $$: xor a out (8Eh),a ld a,40h out (91h),a descriptorOutLoop: ld a,(numOutBytes) cp 40h jr c,$F ld b,40h ;***HACK - bMaxPacketSize0 is hard-coded here sub b ld (numOutBytes),a jr continueOutput $$: ld b,a xor a ld (numOutBytes),a continueOutput: push bc ;***HACK - apparently the 40h command above needs a little delay sometimes ld bc,0FFh ; - the check on port 82h might be meaningless, but if it $$: ;in a,(82h) ; actually did succeed, the delay is no longer necessary ;bit 0,a ; ;jr nz,$F ; ex hl,(sp) ; ex hl,(sp) ; ex hl,(sp) ; ex hl,(sp) ; dec bc ; ld a,b ; or c ; jr nz,$B ; $$: pop bc ; $$: ld a,(de) out (0A0h),a inc de djnz $B ld a,(numOutBytes) or a jr z,finishControlOutput xor a out (8Eh),a ld a,2 out (91h),a jr descriptorOutLoop setIdleRequest: finishControlRequest: xor a out (8Eh),a in a,(91h) ld a,48h out (91h),a in a,(91h) jr cancelUSBHook ;-------------------------------------------------------------------------------------------------- ;Bulk Requests ;-------------------------------------------------------------------------------------------------- bulkDataReady: ld a,2 out (8Eh),a in a,(96h) LOG InData,a ld c,a ;might not need to do this ld b,0 ; set 5,(iy+41h) set 0,(iy+41h) xor a out (5Bh),a ld (bytesRemaining),a ld hl,USBflag bit calcActive,(hl) jr z,$F ;Calculator bulk data received, deal with it call handleCalcData jr cancelUSBHook $$: bit msdActive,(hl) jr z,cancelUSBHook ;Mass storage bulk data received, deal with it call DoMassStorageHandle jr cancelUSBHook ;-------------------------------------------------------------------------------------------------- ;HID Keyboard HIDdeviceDescriptor: DB 12h ;size of descriptor DB 01h ;device descriptor type DW 0110h ;USB version DB 00h ;bDeviceClass DB 00h ;bDeviceSubClass DB 00h ;bDeviceProtocol DB 40h ;bMaxPacketSize0 DW 0451h ;wVendorID DW 2007h ;wProductID DW 0301h ;device release number DB 01h ;manufacturer string index DB 02h ;product string index DB 00h ;serial number string index DB 01h ;bNumConfigurations HIDconfigDescriptor: DB 09h ;size of descriptor DB 02h ;config descriptor type DW 34 ;total length of all descriptors DB 01h ;number of interfaces DB 01h ;configuration number DB 00h ;configuration string index DB 0A0h ;bmAttributes DB 00h ;bMaxPower (0mA) (previously 23h) ;Interface descriptor DB 09h ;size of descriptor DB 04h ;interface descriptor type DB 00h ;interface number DB 00h ;bAlternateSetting DB 01h ;bNumEndpoints DB 03h ;bInterfaceClass DB 01h ;bInterfaceSubClass DB 01h ;bInterfaceProtocol DB 00h ;interface string index ;HID descriptor DB 09h ;size of descriptor DB 21h ;HID descriptor type DW 0110h ;bcdHID DB 00h ;bCountryCode DB 01h ;bNumDescriptors DB 22h ;bDescriptorType DW HIDreportDescriptorEnd-HIDreportDescriptor-1 ;Endpoint descriptor (in) DB 07h ;size of descriptor DB 05h ;endpoint descriptor type DB 10000001b ;bEndpointAddress DB 03h ;interrupt endpoint DW 0008h ;wMaxPacketSize DB 0Ah ;bInterval HIDreportDescriptor: DB HIDreportDescriptorEnd-HIDreportDescriptor-1 DB 05h,07h DB 05h,01h ;Usage Page (Generic Desktop) DB 09h,06h ;Usage (Keyboard) DB 0A1h,01h ;Collection (Application) DB 05h,07h ; Usage Page (Key Codes) DB 19h,0E0h ; Usage Minimum (224) DB 29h,0E7h ; Usage Maximum (231) DB 15h,00h ; Logical Minimum (0) DB 25h,01h ; Logical Maximum (1) DB 75h,01h ; Report Size (1) DB 95h,08h ; Report Count (8) DB 81h,02h ; Input (Data, Variable, Absolute) ;Modifier byte DB 95h,01h ; Report Count (1) DB 75h,08h ; Report Size (8) DB 81h,01h ; Input (Constant) ;Reserved byte DB 95h,05h ; Report Count (5) DB 75h,01h ; Report Size (1) DB 05h,08h ; Usage Page (Page# for LEDs) DB 19h,01h ; Usage Minimum (1) DB 29h,05h ; Usage Maximum (5) DB 91h,02h ; Output (Data, Variable, Absolute) ;LED report DB 95h,01h ; Report Count (1) DB 75h,03h ; Report Size (3) DB 91h,01h ; Output (Constant) ;LED report padding DB 95h,06h ; Report Count (6) DB 75h,08h ; Report Size (8) DB 15h,00h ; Logical Minimum (0) DB 25h,65h ; Logical Maximum (101) DB 05h,07h ; Usage Page (Key Codes) DB 19h,00h ; Usage Minimum (0) DB 29h,65h ; Usage Maximum (101) DB 81h,00h ; Input (Data, Array) ;Key arrays (6 bytes) DB 0C0h ;End Collection HIDreportDescriptorEnd: ;String descriptors stringDescriptor: DB 04h ;size of descriptor DB 03h ;string descriptor type DB 09h,04h ;UNICODE string manufacturerString: DB manufacturerStringEnd-manufacturerString DB 03h DB 'T',0,'e',0,'x',0,'a',0,'s',0,' ',0,'I',0,'n',0,'s',0,'t',0,'r',0,'u',0,'m',0,'e',0,'n',0,'t',0,'s',0,' ',0 DB 'I',0,'n',0,'c',0,'o',0,'r',0,'p',0,'o',0,'r',0,'a',0,'t',0,'e',0,'d',0 manufacturerStringEnd: productString: DB productStringEnd-productString DB 03h DB 'T',0,'I',0,'-',0,'8',0,'4',0,' ',0,'P',0,'l',0,'u',0,'s',0 productStringEnd: productStringSE: DB productStringSEEnd-productStringSE DB 03h DB 'T',0,'I',0,'-',0,'8',0,'4',0,' ',0,'P',0,'l',0,'u',0,'s',0,' ',0 DB 'S',0,'i',0,'l',0,'v',0,'e',0,'r',0,' ',0,'E',0,'d',0,'i',0,'t',0,'i',0,'o',0,'n',0 productStringSEEnd: