;USB interrupt-related routines include "ti83plus.inc" include "equates.inc" PUBLIC DirectUSB_SetUSBInterruptState,DirectUSB_SetDefaultDescriptors,DirectUSB_SetPeripheralDescriptors PUBLIC DirectUSB_MessagePump EXTERN IPutC,DispHexA,DispHexHL EXTERN DirectUSB_Suspend,WaitTimerB10ms,DirectUSB_GetCurrentDevice,DirectUSB_ClearEndpointHalt EXTERN DirectUSB_GetHubPortStatus,DirectUSB_ClearHubPortFeature,DirectUSB_RequestData EXTERN DirectUSB_SetHubPortFeature,DirectUSB_HandleAttachedDevice,DirectUSB_EnablePower EXTERN DirectUSB_EnableHostMode,DirectUSB_HostInit,DirectUSB_PeripheralInit,DirectUSB_Kill EXTERN DirectUSB_Init,DirectUSB_WaitForStableLines,DirectUSB_ReceiveControlRequest,IsPort86hError EXTERN DecrementCounter DirectUSB_SetUSBInterruptState: ;A: zero to disable USB-related interrupts (you must handle it yourself); non-zero to enable them or a jr z,$F ;Install USB activity hook to respond to unsolicited events ld hl,DirectUSB_USBActivityHook in a,(6) rst 28h DW 528Ah ;Enable USB-related interrupts set interruptsEnabled,(iy+USBFlags) ld a,1 out (5Bh),a ret $$: ;Disable USB-related interrupts di xor a out (5Bh),a res interruptsEnabled,(iy+USBFlags) ret DirectUSB_SetDefaultDescriptors: ld hl,calcDeviceDescriptor84PSE in a,(21h) and 3 jr nz,$F ld hl,calcDeviceDescriptor84P $$: ld de,calcConfigDescriptor DirectUSB_SetPeripheralDescriptors: ;HL: address of device descriptor ;DE: address of configuration descriptor ld (deviceDesc),hl ld bc,7 add hl,bc ld a,(hl) ld (bMaxPacketSize0),a ld (configDesc),de ret DirectUSB_USBActivityHook: add a,e push ix call DirectUSB_MessagePump pop ix ld b,0 ret DirectUSB_MessagePump: ld a,'I' call IPutC in a,(55h) LOG Interrupt,a call DispHexA ld b,a in a,(56h) LOG Interrupt,a call DispHexA or a jr z,$F ;Handle connect/disconnect events bit 1,a jr nz,DirectUSB_HandleBit1Event in a,(57h) ld c,a xor a out (57h),a ld a,c out (57h),a ret $$: ld a,b and 11h xor 11h ret z bit 4,b jr z,DirectUSB_ReadData di in a,(8Fh) bit 7,a jr nz,DirectUSB_Suspend xor a out (5Bh),a ld a,20h ;A cable unplugged event out (57h),a ld b,50 call WaitTimerB10ms ld a,1 out (5Bh),a ret DirectUSB_ReadData: in a,(82h) call DispHexA in a,(84h) ld c,a call DispHexA in a,(86h) call DispHexA ld b,a ;... in a,(8Fh) call DispHexA bit 7,a jr nz,$F ld a,b ;... bit 7,a jr nz,DirectUSB_Error7 $$: ld a,b bit 5,a jr nz,DirectUSB_Suspend bit 4,a ; jr nz,DirectUSB_Reconnect bit 1,a jr nz,DirectUSB_Suspend ld a,c bit 1,a jr nz,$F ret $$: ld a,1 out (80h),a out (8Eh),a in a,(94h) call DispHexA bit 2,a jr nz,$F bit 6,a jr nz,$F ld a,'R' call IPutC in a,(96h) ld b,a readLoop: in a,(0A1h) call DispHexA djnz readLoop ld a,'E' call IPutC jr skipRead $$: call DirectUSB_GetCurrentDevice ld e,81h call DirectUSB_ClearEndpointHalt skipRead: xor a out (94h),a call DirectUSB_GetCurrentDevice ld hl,1 call DirectUSB_GetHubPortStatus jr c,$F ex de,hl call DispHexHL ex de,hl call DispHexHL LOG GetHubStatus,d LOG GetHubStatus,e LOG GetHubStatus,h LOG GetHubStatus,l call DirectUSB_GetCurrentDevice bit 0,d jr z,startClearFeatureTests bit 4,d jr nz,startClearFeatureTests bit newDeviceConnected,(iy+USBFlags) jr nz,startClearFeatureTests bit 0,h call nz,ResetNewDevice startClearFeatureTests: ld bc,16 bit 0,h jr nz,clearFeature ld bc,17 bit 1,h jr nz,clearFeature ld bc,18 bit 2,h jr nz,clearFeature ld bc,19 bit 3,h jr nz,clearFeature ld bc,20 bit 4,h jr nz,clearFeature ld bc,0 clearFeature: ld h,b ld l,c ld de,1 push hl call DirectUSB_ClearHubPortFeature pop hl jr c,$F ld de,20 or a sbc hl,de call z,HandleNewDevice ld a,'L' call IPutC $$: call DirectUSB_GetCurrentDevice ld c,1 call DirectUSB_RequestData ld a,'D' call IPutC ret ResetNewDevice: set newDeviceConnected,(iy+USBFlags) ld a,'N' call IPutC call DirectUSB_GetCurrentDevice ld hl,4 ld de,1 call DirectUSB_SetHubPortFeature ret HandleNewDevice: xor a out (80h),a call DirectUSB_HandleAttachedDevice ld a,1 out (80h),a ret DirectUSB_Reconnect: ld a,20h out (4Ah),a ld a,2 out (54h),a call DirectUSB_EnablePower ld de,0FFFFh $$: call DecrementCounter jr z,DirectUSB_Suspend in a,(4Ch) cp 12h jr z,$F cp 52h jr nz,$B $$: call DirectUSB_EnableHostMode ret DirectUSB_Error7: call DirectUSB_Suspend ei ld a,1 out (5Bh),a ret DirectUSB_HandleBit1Event: in a,(4Dh) bit 5,a call DispHexA ret nz ld a,20h call DispHexA out (57h),a call DirectUSB_HostInit ret nc ld a,0FFh call DispHexA ret DirectUSB_NoOSMessagePump: bit 5,(iy+1Bh) jr z,$F ;We're initialized, so check for activity in a,(82h) bit 0,a jp nz,DirectUSB_HandleControlData in a,(84h) bit 2,a jp nz,DirectUSB_HandleBulkData in a,(86h) bit 5,a ret z call DirectUSB_Suspend res 5,(iy+1Bh) ret $$: in a,(4Dh) and 40h jr nz,$F in a,(56h) and 0F2h $$: ret z ;We have an event to process ;Bit 4: A cable plugged in ;Bit 5: A cable unplugged ;Bit 6: B cable plugged in ;Bit 7: B cable unplugged bit 4,a jp nz,DirectUSB_WaitForStableLines bit 5,a jp nz,DirectUSB_WaitForStableLines bit 6,a jp nz,initializeUSB bit 7,a jr nz,killUSB bit 1,a ret z in a,(4Dh) bit 5,a jr nz,initializeUSB ;we're a peripheral call DirectUSB_Init ;we're a host set 5,(iy+1Bh) ret killUSB: call DirectUSB_Kill res 5,(iy+1Bh) ret initializeUSB: call DirectUSB_PeripheralInit set 5,(iy+1Bh) ret DirectUSB_HandleBulkData: set 5,(iy+41h) ret DirectUSB_HandleControlData: call DirectUSB_ReceiveControlRequest ;Handle the control request HandleControlRequest: ld a,(controlRequestBuffer) cp 80h jp z,deviceToHostReceived or a jr z,hostToDeviceReceived cp 02h jr z,endpointReceived cp 0A1h jr z,deviceToHostClassInterfaceReceived stallControlPipe: xor a out (8Eh),a ld a,0E0h out (91h),a ret deviceToHostClassInterfaceReceived: ld a,(controlRequestBuffer+1) cp 0FEh jr z,getMaxLUNReceived jr stallControlPipe getMaxLUNReceived: xor a out (0A0h),a jp DirectUSB_FinishControlOutput endpointReceived: ld a,(controlRequestBuffer+1) cp 01h jr z,endpointClearFeatureReceived cp 03h jr z,endpointSetFeatureReceived jr stallControlPipe hostToDeviceReceived: ld a,(controlRequestBuffer+1) cp 05h jr z,setAddressReceived cp 09h jr z,setConfigurationReceived jr stallControlPipe setConfigurationReceived: ld a,(controlRequestBuffer+2) ;A is the configuration value (1) ret endpointClearFeatureReceived: ld a,(controlRequestBuffer+4) and 7Fh ld (9C71h),a ld a,(controlRequestBuffer+4) and 80h ld (9C72h),a in a,(8Eh) push af ld a,(9C71h) out (8Eh),a ld a,(9C72h) or a jr z,$F in a,(91h) and 0EFh or 40h out (91h),a jr endpointFeatureDone $$: in a,(94h) and 0DFh or 80h out (94h),a endpointFeatureDone: pop af out (8Eh),a xor a out (8Eh),a in a,(91h) ld a,48h out (91h),a in a,(91h) xor a ld (9C27h),a ret endpointSetFeatureReceived: ld a,(9C2Dh) ld (9C71h),a ld a,(9C2Dh) and 80h ld (9C72h),a in a,(8Eh) push af ld a,(9C71h) out (8Eh),a ld a,(9C72h) or a jr nz,$F ld a,10h out (91h),a jr endpointFeatureDone $$: ld a,20h out (94h),a jr endpointFeatureDone setAddressReceived: ;Wait a while and then set the address? Sounds strange, but the boot code does it, so surely it must be okay... ld b,1 call WaitTimerB10ms ld a,(controlRequestBuffer+2) out (80h),a or a in a,(80h) in a,(5Bh) ld a,0FFh out (87h),a xor a out (8Eh),a in a,(91h) ld a,48h out (91h),a in a,(91h) ret deviceToHostReceived: ld a,(controlRequestBuffer+1) cp 06h jr z,getDescriptorReceived jp stallControlPipe getDescriptorReceived: ld a,(controlRequestBuffer+3) cp 01h jr z,deviceDescriptor cp 02h jp z,configDescriptor ;Stall all string descriptor requests (don't care) jp stallControlPipe deviceDescriptor: ld hl,(deviceDesc) ld c,18 jr $F configDescriptor: ld hl,(configDesc) inc hl inc hl ld c,(hl) dec hl dec hl $$: ld a,(controlRequestBuffer+6) ld b,a ld a,c cp b jr nc,$F ld (controlRequestBuffer+6),a sendDescriptorLoop $$: ld a,(bMaxPacketSize0) ld c,a ld a,(controlRequestBuffer+6) cp c jr c,$F ld b,c sub b ld (controlRequestBuffer+6),a jr sendDescriptor $$: ld b,a xor a ld (controlRequestBuffer+6),a sendDescriptor: ld a,(hl) out (0A0h),a inc hl djnz sendDescriptor ld a,(controlRequestBuffer+6) or a jr z,$F xor a out (8Eh),a ld a,2 out (91h),a jr sendDescriptorLoop DirectUSB_FinishControlOutput: $$: xor a out (8Eh),a ld a,0Ah out (91h),a ld de,0FFFFh $$: call DecrementCounter scf ret z call IsPort86hError jp nz,DirectUSB_Suspend in a,(82h) and 1 jr z,$B in a,(91h) ld de,0FFFFh $$: call DecrementCounter scf ret z call IsPort86hError jp nz,DirectUSB_Suspend in a,(82h) and 1 jr z,$B in a,(91h) ret calcDeviceDescriptor84P: DB 12h DB 01h DW 0200h DB 00h, 00h, 00h DB DEFAULT_MAX_PACKET_SIZE0 DW 0451h DW 0E003h DW 0100h DB 00h ;01h ;no manufacturer or product string descriptors for now DB 00h ;02h DB 00h DB 01h calcDeviceDescriptor84PSE: DB 12h DB 01h DW 0200h DB 00h, 00h, 00h DB DEFAULT_MAX_PACKET_SIZE0 DW 0451h DW 0E008h DW 0100h DB 00h ;01h ;no manufacturer or product string descriptors for now DB 00h ;02h DB 00h DB 01h calcConfigDescriptor: DB 09h DB 02h DW 0023h DB 01h DB 01h DB 00h DB 0E0h ;attributes DB 00h ;self-powered DB 09h, 04h, 00h, 00h, 02h, 0FFh, 01h, 00h, 00h DB 07h, 05h, 81h, 02h, 40h, 00h, 00h ;incoming bulk endpoint 0x81 DB 07h, 05h, 02h, 02h, 40h, 00h, 00h ;outgoing bulk endpoint 0x02 DB 03h, 09h, 03h ;OTG/HNP configDescriptorEnd: