;USB high-level standard requests include "ti83plus.inc" include "equates.inc" PUBLIC DirectUSB_AssignNextAddress,DirectUSB_GetDescriptor,DirectUSB_ConfigureDevice,DirectUSB_RequestData PUBLIC DirectUSB_ClearFeature,DirectUSB_ClearEndpointHalt EXTERN IPutC,DispHexA,DispHexHL EXTERN DirectUSB_SendControlData,DirectUSB_SendControlRequest,DecrementCounter,IsPort86hError EXTERN DirectUSB_Suspend,IsControlNAKOrStall,DirectUSB_Suspend,DirectUSB_MessagePump DirectUSB_ClearEndpointHalt: ;IX => device information structure ;E: endpoint number (OR with 80h for an incoming pipe) ld b,00000010b ld hl,0 ld d,0 ;Fall through to DirectUSB_ClearFeature DirectUSB_ClearFeature: ;IX => device information structure ;HL: wValue (feature/selector) ;DE: wIndex (zero/interface/endpoint) ;B: bmRequestType: ; Device: 00000000b ; Interface: 00000001b ; Endpoint: 00000010b in a,(80h) push af push hl push de push bc ld a,(ix+0) out (80h),a ld hl,sClearFeature rst 20h pop af pop de pop hl ld (OP1),a ld (OP1+2),hl ld (OP1+4),de ld hl,OP1 ld bc,0 call DirectUSB_SendControlData pop bc ld a,b out (80h),a ret sClearFeature: DB 00000010b, 1, 0, 0, 81h, 0, 0, 0 DirectUSB_RequestData: ;IX => device information structure ;C: endpoint number ld a,8 call IPutC ld a,(ix+0) call DispHexA out (80h),a inc ix ; inc ix ld b,0 add ix,bc ld a,(ix+0) call DispHexA out (8Eh),a ld a,20h out (94h),a ret ;This configures the connected peripheral with configuration B. DirectUSB_ConfigureDevice: push bc ld hl,bConfigureDevice rst 20h pop af ld (OP1+2),a ld hl,OP1 ld bc,0 jr DirectUSB_SendControlData bConfigureDevice: DB 00h,09h,00h,00h,00h,00h,00h,00h DirectUSB_GetDescriptor: ;A: descriptor type (01h = device, 02h = configuration) ;BC: number of bytes expected to receive in response ;DE => buffer for response ;Returns carry flag set if problems push de push af push bc ld hl,bGetDeviceDescriptor rst 20h pop bc pop af pop de ld (OP1+3),a ld (OP1+6),bc ld hl,OP1 jr DirectUSB_SendControlData bGetDeviceDescriptor: DB 80h,06h,00h,01h,00h,00h,08h,00h DirectUSB_AssignNextAddress: ;Returns device address in A ld a,(nextAddress) push af call DirectUSB_AssignAddress inc a or a jr nz,$F inc a ;don't allow address zero $$: ld (nextAddress),a pop af or a ret DirectUSB_AssignAddress: ;A: device address push af ld hl,bSetAddress rst 20h pop af ld (OP1+2),a ld hl,OP1 ld bc,0 push af call DirectUSB_SendControlData pop bc ret c ld a,b out (80h),a ret bSetAddress: DB 00h,05h,02h,00h,00h,00h,00h,00h ;This sends the USB On-the-Go a_hnp_support Set Feature control request. ;I'm not sure if it's actually necessary, but it indicates to the peripheral that we support OTG. Or something. DirectUSB_SetFeature_a_hnp_support: ld hl,0 ld (9C2Bh),hl ld (9C2Dh),hl ld (9C2Fh),hl xor a ld (controlRequestBuffer),a ld a,3 ld (controlRequestBuffer+1),a call DirectUSB_SendControlRequest ld de,0FFFFh $$: call DecrementCounter scf ret z call IsPort86hError jp nz,DirectUSB_Suspend in a,(82h) and 1 jr z,$B call IsControlNAKOrStall scf ret nz xor a out (8Eh),a ld a,60h 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 call IsControlNAKOrStall scf ret nz xor a out (8Eh),a xor a out (91h),a call IsControlNAKOrStall scf ret nz xor a ret ;Sends bulk data over USB. ;Inputs: HL => buffer to read from (on extra RAM page 0x83 -- 0x8000 range). ; DE: number of bytes to receive ;Outputs: DE bytes sent from HL ; Carry flag set if any issues ;This is a fragile routine in need of major optimization, because I ripped it from another program of mine in a hurry. DirectUSB_SendData: res 5,(iy+41h) xor a ld (9C7Dh),a ld (9C81h),de ld (9C7Eh),hl in a,(8Fh) bit 2,a jp z,sendAsPeripheral ld a,2 out (8Eh),a ld a,22h out (98h),a xor a in a,(98h) ld a,8 out (90h),a xor a in a,(90h) ld a,0FFh out (87h),a xor a out (92h),a in a,(87h) ld a,21h out (8Bh),a in a,(8Bh) jr startSendAsHost sendHostLarge: ld a,1 ld (9C7Dh),a ld b,40h $$: call GetExtraRAMByte out (0A2h),a inc hl dec de djnz $B ld (9C81h),de ld (9C7Eh),hl ld a,2 out (8Eh),a ld a,1 out (91h),a jr sendHostContinue sendHostRestart: ld a,2 out (8Eh),a startSendAsHost: ld a,d or a jr nz,sendHostLarge ld a,e cp 40h jr nc,sendHostLarge or a jr z,sendDone ld b,a xor a ld (9C7Dh),a $$: call GetExtraRAMByte out (0A2h),a inc hl djnz $B ld a,2 out (8Eh),a ld a,1 out (91h),a sendHostContinue: call IsPort86hError jp nz,DirectUSB_Suspend in a,(82h) and 4 jr z,sendHostContinue in a,(91h) bit 2,a jp nz,DirectUSB_Suspend bit 5,a jp nz,DirectUSB_Suspend ld hl,(9C7Eh) ld de,(9C81h) ld a,(9C7Dh) or a jr nz,sendHostRestart ld a,2 out (8Eh),a ld a,8 out (91h),a sendDone: ; set 5,(iy+41h) ;uh, what? xor a ld (9C27h),a ret sendAsPeripheral: ld a,1 out (8Eh),a ld a,21h out (98h),a xor a in a,(98h) ld a,8 out (90h),a xor a in a,(90h) ld a,0FFh out (87h),a xor a out (92h),a in a,(87h) ld a,21h out (8Bh),a in a,(8Bh) jr startSendPeriph sendPeriphLarge: xor a out (5Bh),a ld b,40h $$: call GetExtraRAMByte out (0A1h),a inc hl dec de djnz $B ld a,1 out (8Eh),a ld a,1 out (91h),a $$: call IsPort86hError jp nz,DirectUSB_Suspend in a,(82h) and 2 jr z,$B in a,(91h) bit 5,a jp nz,DirectUSB_Suspend ld a,1 out (8Eh),a ld a,8 out (91h),a startSendPeriph: ld a,d or a jr nz,sendPeriphLarge ld a,e cp 40h jr nc,sendPeriphLarge or a jr z,sendPeriphContinue ld b,a $$: call GetExtraRAMByte out (0A1h),a inc hl djnz $B sendPeriphContinue: ld a,1 out (8Eh),a ld a,1 out (91h),a $$: call IsPort86hError jp nz,DirectUSB_Suspend in a,(82h) and 2 jr z,$B in a,(91h) bit 5,a jp nz,DirectUSB_Suspend ld a,1 out (8Eh),a ld a,8 out (91h),a ret GetExtraRAMByte: ld a,83h out (7),a ld c,(hl) ld a,81h out (7),a ld a,c ret DirectUSB_ReceiveDataWait: ;Receives data over USB (waits until all data is received). ;Inputs: HL => buffer to store data to. ; BC: number of bytes to receive ;Outputs: BC bytes received to HL ; Carry flag set if any issues ;Make sure you know how much you need to receive before calling. ;This is a blocking call and will not return until you press [ON] or everything is received. call DirectUSB_MessagePump in a,(4) bit 3,a scf ret z bit 5,(iy+41h) jr z,DirectUSB_ReceiveDataWait ;Receives bulk data over USB. ;Inputs: HL => buffer to store data to. ; BC: number of bytes to receive ;Outputs: BC bytes received to HL ; Carry flag set if any issues ;Make sure you know how much you need to receive before calling. ;This is a fragile routine in need of major optimization, because I ripped it from another program of mine in a hurry. DirectUSB_ReceiveData: push bc push af xor a ld (9834h),a jr receive_data_ready receive_big_loop: in a,(4) bit 3,a jr z,P2scfRet bit 5,(iy+41h) jr nz,receive_data_ready in a,(84h) bit 2,a jr nz,receiving_data bit 1,a jr z,restart_receive_loop receiving_data: set 5,(iy+41h) xor a ld (9C27h),a jr receive_data_ready restart_receive_loop: in a,(86h) bit 5,a jr nz,P2scfRet jr receive_big_loop receive_data_ready: push bc push hl ld hl,40h or a sbc hl,bc pop hl ld b,c jr nc,receiveRest ld b,40h receiveRest: call ReceiveUSBData_small ex de,hl pop hl jr c,P2scfRet or a ld b,0 sbc hl,bc jr z,P2ret ld b,h ld c,l ex de,hl jr receive_big_loop P2ret: pop bc ld a,b pop bc ret P2scfRet: pop af pop bc scf ret ReceiveUSBData_small: ld a,b or a ret z ld a,40h cp b ret c ld a,b ld (9C80h),a ld a,(9C27h) or a jr z,ReceiveUSBData_continue cp b jr nc,ReceiveUSBData_continue ld b,a ld (9C80h),a ReceiveUSBData_continue: in a,(8Fh) bit 2,a jp z,calcIsPeripheral xor a out (5Bh),a ld a,(9C27h) or a jr nz,startReceive ld a,1 out (8Eh),a ld a,21h out (9Ah),a xor a in a,(9Ah) ld a,8 out (93h),a xor a in a,(93h) ld a,0FFh out (89h),a xor a out (95h),a in a,(89h) ld a,0A1h out (8Bh),a in a,(94h) bit 2,a jp nz,receiveError bit 6,a jp nz,receiveError ; ld a,1 ; out (5Bh),a ld a,(9C27h) or a jr nz,startReceive ld a,1 out (8Eh),a in a,(94h) in a,(96h) startReceive: push af ld a,(9C80h) ld b,a ld c,0 receiveLoop: in a,(0A1h) ld (hl),a inc hl inc c djnz receiveLoop ld a,1 out (8Eh),a in a,(94h) bit 2,a jr nz,p1ReceiveError bit 6,a jr nz,p1ReceiveError pop af sub c ld (9C27h),a set 5,(iy+41h) ret nz ld a,1 out (8Eh),a ld a,21h out (9Ah),a ld a,8 out (93h),a xor a in a,(93h) ld a,0Eh out (89h),a xor a out (95h),a res 5,(iy+41h) xor a ld (9C27h),a res 0,(iy+41h) ld a,20h out (94h),a ; ld a,1 ; out (5Bh),a ret calcIsPeripheral: ld a,2 out (8Eh),a in a,(94h) bit 6,a jr z,startReceive2 and 0DFh out (94h),a pop af call DirectUSB_Suspend jr receiveError startReceive2: ld a,(9C27h) or a jr nz,startReceive3 in a,(96h) startReceive3: push af ld c,0 receivePeriphLoop: in a,(0A2h) ld (hl),a inc hl inc c djnz receivePeriphLoop ld a,2 out (8Eh),a pop af sub c ld (9C27h),a ret nz xor a ld (9C27h),a in a,(94h) and 0FEh out (94h),a res 5,(iy+41h) ld a,0A1h out (8Bh),a jr endReceive p1ReceiveError: pop af receiveError: res 5,(iy+41h) scf endReceive: ; ei ; ld a,1 ; out (5Bh),a res 0,(iy+41h) ret