convert usbhid and usbstor to PE

git-svn-id: svn://kolibrios.org@5051 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
CleverMouse 2014-08-22 09:54:27 +00:00
parent 962d0858c7
commit 7dce54fc55
8 changed files with 261 additions and 294 deletions

View File

@ -134,8 +134,6 @@ FASM_PROGRAMS:=\
drivers/sb16.obj:DRIVERS/SB16.OBJ:$(KERNEL)/drivers/sb16/sb16.asm \ drivers/sb16.obj:DRIVERS/SB16.OBJ:$(KERNEL)/drivers/sb16/sb16.asm \
drivers/sound.obj:DRIVERS/SOUND.OBJ:$(KERNEL)/drivers/sound.asm \ drivers/sound.obj:DRIVERS/SOUND.OBJ:$(KERNEL)/drivers/sound.asm \
drivers/intelac97.obj:DRIVERS/INTELAC97.OBJ:$(KERNEL)/drivers/intelac97.asm \ drivers/intelac97.obj:DRIVERS/INTELAC97.OBJ:$(KERNEL)/drivers/intelac97.asm \
drivers/usbhid.obj:DRIVERS/USBHID.OBJ:$(KERNEL)/drivers/usbhid/usbhid.asm \
drivers/usbstor.obj:DRIVERS/USBSTOR.OBJ:$(KERNEL)/drivers/usbstor.asm \
drivers/vt823x.obj:DRIVERS/VT823X.OBJ:$(KERNEL)/drivers/vt823x.asm \ drivers/vt823x.obj:DRIVERS/VT823X.OBJ:$(KERNEL)/drivers/vt823x.asm \
drivers/3c59x.obj:DRIVERS/3C59X.OBJ:$(REPOSITORY)/drivers/ethernet/3c59x.asm \ drivers/3c59x.obj:DRIVERS/3C59X.OBJ:$(REPOSITORY)/drivers/ethernet/3c59x.asm \
File|Managers/kfar:File|Managers/KFAR:$(PROGS)/fs/kfar/trunk/kfar.asm \ File|Managers/kfar:File|Managers/KFAR:$(PROGS)/fs/kfar/trunk/kfar.asm \
@ -226,6 +224,8 @@ FASM_PROGRAMS_PESTRIP:=\
drivers/uhci.sys:DRIVERS/UHCI.SYS:$(REPOSITORY)/drivers/usb/uhci.asm \ drivers/uhci.sys:DRIVERS/UHCI.SYS:$(REPOSITORY)/drivers/usb/uhci.asm \
drivers/ohci.sys:DRIVERS/OHCI.SYS:$(REPOSITORY)/drivers/usb/ohci.asm \ drivers/ohci.sys:DRIVERS/OHCI.SYS:$(REPOSITORY)/drivers/usb/ohci.asm \
drivers/ehci.sys:DRIVERS/EHCI.SYS:$(REPOSITORY)/drivers/usb/ehci.asm \ drivers/ehci.sys:DRIVERS/EHCI.SYS:$(REPOSITORY)/drivers/usb/ehci.asm \
drivers/usbhid.sys:DRIVERS/USBHID.SYS:$(REPOSITORY)/drivers/usb/usbhid/usbhid.asm \
drivers/usbstor.sys:DRIVERS/USBSTOR.SYS:$(REPOSITORY)/drivers/usb/usbstor.asm \
drivers/rdc.sys:DRIVERS/RDC.SYS:$(REPOSITORY)/drivers/video/rdc.asm \ drivers/rdc.sys:DRIVERS/RDC.SYS:$(REPOSITORY)/drivers/video/rdc.asm \
drivers/ps2mouse.sys:DRIVERS/PS2MOUSE.SYS:$(REPOSITORY)/drivers/mouse/ps2mouse4d/trunk/ps2mouse.asm \ drivers/ps2mouse.sys:DRIVERS/PS2MOUSE.SYS:$(REPOSITORY)/drivers/mouse/ps2mouse4d/trunk/ps2mouse.asm \
drivers/tmpdisk.sys:DRIVERS/TMPDISK.SYS:$(REPOSITORY)/drivers/disk/tmpdisk.asm \ drivers/tmpdisk.sys:DRIVERS/TMPDISK.SYS:$(REPOSITORY)/drivers/disk/tmpdisk.asm \

View File

@ -60,7 +60,7 @@ ends
proc keyboard_driver_add_device proc keyboard_driver_add_device
; 1. Allocate memory for keyboard_device_data. If failed, return NULL. ; 1. Allocate memory for keyboard_device_data. If failed, return NULL.
movi eax, sizeof.keyboard_device_data movi eax, sizeof.keyboard_device_data
call Kmalloc invoke Kmalloc
test eax, eax test eax, eax
jz .nothing jz .nothing
; 2. Initialize keyboard_device_data: store pointer to USB layer data, ; 2. Initialize keyboard_device_data: store pointer to USB layer data,
@ -154,7 +154,7 @@ proc keyboard_driver_add_device
; store pointer to keyboard_device_data in the stack ; store pointer to keyboard_device_data in the stack
push eax push eax
; call kernel API ; call kernel API
stdcall RegKeyboard, kbd_functions, eax invoke RegKeyboard, kbd_functions, eax
; restore pointer to keyboard_device_data from the stack, ; restore pointer to keyboard_device_data from the stack,
; putting keyboard handle from API to the stack ; putting keyboard handle from API to the stack
xchg eax, [esp] xchg eax, [esp]
@ -167,7 +167,7 @@ proc keyboard_driver_add_device
.nothing: .nothing:
ret ret
.fail_free: .fail_free:
call Kfree invoke Kfree
xor eax, eax xor eax, eax
ret ret
endp endp
@ -179,10 +179,10 @@ proc keyboard_driver_disconnect
; 1. If an autorepeat timer is active, stop it. ; 1. If an autorepeat timer is active, stop it.
cmp [edi+keyboard_device_data.timer], 0 cmp [edi+keyboard_device_data.timer], 0
jz @f jz @f
stdcall CancelTimerHS, [edi+keyboard_device_data.timer] invoke CancelTimerHS, [edi+keyboard_device_data.timer]
@@: @@:
; 2. Unregister keyboard in the kernel. ; 2. Unregister keyboard in the kernel.
stdcall DelKeyboard, [edi+keyboard_device_data.handle] invoke DelKeyboard, [edi+keyboard_device_data.handle]
; We should free data in CloseKeyboard, not here. ; We should free data in CloseKeyboard, not here.
ret ret
endp endp
@ -245,11 +245,11 @@ end if
mov eax, [edi+keyboard_device_data.timer] mov eax, [edi+keyboard_device_data.timer]
test eax, eax test eax, eax
jz @f jz @f
stdcall CancelTimerHS, eax invoke CancelTimerHS, eax
@@: @@:
; 1h. Start the new autorepeat timer with 250 ms initial delay ; 1h. Start the new autorepeat timer with 250 ms initial delay
; and 50 ms subsequent delays. ; and 50 ms subsequent delays.
stdcall TimerHS, 25, 5, autorepeat_timer, edi invoke TimerHS, 25, 5, autorepeat_timer, edi
mov [edi+keyboard_device_data.timer], eax mov [edi+keyboard_device_data.timer], eax
if ~HID_DUMP_UNCLAIMED if ~HID_DUMP_UNCLAIMED
.unclaimed: .unclaimed:
@ -265,7 +265,7 @@ end if
mov eax, [edi+keyboard_device_data.timer] mov eax, [edi+keyboard_device_data.timer]
test eax, eax test eax, eax
jz @f jz @f
stdcall CancelTimerHS, eax invoke CancelTimerHS, eax
mov [edi+keyboard_device_data.timer], 0 mov [edi+keyboard_device_data.timer], 0
@@: @@:
pop ecx pop ecx
@ -321,10 +321,10 @@ end if
jnc @f jnc @f
push ecx push ecx
mov ecx, 0xE0 mov ecx, 0xE0
call SetKeyboardData invoke SetKeyboardData
pop ecx pop ecx
@@: @@:
call SetKeyboardData invoke SetKeyboardData
ret ret
endp endp
@ -359,7 +359,7 @@ virtual at esp
.device_data dd ? .device_data dd ?
end virtual end virtual
mov eax, [.device_data] mov eax, [.device_data]
call Kfree invoke Kfree
ret 4 ret 4
endp endp
@ -392,7 +392,7 @@ endl
add eax, 8 + 3 add eax, 8 + 3
and eax, not 3 and eax, not 3
push eax push eax
call Kmalloc invoke Kmalloc
pop ecx pop ecx
test eax, eax test eax, eax
jz .nothing jz .nothing
@ -444,14 +444,14 @@ endl
or edx, [ebx+usb_device_data.interface_number] or edx, [ebx+usb_device_data.interface_number]
mov [eax+4], edx mov [eax+4], edx
; 8. Submit output control request. ; 8. Submit output control request.
stdcall USBControlTransferAsync, [ebx+usb_device_data.configpipe], \ invoke USBControlTransferAsync, [ebx+usb_device_data.configpipe], \
eax, edi, [size], after_set_keyboard_lights, ebx, 0 eax, edi, [size], after_set_keyboard_lights, ebx, 0
; If failed, free the buffer now. ; If failed, free the buffer now.
; If succeeded, the callback will free the buffer. ; If succeeded, the callback will free the buffer.
test eax, eax test eax, eax
jnz .nothing jnz .nothing
lea eax, [edi-8] lea eax, [edi-8]
call Kfree invoke Kfree
.nothing: .nothing:
ret ret
endp endp
@ -470,6 +470,6 @@ end virtual
; Ignore status, just free the buffer allocated by SetKeyboardLights. ; Ignore status, just free the buffer allocated by SetKeyboardLights.
mov eax, [.buffer] mov eax, [.buffer]
sub eax, 8 sub eax, 8
call Kfree invoke Kfree
ret 20 ret 20
endp endp

View File

@ -34,7 +34,7 @@ ends
proc mouse_driver_add_device proc mouse_driver_add_device
; Just allocate memory; no initialization needed. ; Just allocate memory; no initialization needed.
movi eax, sizeof.mouse_device_data movi eax, sizeof.mouse_device_data
call Kmalloc invoke Kmalloc
ret ret
endp endp
@ -44,7 +44,7 @@ endp
proc mouse_driver_disconnect proc mouse_driver_disconnect
; Free the allocated memory. ; Free the allocated memory.
mov eax, edi mov eax, edi
call Kfree invoke Kfree
ret ret
endp endp
@ -153,7 +153,7 @@ endp
; in: edi -> mouse_device_data (pointer returned from mouse_driver_add_device) ; in: edi -> mouse_device_data (pointer returned from mouse_driver_add_device)
proc mouse_driver_end_packet proc mouse_driver_end_packet
; Call the kernel, passing collected state. ; Call the kernel, passing collected state.
stdcall SetMouseData, \ invoke SetMouseData, \
[edi+mouse_device_data.buttons], \ [edi+mouse_device_data.buttons], \
[edi+mouse_device_data.dx], \ [edi+mouse_device_data.dx], \
[edi+mouse_device_data.dy], \ [edi+mouse_device_data.dy], \

View File

@ -353,7 +353,7 @@ parse_descr_label:
mov [last_collection], eax mov [last_collection], eax
; 1b. Allocate state of global items. ; 1b. Allocate state of global items.
movi eax, sizeof.global_items movi eax, sizeof.global_items
call Kmalloc invoke Kmalloc
test eax, eax test eax, eax
jz .memory_error jz .memory_error
; 1c. Zero-initialize it and move pointer to edi. ; 1c. Zero-initialize it and move pointer to edi.
@ -373,7 +373,7 @@ parse_descr_label:
test eax, eax test eax, eax
jz @f jz @f
push [eax+usage_list_item.next] push [eax+usage_list_item.next]
call Kfree invoke Kfree
pop eax pop eax
jmp @b jmp @b
@@: @@:
@ -496,7 +496,7 @@ end if
cmp [ebx+report_set.data], 0 cmp [ebx+report_set.data], 0
jnz .invalid_report jnz .invalid_report
mov eax, 256*4 mov eax, 256*4
call Kmalloc invoke Kmalloc
test eax, eax test eax, eax
jz .memory_error jz .memory_error
mov [ebx+report_set.data], eax mov [ebx+report_set.data], eax
@ -521,7 +521,7 @@ end if
jnz .report_allocated jnz .report_allocated
; 7b. Allocate. ; 7b. Allocate.
movi eax, sizeof.report movi eax, sizeof.report
call Kmalloc invoke Kmalloc
test eax, eax test eax, eax
jz .memory_error jz .memory_error
; 7c. Initialize. ; 7c. Initialize.
@ -568,7 +568,7 @@ end if
mov edx, [num_usage_ranges] mov edx, [num_usage_ranges]
lea eax, [eax+edx*sizeof.usage_range+4] lea eax, [eax+edx*sizeof.usage_range+4]
@@: @@:
call Kmalloc invoke Kmalloc
pop edx pop edx
test eax, eax test eax, eax
jz .memory_error jz .memory_error
@ -688,7 +688,7 @@ end if
; allocate, zero-initialize, update parent, if there is one, ; allocate, zero-initialize, update parent, if there is one,
; make it current. ; make it current.
movi eax, sizeof.collection movi eax, sizeof.collection
call Kmalloc invoke Kmalloc
test eax, eax test eax, eax
jz .memory_error jz .memory_error
push eax edi push eax edi
@ -817,7 +817,7 @@ end if
; For Push, allocate new global_items structure, ; For Push, allocate new global_items structure,
; initialize from the current one and make it current. ; initialize from the current one and make it current.
movi eax, sizeof.global_items movi eax, sizeof.global_items
call Kmalloc invoke Kmalloc
test eax, eax test eax, eax
jz .memory_error jz .memory_error
push esi eax push esi eax
@ -835,7 +835,7 @@ end if
jz .invalid_report jz .invalid_report
push eax push eax
xchg eax, edi xchg eax, edi
call Kfree invoke Kfree
pop edi pop edi
jmp .item_parsed jmp .item_parsed
; -------------------------------- Local items -------------------------------- ; -------------------------------- Local items --------------------------------
@ -862,7 +862,7 @@ end if
push 1 push 1
.new_usage: .new_usage:
movi eax, sizeof.usage_list_item movi eax, sizeof.usage_list_item
call Kmalloc invoke Kmalloc
pop edx pop edx
test eax, eax test eax, eax
jz .memory_error jz .memory_error
@ -912,7 +912,7 @@ end if
inc [delimiter_depth] inc [delimiter_depth]
push esi push esi
mov esi, delimiter_note mov esi, delimiter_note
call SysMsgBoardStr invoke SysMsgBoardStr
pop esi pop esi
jmp .item_parsed jmp .item_parsed
.delimiter.close: .delimiter.close:
@ -954,14 +954,14 @@ end if
.memory_error: .memory_error:
mov esi, nomemory_msg mov esi, nomemory_msg
.end_str: .end_str:
call SysMsgBoardStr invoke SysMsgBoardStr
.end: .end:
; Free all global_items structures. ; Free all global_items structures.
test edi, edi test edi, edi
jz @f jz @f
push [edi+global_items.next] push [edi+global_items.next]
xchg eax, edi xchg eax, edi
call Kfree invoke Kfree
pop edi pop edi
jmp .end jmp .end
@@: @@:
@ -971,7 +971,7 @@ end if
test eax, eax test eax, eax
jz @f jz @f
push [eax+usage_list_item.next] push [eax+usage_list_item.next]
call Kfree invoke Kfree
pop eax pop eax
jmp @b jmp @b
@@: @@:
@ -1116,7 +1116,7 @@ macro hid_cleanup
mov eax, [esi+collection.parent] mov eax, [esi+collection.parent]
@@: @@:
xchg eax, esi xchg eax, esi
call Kfree invoke Kfree
jmp .free_collections jmp .free_collections
.collections_done: .collections_done:
; 3. Free all three report sets. ; 3. Free all three report sets.
@ -1136,19 +1136,19 @@ macro hid_cleanup
test eax, eax test eax, eax
jz .field_done jz .field_done
push [eax+report_field_group.next] push [eax+report_field_group.next]
call Kfree invoke Kfree
pop eax pop eax
jmp .field_loop jmp .field_loop
.field_done: .field_done:
mov eax, [edi+report.next] mov eax, [edi+report.next]
xchg eax, edi xchg eax, edi
call Kfree invoke Kfree
jmp .report_loop jmp .report_loop
.report_done: .report_done:
cmp [esi+report_set.numbered], 0 cmp [esi+report_set.numbered], 0
jz @f jz @f
mov eax, [esi+report_set.data] mov eax, [esi+report_set.data]
call Kfree invoke Kfree
@@: @@:
add esi, sizeof.report_set add esi, sizeof.report_set
dec dword [esp] dec dword [esp]

View File

@ -1,5 +1,6 @@
; standard driver stuff ; standard driver stuff; version of driver model = 5
format MS COFF format PE DLL native 0.05
entry START
DEBUG = 1 DEBUG = 1
@ -7,14 +8,8 @@ DEBUG = 1
__DEBUG__ = 1 __DEBUG__ = 1
__DEBUG_LEVEL__ = 1 __DEBUG_LEVEL__ = 1
include '../proc32.inc'
include '../imports.inc'
include '../fdo.inc'
include '../../struct.inc' include '../../struct.inc'
public START
public version
; Compile-time settings. ; Compile-time settings.
; If set, the code will dump all descriptors as they are read to the debug board. ; If set, the code will dump all descriptors as they are read to the debug board.
USB_DUMP_DESCRIPTORS = 1 USB_DUMP_DESCRIPTORS = 1
@ -103,12 +98,17 @@ input_buffer dd ? ; buffer for input transfers
control rb 8 ; control packet to device control rb 8 ; control packet to device
ends ends
section '.flat' code readable align 16 section '.flat' code readable writable executable
include '../../macros.inc'
include '../../proc32.inc'
include '../../peimport.inc'
include '../../fdo.inc'
; The start procedure. ; The start procedure.
proc START proc START
virtual at esp virtual at esp
dd ? ; return address dd ? ; return address
.reason dd ? .reason dd ?
.cmdline dd ?
end virtual end virtual
; 1. Test whether the procedure is called with the argument DRV_ENTRY. ; 1. Test whether the procedure is called with the argument DRV_ENTRY.
; If not, return 0. ; If not, return 0.
@ -118,10 +118,10 @@ end virtual
; 2. Register self as a USB driver. ; 2. Register self as a USB driver.
; The name is my_driver = 'usbhid'; IOCTL interface is not supported; ; The name is my_driver = 'usbhid'; IOCTL interface is not supported;
; usb_functions is an offset of a structure with callback functions. ; usb_functions is an offset of a structure with callback functions.
stdcall RegUSBDriver, my_driver, eax, usb_functions invoke RegUSBDriver, my_driver, eax, usb_functions
; 3. Return the returned value of RegUSBDriver. ; 3. Return the returned value of RegUSBDriver.
.nothing: .nothing:
ret 4 ret
endp endp
; This procedure is called when new HID device is detected. ; This procedure is called when new HID device is detected.
@ -138,11 +138,11 @@ end virtual
DEBUGF 1,'K : USB HID device detected\n' DEBUGF 1,'K : USB HID device detected\n'
; 1. Allocate memory for device data. ; 1. Allocate memory for device data.
movi eax, sizeof.usb_device_data movi eax, sizeof.usb_device_data
call Kmalloc invoke Kmalloc
test eax, eax test eax, eax
jnz @f jnz @f
mov esi, nomemory_msg mov esi, nomemory_msg
call SysMsgBoardStr invoke SysMsgBoardStr
jmp .return0 jmp .return0
@@: @@:
; zero-initialize it ; zero-initialize it
@ -215,11 +215,11 @@ end virtual
.cfgerror: .cfgerror:
; 6a. Print a message. ; 6a. Print a message.
mov esi, invalid_config_descr_msg mov esi, invalid_config_descr_msg
call SysMsgBoardStr invoke SysMsgBoardStr
; 6b. Free memory allocated for device data. ; 6b. Free memory allocated for device data.
.free: .free:
xchg eax, ebx xchg eax, ebx
call Kfree invoke Kfree
.return0: .return0:
; 6c. Return an error. ; 6c. Return an error.
xor eax, eax xor eax, eax
@ -255,7 +255,7 @@ end virtual
mov eax, [.config_pipe] mov eax, [.config_pipe]
mov [ebx+usb_device_data.configpipe], eax mov [ebx+usb_device_data.configpipe], eax
xor ecx, ecx xor ecx, ecx
stdcall USBControlTransferAsync, eax, edx, ecx, ecx, idle_set, ebx, ecx invoke USBControlTransferAsync, eax, edx, ecx, ecx, idle_set, ebx, ecx
; 7. Return pointer to usb_device_data. ; 7. Return pointer to usb_device_data.
xchg eax, ebx xchg eax, ebx
jmp .nothing jmp .nothing
@ -295,7 +295,7 @@ end virtual
.cfgerror: .cfgerror:
mov esi, invalid_config_descr_msg mov esi, invalid_config_descr_msg
.abort_with_msg: .abort_with_msg:
call SysMsgBoardStr invoke SysMsgBoardStr
jmp .nothing jmp .nothing
.found_report: .found_report:
; 2. Send request for the Report descriptor. ; 2. Send request for the Report descriptor.
@ -304,7 +304,7 @@ end virtual
test eax, eax test eax, eax
jz .cfgerror jz .cfgerror
push eax push eax
call Kmalloc invoke Kmalloc
pop ecx pop ecx
; If failed, say a message and stop initialization. ; If failed, say a message and stop initialization.
mov esi, nomemory_msg mov esi, nomemory_msg
@ -320,13 +320,13 @@ end virtual
(REPORT_DESCR_TYPE shl 24); descriptor type (REPORT_DESCR_TYPE shl 24); descriptor type
mov [edx+4], ax ; Interface number mov [edx+4], ax ; Interface number
mov [edx+6], cx ; descriptor length mov [edx+6], cx ; descriptor length
stdcall USBControlTransferAsync, [ebx+usb_device_data.configpipe], \ invoke USBControlTransferAsync, [ebx+usb_device_data.configpipe], \
edx, esi, ecx, got_report, ebx, 0 edx, esi, ecx, got_report, ebx, 0
; 2c. If failed, free the buffer and stop initialization. ; 2c. If failed, free the buffer and stop initialization.
test eax, eax test eax, eax
jnz .nothing jnz .nothing
xchg eax, esi xchg eax, esi
call Kfree invoke Kfree
.nothing: .nothing:
pop esi ebx ; restore used registers to be stdcall pop esi ebx ; restore used registers to be stdcall
ret 20 ret 20
@ -353,7 +353,7 @@ endl
.generic_fail: .generic_fail:
push esi push esi
mov esi, reportfail mov esi, reportfail
call SysMsgBoardStr invoke SysMsgBoardStr
pop esi pop esi
jmp .exit jmp .exit
.has_something: .has_something:
@ -386,7 +386,7 @@ end if
movzx ecx, [edx+endpoint_descr.bEndpointAddress] movzx ecx, [edx+endpoint_descr.bEndpointAddress]
movzx eax, [edx+endpoint_descr.bInterval] movzx eax, [edx+endpoint_descr.bInterval]
movzx edx, [edx+endpoint_descr.wMaxPacketSize] movzx edx, [edx+endpoint_descr.wMaxPacketSize]
stdcall USBOpenPipe, [ebx+usb_device_data.configpipe], ecx, edx, INTERRUPT_PIPE, eax invoke USBOpenPipe, [ebx+usb_device_data.configpipe], ecx, edx, INTERRUPT_PIPE, eax
test eax, eax test eax, eax
jz got_report.exit jz got_report.exit
mov [ebx+usb_device_data.intpipe], eax mov [ebx+usb_device_data.intpipe], eax
@ -418,11 +418,11 @@ end if
; for extract_field_value. ; for extract_field_value.
add eax, 4+3 add eax, 4+3
and eax, not 3 and eax, not 3
call Kmalloc invoke Kmalloc
test eax, eax test eax, eax
jnz @f jnz @f
mov esi, nomemory_msg mov esi, nomemory_msg
call SysMsgBoardStr invoke SysMsgBoardStr
jmp got_report.exit jmp got_report.exit
@@: @@:
mov [ebx+usb_device_data.input_buffer], eax mov [ebx+usb_device_data.input_buffer], eax
@ -430,7 +430,7 @@ end if
call ask_for_input call ask_for_input
got_report.exit: got_report.exit:
mov eax, [buffer] mov eax, [buffer]
call Kfree invoke Kfree
ret ret
endp endp
@ -439,7 +439,7 @@ endp
proc ask_for_input proc ask_for_input
; just call USBNormalTransferAsync with correct parameters, ; just call USBNormalTransferAsync with correct parameters,
; allow short packets ; allow short packets
stdcall USBNormalTransferAsync, \ invoke USBNormalTransferAsync, \
[ebx+usb_device_data.intpipe], \ [ebx+usb_device_data.intpipe], \
[ebx+usb_device_data.input_buffer], \ [ebx+usb_device_data.input_buffer], \
[ebx+usb_device_data.input_transfer_size], \ [ebx+usb_device_data.input_transfer_size], \
@ -492,7 +492,7 @@ endl
ret ret
.fail: .fail:
mov esi, transfer_error_msg mov esi, transfer_error_msg
call SysMsgBoardStr invoke SysMsgBoardStr
jmp .nothing jmp .nothing
endp endp
@ -507,12 +507,12 @@ end virtual
; 1. Say a message. ; 1. Say a message.
mov ebx, [.device_data] mov ebx, [.device_data]
mov esi, disconnectmsg mov esi, disconnectmsg
stdcall SysMsgBoardStr invoke SysMsgBoardStr
; 2. Ask HID layer to release all HID-related resources. ; 2. Ask HID layer to release all HID-related resources.
hid_cleanup hid_cleanup
; 3. Free the device data. ; 3. Free the device data.
xchg eax, ebx xchg eax, ebx
call Kfree invoke Kfree
; 4. Return. ; 4. Return.
.nothing: .nothing:
pop edi esi ebx ; restore used registers to be stdcall pop edi esi ebx ; restore used registers to be stdcall
@ -534,9 +534,7 @@ disconnectmsg db 'K : USB HID device disconnected',13,10,0
invalid_report_msg db 'K : report descriptor is invalid',13,10,0 invalid_report_msg db 'K : report descriptor is invalid',13,10,0
delimiter_note db 'K : note: alternate usage ignored',13,10,0 delimiter_note db 'K : note: alternate usage ignored',13,10,0
; Exported variable: kernel API version.
align 4 align 4
version dd 50005h
; Structure with callback functions. ; Structure with callback functions.
usb_functions: usb_functions:
dd 12 dd 12
@ -549,5 +547,6 @@ include_debug_strings
; Workers data ; Workers data
workers_globals workers_globals
; for uninitialized data align 4
;section '.data' data readable writable align 16 data fixups
end data

View File

@ -1,5 +1,6 @@
; standard driver stuff ; standard driver stuff; version of driver model = 5
format MS COFF format PE DLL native 0.05
entry START
DEBUG = 1 DEBUG = 1
DUMP_PACKETS = 0 DUMP_PACKETS = 0
@ -8,12 +9,7 @@ DUMP_PACKETS = 0
__DEBUG__ = 1 __DEBUG__ = 1
__DEBUG_LEVEL__ = 1 __DEBUG_LEVEL__ = 1
include 'proc32.inc' include '../struct.inc'
include 'imports.inc'
include 'fdo.inc'
public START
public version
; USB constants ; USB constants
DEVICE_DESCR_TYPE = 1 DEVICE_DESCR_TYPE = 1
@ -29,43 +25,37 @@ BULK_PIPE = 2
INTERRUPT_PIPE = 3 INTERRUPT_PIPE = 3
; USB structures ; USB structures
virtual at 0 struct config_descr
config_descr: bLength db ?
.bLength db ? bDescriptorType db ?
.bDescriptorType db ? wTotalLength dw ?
.wTotalLength dw ? bNumInterfaces db ?
.bNumInterfaces db ? bConfigurationValue db ?
.bConfigurationValue db ? iConfiguration db ?
.iConfiguration db ? bmAttributes db ?
.bmAttributes db ? bMaxPower db ?
.bMaxPower db ? ends
.sizeof:
end virtual
virtual at 0 struct interface_descr
interface_descr: bLength db ?
.bLength db ? bDescriptorType db ?
.bDescriptorType db ? bInterfaceNumber db ?
.bInterfaceNumber db ? bAlternateSetting db ?
.bAlternateSetting db ? bNumEndpoints db ?
.bNumEndpoints db ? bInterfaceClass db ?
.bInterfaceClass db ? bInterfaceSubClass db ?
.bInterfaceSubClass db ? bInterfaceProtocol db ?
.bInterfaceProtocol db ? iInterface db ?
.iInterface db ? ends
.sizeof:
end virtual
virtual at 0 struct endpoint_descr
endpoint_descr: bLength db ?
.bLength db ? bDescriptorType db ?
.bDescriptorType db ? bEndpointAddress db ?
.bEndpointAddress db ? bmAttributes db ?
.bmAttributes db ? wMaxPacketSize dw ?
.wMaxPacketSize dw ? bInterval db ?
.bInterval db ? ends
.sizeof:
end virtual
; Mass storage protocol constants, USB layer ; Mass storage protocol constants, USB layer
REQUEST_GETMAXLUN = 0xFE ; get max lun REQUEST_GETMAXLUN = 0xFE ; get max lun
@ -73,38 +63,28 @@ REQUEST_BORESET = 0xFF ; bulk-only reset
; Mass storage protocol structures, USB layer ; Mass storage protocol structures, USB layer
; Sent from host to device in the first stage of an operation. ; Sent from host to device in the first stage of an operation.
struc command_block_wrapper struct command_block_wrapper
{ Signature dd ? ; the constant 'USBC'
.Signature dd ? ; the constant 'USBC' Tag dd ? ; identifies response with request
.Tag dd ? ; identifies response with request Length dd ? ; length of data-transport phase
.Length dd ? ; length of data-transport phase Flags db ? ; one of CBW_FLAG_*
.Flags db ? ; one of CBW_FLAG_*
CBW_FLAG_OUT = 0 CBW_FLAG_OUT = 0
CBW_FLAG_IN = 80h CBW_FLAG_IN = 80h
.LUN db ? ; addressed unit LUN db ? ; addressed unit
.CommandLength db ? ; the length of the following field CommandLength db ? ; the length of the following field
.Command rb 16 Command rb 16
.sizeof: ends
}
virtual at 0
command_block_wrapper command_block_wrapper
end virtual
; Sent from device to host in the last stage of an operation. ; Sent from device to host in the last stage of an operation.
struc command_status_wrapper struct command_status_wrapper
{ Signature dd ? ; the constant 'USBS'
.Signature dd ? ; the constant 'USBS' Tag dd ? ; identifies response with request
.Tag dd ? ; identifies response with request LengthRest dd ? ; .Length - (size of data which were transferred)
.LengthRest dd ? ; .Length - (size of data which were transferred) Status db ? ; one of CSW_STATUS_*
.Status db ? ; one of CSW_STATUS_*
CSW_STATUS_OK = 0 CSW_STATUS_OK = 0
CSW_STATUS_FAIL = 1 CSW_STATUS_FAIL = 1
CSW_STATUS_FATAL = 2 CSW_STATUS_FATAL = 2
.sizeof: ends
}
virtual at 0
command_status_wrapper command_status_wrapper
end virtual
; Constants of SCSI layer ; Constants of SCSI layer
SCSI_REQUEST_SENSE = 3 SCSI_REQUEST_SENSE = 3
@ -133,73 +113,62 @@ SENSE_MISCOMPARE = 14
; Structures of SCSI layer ; Structures of SCSI layer
; Result of SCSI INQUIRY request. ; Result of SCSI INQUIRY request.
struc inquiry_data struct inquiry_data
{ PeripheralDevice db ? ; lower 5 bits are PeripheralDeviceType
.PeripheralDevice db ? ; lower 5 bits are PeripheralDeviceType
; upper 3 bits are PeripheralQualifier ; upper 3 bits are PeripheralQualifier
.RemovableMedium db ? ; upper bit is RemovableMedium RemovableMedium db ? ; upper bit is RemovableMedium
; other bits are for compatibility ; other bits are for compatibility
.Version db ? ; lower 3 bits are ANSI-Approved version Version db ? ; lower 3 bits are ANSI-Approved version
; next 3 bits are ECMA version ; next 3 bits are ECMA version
; upper 2 bits are ISO version ; upper 2 bits are ISO version
.ResponseDataFormat db ? ; lower 4 bits are ResponseDataFormat ResponseDataFormat db ? ; lower 4 bits are ResponseDataFormat
; bit 6 is TrmIOP ; bit 6 is TrmIOP
; bit 7 is AENC ; bit 7 is AENC
.AdditionalLength db ? AdditionalLength db ?
dw ? ; reserved dw ? ; reserved
.Flags db ? Flags db ?
.VendorID rb 8 ; vendor ID, big-endian VendorID rb 8 ; vendor ID, big-endian
.ProductID rb 16 ; product ID, big-endian ProductID rb 16 ; product ID, big-endian
.ProductRevBE dd ? ; product revision, big-endian ProductRevBE dd ? ; product revision, big-endian
.sizeof: ends
}
virtual at 0
inquiry_data inquiry_data
end virtual
struc sense_data struct sense_data
{ ErrorCode db ? ; lower 7 bits are error code:
.ErrorCode db ? ; lower 7 bits are error code:
; 70h = current error, ; 70h = current error,
; 71h = deferred error ; 71h = deferred error
; upper bit is InformationValid ; upper bit is InformationValid
.SegmentNumber db ? ; number of segment descriptor SegmentNumber db ? ; number of segment descriptor
; for commands COPY [+VERIFY], COMPARE ; for commands COPY [+VERIFY], COMPARE
.SenseKey db ? ; bits 0-3 are one of SENSE_* SenseKey db ? ; bits 0-3 are one of SENSE_*
; bit 4 is reserved ; bit 4 is reserved
; bit 5 is IncorrectLengthIndicator ; bit 5 is IncorrectLengthIndicator
; bits 6 and 7 are used by ; bits 6 and 7 are used by
; sequential-access devices ; sequential-access devices
.Information dd ? ; command-specific Information dd ? ; command-specific
.AdditionalLength db ? ; length of data starting here AdditionalLength db ? ; length of data starting here
.CommandInformation dd ? ; command-specific CommandInformation dd ? ; command-specific
.AdditionalSenseCode db ? ; \ more detailed error code AdditionalSenseCode db ? ; \ more detailed error code
.AdditionalSenseQual db ? ; / standard has a large table of them AdditionalSenseQual db ? ; / standard has a large table of them
.FRUCode db ? ; which part of device has failed FRUCode db ? ; which part of device has failed
; (device-specific, not regulated) ; (device-specific, not regulated)
.SenseKeySpecific rb 3 ; depends on SenseKey SenseKeySpecific rb 3 ; depends on SenseKey
.sizeof: ends
}
virtual at 0
sense_data sense_data
end virtual
; Device data ; Device data
; USB Mass storage device has one or more logical units, identified by LUN, ; USB Mass storage device has one or more logical units, identified by LUN,
; logical unit number. The highest value of LUN, that is, number of units ; logical unit number. The highest value of LUN, that is, number of units
; minus 1, can be obtained via control request Get Max LUN. ; minus 1, can be obtained via control request Get Max LUN.
virtual at 0 struct usb_device_data
usb_device_data: ConfigPipe dd ? ; configuration pipe
.ConfigPipe dd ? ; configuration pipe OutPipe dd ? ; pipe for OUT bulk endpoint
.OutPipe dd ? ; pipe for OUT bulk endpoint InPipe dd ? ; pipe for IN bulk endpoint
.InPipe dd ? ; pipe for IN bulk endpoint MaxLUN dd ? ; maximum Logical Unit Number
.MaxLUN dd ? ; maximum Logical Unit Number LogicalDevices dd ? ; pointer to array of usb_unit_data
.LogicalDevices dd ? ; pointer to array of usb_unit_data
; 1 for a connected USB device, 1 for each disk device ; 1 for a connected USB device, 1 for each disk device
; the structure can be freed when .NumReferences decreases to zero ; the structure can be freed when .NumReferences decreases to zero
.NumReferences dd ? ; number of references NumReferences dd ? ; number of references
.ConfigRequest rb 8 ; buffer for configuration requests ConfigRequest rb 8 ; buffer for configuration requests
.LengthRest dd ? ; Length - (size of data which were transferred) LengthRest dd ? ; Length - (size of data which were transferred)
; All requests to a given device are serialized, ; All requests to a given device are serialized,
; only one request to a given device can be processed at a time. ; only one request to a given device can be processed at a time.
; The current request and all pending requests are organized in the following ; The current request and all pending requests are organized in the following
@ -208,46 +177,42 @@ usb_device_data:
; data stage is not tagged (unlike command_*_wrapper), so the only way to know ; data stage is not tagged (unlike command_*_wrapper), so the only way to know
; what request the data are associated with is to guarantee that only one ; what request the data are associated with is to guarantee that only one
; request is processing at the time. ; request is processing at the time.
.RequestsQueue rd 2 RequestsQueue rd 2
.QueueLock rd 3 ; protects .RequestsQueue QueueLock rd 3 ; protects .RequestsQueue
.InquiryData inquiry_data ; information about device InquiryData inquiry_data ; information about device
; data for the current request ; data for the current request
.Command command_block_wrapper Command command_block_wrapper
.DeviceDisconnected db ? DeviceDisconnected db ?
.Status command_status_wrapper Status command_status_wrapper
.Sense sense_data Sense sense_data
.sizeof: ends
end virtual
; Information about one logical device. ; Information about one logical device.
virtual at 0 struct usb_unit_data
usb_unit_data: Parent dd ? ; pointer to parent usb_device_data
.Parent dd ? ; pointer to parent usb_device_data LUN db ? ; index in usb_device_data.LogicalDevices array
.LUN db ? ; index in usb_device_data.LogicalDevices array DiskIndex db ? ; for name "usbhd<index>"
.DiskIndex db ? ; for name "usbhd<index>" MediaPresent db ?
.MediaPresent db ?
db ? ; alignment db ? ; alignment
.DiskDevice dd ? ; handle of disk device or NULL DiskDevice dd ? ; handle of disk device or NULL
.SectorSize dd ? ; sector size SectorSize dd ? ; sector size
; For some devices, the first request to the medium fails with 'unit not ready'. ; For some devices, the first request to the medium fails with 'unit not ready'.
; When the code sees this status, it retries the command several times. ; When the code sees this status, it retries the command several times.
; Two following variables track the retry count and total time for those; ; Two following variables track the retry count and total time for those;
; total time is currently used only for debug output. ; total time is currently used only for debug output.
.UnitReadyAttempts dd ? UnitReadyAttempts dd ?
.TimerTicks dd ? TimerTicks dd ?
.sizeof: ends
end virtual
; This is the structure for items in the queue usb_device_data.RequestsQueue. ; This is the structure for items in the queue usb_device_data.RequestsQueue.
virtual at 0 struct request_queue_item
request_queue_item: Next dd ? ; next item in the queue
.Next dd ? ; next item in the queue Prev dd ? ; prev item in the queue
.Prev dd ? ; prev item in the queue ReqBuilder dd ? ; procedure to fill command_block_wrapper
.ReqBuilder dd ? ; procedure to fill command_block_wrapper Buffer dd ? ; input or output data
.Buffer dd ? ; input or output data
; (length is command_block_wrapper.Length) ; (length is command_block_wrapper.Length)
.Callback dd ? ; procedure to call in the end of transfer Callback dd ? ; procedure to call in the end of transfer
.UserData dd ? ; passed as-is to .Callback UserData dd ? ; passed as-is to .Callback
; There are 3 possible stages of any request, one of them optional: ; There are 3 possible stages of any request, one of them optional:
; command stage (host sends command_block_wrapper to device), ; command stage (host sends command_block_wrapper to device),
; optional data stage, ; optional data stage,
@ -255,16 +220,21 @@ request_queue_item:
; Also, if a request fails, the code queues additional request ; Also, if a request fails, the code queues additional request
; SCSI_REQUEST_SENSE; sense_data from SCSI_REQUEST_SENSE ; SCSI_REQUEST_SENSE; sense_data from SCSI_REQUEST_SENSE
; contains some information about the error. ; contains some information about the error.
.Stage db ? Stage db ?
.sizeof: ends
end virtual
section '.flat' code readable writable executable
include '../proc32.inc'
include '../peimport.inc'
include '../fdo.inc'
include '../macros.inc'
section '.flat' code readable align 16
; The start procedure. ; The start procedure.
proc START proc START
virtual at esp virtual at esp
dd ? ; return address dd ? ; return address
.reason dd ? ; DRV_ENTRY or DRV_EXIT .reason dd ? ; DRV_ENTRY or DRV_EXIT
.cmdline dd ?
end virtual end virtual
; 1. Test whether the procedure is called with the argument DRV_ENTRY. ; 1. Test whether the procedure is called with the argument DRV_ENTRY.
; If not, return 0. ; If not, return 0.
@ -273,14 +243,14 @@ end virtual
jnz .nothing jnz .nothing
; 2. Initialize: we have one global mutex. ; 2. Initialize: we have one global mutex.
mov ecx, free_numbers_lock mov ecx, free_numbers_lock
call MutexInit invoke MutexInit
; 3. Register self as a USB driver. ; 3. Register self as a USB driver.
; The name is my_driver = 'usbstor'; IOCTL interface is not supported; ; The name is my_driver = 'usbstor'; IOCTL interface is not supported;
; usb_functions is an offset of a structure with callback functions. ; usb_functions is an offset of a structure with callback functions.
stdcall RegUSBDriver, my_driver, 0, usb_functions invoke RegUSBDriver, my_driver, 0, usb_functions
; 4. Return the returned value of RegUSBDriver. ; 4. Return the returned value of RegUSBDriver.
.nothing: .nothing:
ret 4 ret
endp endp
; Helper procedures to work with requests queue. ; Helper procedures to work with requests queue.
@ -298,12 +268,12 @@ virtual at esp
.UserData dd ? ; request_queue_item.UserData .UserData dd ? ; request_queue_item.UserData
end virtual end virtual
; 1. Allocate the memory for the request description. ; 1. Allocate the memory for the request description.
movi eax, request_queue_item.sizeof movi eax, sizeof.request_queue_item
call Kmalloc invoke Kmalloc
test eax, eax test eax, eax
jnz @f jnz @f
mov esi, nomemory mov esi, nomemory
call SysMsgBoardStr invoke SysMsgBoardStr
pop esi ebx pop esi ebx
ret 20 ret 20
@@: @@:
@ -322,7 +292,7 @@ end virtual
; 4. Lock the queue. ; 4. Lock the queue.
mov esi, [.device] mov esi, [.device]
lea ecx, [esi+usb_device_data.QueueLock] lea ecx, [esi+usb_device_data.QueueLock]
call MutexLock invoke MutexLock
; 5. Insert the request to the tail of the queue. ; 5. Insert the request to the tail of the queue.
add esi, usb_device_data.RequestsQueue add esi, usb_device_data.RequestsQueue
mov edx, [esi+request_queue_item.Prev] mov edx, [esi+request_queue_item.Prev]
@ -340,7 +310,7 @@ end virtual
call setup_request call setup_request
jmp .nothing jmp .nothing
.unlock: .unlock:
call MutexUnlock invoke MutexUnlock
; 9. Return. ; 9. Return.
.nothing: .nothing:
pop esi ebx pop esi ebx
@ -369,7 +339,7 @@ end if
stdcall [ebx+request_queue_item.Callback], esi, [ebx+request_queue_item.UserData] stdcall [ebx+request_queue_item.Callback], esi, [ebx+request_queue_item.UserData]
; 4. Lock the queue. ; 4. Lock the queue.
lea ecx, [esi+usb_device_data.QueueLock] lea ecx, [esi+usb_device_data.QueueLock]
call MutexLock invoke MutexLock
; 5. Remove the request. ; 5. Remove the request.
lea edx, [esi+usb_device_data.RequestsQueue] lea edx, [esi+usb_device_data.RequestsQueue]
mov eax, [ebx+request_queue_item.Next] mov eax, [ebx+request_queue_item.Next]
@ -378,14 +348,14 @@ end if
; 6. Free the request memory. ; 6. Free the request memory.
push eax edx push eax edx
xchg eax, ebx xchg eax, ebx
call Kfree invoke Kfree
pop edx ebx pop edx ebx
; 7. If there is a next request, start processing. ; 7. If there is a next request, start processing.
cmp ebx, edx cmp ebx, edx
jnz setup_request jnz setup_request
; 8. Unlock the queue and return. ; 8. Unlock the queue and return.
lea ecx, [esi+usb_device_data.QueueLock] lea ecx, [esi+usb_device_data.QueueLock]
call MutexUnlock invoke MutexUnlock
ret ret
endp endp
@ -410,14 +380,14 @@ proc setup_request
lea edx, [esi+usb_device_data.ConfigRequest] lea edx, [esi+usb_device_data.ConfigRequest]
mov word [edx], (REQUEST_BORESET shl 8) + 21h ; class request mov word [edx], (REQUEST_BORESET shl 8) + 21h ; class request
mov word [edx+6], ax ; length = 0 mov word [edx+6], ax ; length = 0
stdcall USBControlTransferAsync, [esi+usb_device_data.ConfigPipe], edx, eax, eax, recovery_callback1, esi, eax invoke USBControlTransferAsync, [esi+usb_device_data.ConfigPipe], edx, eax, eax, recovery_callback1, esi, eax
; 2b. Fail here = fatal error. ; 2b. Fail here = fatal error.
test eax, eax test eax, eax
jz .fatal jz .fatal
; 2c. Otherwise, unlock the queue and return. recovery_callback1 will continue processing. ; 2c. Otherwise, unlock the queue and return. recovery_callback1 will continue processing.
.unlock_return: .unlock_return:
lea ecx, [esi+usb_device_data.QueueLock] lea ecx, [esi+usb_device_data.QueueLock]
call MutexUnlock invoke MutexUnlock
ret ret
.norecovery: .norecovery:
; 3. Send the command. Fail (no memory or device disconnected) = fatal error. ; 3. Send the command. Fail (no memory or device disconnected) = fatal error.
@ -429,7 +399,7 @@ proc setup_request
; 4. Fatal error. Set status = FATAL, unlock the queue, complete the request. ; 4. Fatal error. Set status = FATAL, unlock the queue, complete the request.
mov [esi+usb_device_data.Status.Status], CSW_STATUS_FATAL mov [esi+usb_device_data.Status.Status], CSW_STATUS_FATAL
lea ecx, [esi+usb_device_data.QueueLock] lea ecx, [esi+usb_device_data.QueueLock]
call MutexUnlock invoke MutexUnlock
jmp complete_request jmp complete_request
endp endp
@ -453,11 +423,11 @@ proc request_stage1
if DUMP_PACKETS if DUMP_PACKETS
DEBUGF 1,'K : USBSTOR out:' DEBUGF 1,'K : USBSTOR out:'
mov eax, edx mov eax, edx
mov ecx, command_block_wrapper.sizeof mov ecx, sizeof.command_block_wrapper
call debug_dump call debug_dump
DEBUGF 1,'\n' DEBUGF 1,'\n'
end if end if
stdcall USBNormalTransferAsync, [esi+usb_device_data.OutPipe], edx, command_block_wrapper.sizeof, request_callback1, esi, 0 invoke USBNormalTransferAsync, [esi+usb_device_data.OutPipe], edx, sizeof.command_block_wrapper, request_callback1, esi, 0
test eax, eax test eax, eax
jz .nothing jz .nothing
; 5. If the next stage is data stage in the same direction, enqueue it here. ; 5. If the next stage is data stage in the same direction, enqueue it here.
@ -473,7 +443,7 @@ if DUMP_PACKETS
call debug_dump call debug_dump
DEBUGF 1,'\n' DEBUGF 1,'\n'
end if end if
stdcall USBNormalTransferAsync, [esi+usb_device_data.OutPipe], [edx+request_queue_item.Buffer], [esi+usb_device_data.Command.Length], request_callback2, esi, 0 invoke USBNormalTransferAsync, [esi+usb_device_data.OutPipe], [edx+request_queue_item.Buffer], [esi+usb_device_data.Command.Length], request_callback2, esi, 0
.nothing: .nothing:
ret ret
endp endp
@ -551,7 +521,7 @@ end virtual
cmp [ecx+usb_device_data.Command.Flags], 0 cmp [ecx+usb_device_data.Command.Flags], 0
jns .nothing jns .nothing
; 5. Initiate USB transfer. If this fails, go to the error handler. ; 5. Initiate USB transfer. If this fails, go to the error handler.
stdcall USBNormalTransferAsync, [ecx+usb_device_data.InPipe], [edx+request_queue_item.Buffer], [ecx+usb_device_data.Command.Length], request_callback2, ecx, 0 invoke USBNormalTransferAsync, [ecx+usb_device_data.InPipe], [edx+request_queue_item.Buffer], [ecx+usb_device_data.Command.Length], request_callback2, ecx, 0
test eax, eax test eax, eax
jz .error jz .error
; 6. The status stage goes to the same direction, enqueue it now. ; 6. The status stage goes to the same direction, enqueue it now.
@ -625,7 +595,7 @@ end if
; 4. Initiate USB transfer. If this fails, go to the error handler. ; 4. Initiate USB transfer. If this fails, go to the error handler.
..enqueue_status: ..enqueue_status:
lea edx, [ecx+usb_device_data.Status] lea edx, [ecx+usb_device_data.Status]
stdcall USBNormalTransferAsync, [ecx+usb_device_data.InPipe], edx, command_status_wrapper.sizeof, request_callback3, ecx, 0 invoke USBNormalTransferAsync, [ecx+usb_device_data.InPipe], edx, sizeof.command_status_wrapper, request_callback3, ecx, 0
test eax, eax test eax, eax
jz .error jz .error
.nothing: .nothing:
@ -698,7 +668,7 @@ end if
; 6. Invalid status block. Say error, set status to fatal and complete request. ; 6. Invalid status block. Say error, set status to fatal and complete request.
push esi push esi
mov esi, invresponse mov esi, invresponse
call SysMsgBoardStr invoke SysMsgBoardStr
pop esi pop esi
mov [esi+usb_device_data.Status.Status], CSW_STATUS_FATAL mov [esi+usb_device_data.Status.Status], CSW_STATUS_FATAL
jmp .complete jmp .complete
@ -728,10 +698,10 @@ endp
; edx = first argument = pointer to usb_device_data.Command, ; edx = first argument = pointer to usb_device_data.Command,
; second argument = custom data given to queue_request (ignored). ; second argument = custom data given to queue_request (ignored).
proc request_sense_req proc request_sense_req
mov [edx+command_block_wrapper.Length], sense_data.sizeof mov [edx+command_block_wrapper.Length], sizeof.sense_data
mov [edx+command_block_wrapper.Flags], CBW_FLAG_IN mov [edx+command_block_wrapper.Flags], CBW_FLAG_IN
mov byte [edx+command_block_wrapper.Command+0], SCSI_REQUEST_SENSE mov byte [edx+command_block_wrapper.Command+0], SCSI_REQUEST_SENSE
mov byte [edx+command_block_wrapper.Command+4], sense_data.sizeof mov byte [edx+command_block_wrapper.Command+4], sizeof.sense_data
ret 8 ret 8
endp endp
@ -780,25 +750,25 @@ end virtual
jz .known jz .known
; 1c. If the device is unknown, print a message and go to 11c. ; 1c. If the device is unknown, print a message and go to 11c.
mov esi, unkdevice mov esi, unkdevice
call SysMsgBoardStr invoke SysMsgBoardStr
jmp .nothing jmp .nothing
; 1d. If the device uses known command set, print a message and continue ; 1d. If the device uses known command set, print a message and continue
; configuring. ; configuring.
.known: .known:
push esi push esi
mov esi, okdevice mov esi, okdevice
call SysMsgBoardStr invoke SysMsgBoardStr
pop esi pop esi
; 2. Allocate memory for internal device data. ; 2. Allocate memory for internal device data.
; 2a. Call the kernel. ; 2a. Call the kernel.
mov eax, usb_device_data.sizeof mov eax, sizeof.usb_device_data
call Kmalloc invoke Kmalloc
; 2b. Check return value. ; 2b. Check return value.
test eax, eax test eax, eax
jnz @f jnz @f
; 2c. If failed, say a message and go to 11c. ; 2c. If failed, say a message and go to 11c.
mov esi, nomemory mov esi, nomemory
call SysMsgBoardStr invoke SysMsgBoardStr
jmp .nothing jmp .nothing
@@: @@:
; 2d. If succeeded, zero the contents and continue configuring. ; 2d. If succeeded, zero the contents and continue configuring.
@ -829,7 +799,7 @@ end virtual
mov [eax+request_queue_item.Next], eax mov [eax+request_queue_item.Next], eax
mov [eax+request_queue_item.Prev], eax mov [eax+request_queue_item.Prev], eax
lea ecx, [ebx+usb_device_data.QueueLock] lea ecx, [ebx+usb_device_data.QueueLock]
call MutexInit invoke MutexInit
; Bulk-only mass storage devices use one OUT bulk endpoint for sending ; Bulk-only mass storage devices use one OUT bulk endpoint for sending
; command/data and one IN bulk endpoint for receiving data/status. ; command/data and one IN bulk endpoint for receiving data/status.
; Look for those endpoints. ; Look for those endpoints.
@ -862,9 +832,9 @@ end virtual
jnz .lookep jnz .lookep
; 5. Check that the descriptor contains all required data and all data are ; 5. Check that the descriptor contains all required data and all data are
; readable. The opposite is an error. ; readable. The opposite is an error.
cmp byte [esi+endpoint_descr.bLength], endpoint_descr.sizeof cmp byte [esi+endpoint_descr.bLength], sizeof.endpoint_descr
jb .errorep jb .errorep
lea ecx, [esi+endpoint_descr.sizeof] lea ecx, [esi+sizeof.endpoint_descr]
cmp ecx, edx cmp ecx, edx
ja .errorep ja .errorep
; 6. Check that the endpoint is bulk endpoint. The opposite is an error. ; 6. Check that the endpoint is bulk endpoint. The opposite is an error.
@ -887,7 +857,7 @@ end virtual
movzx edx, [esi+endpoint_descr.wMaxPacketSize] movzx edx, [esi+endpoint_descr.wMaxPacketSize]
movzx eax, [esi+endpoint_descr.bInterval] ; not used for USB1, may be important for USB2 movzx eax, [esi+endpoint_descr.bInterval] ; not used for USB1, may be important for USB2
; 9c. Call the kernel. ; 9c. Call the kernel.
stdcall USBOpenPipe, [ebx+usb_device_data.ConfigPipe], ecx, edx, BULK_PIPE, eax invoke USBOpenPipe, [ebx+usb_device_data.ConfigPipe], ecx, edx, BULK_PIPE, eax
; 9d. Restore registers. ; 9d. Restore registers.
pop edx ecx pop edx ecx
; 9e. Check result. If failed, go to 11b. ; 9e. Check result. If failed, go to 11b.
@ -907,7 +877,7 @@ end virtual
.free: .free:
; 11b. Free the allocated usb_device_data. ; 11b. Free the allocated usb_device_data.
xchg eax, ebx xchg eax, ebx
call Kfree invoke Kfree
.nothing: .nothing:
; 11c. Return an error. ; 11c. Return an error.
xor eax, eax xor eax, eax
@ -922,7 +892,7 @@ end virtual
if DUMP_PACKETS if DUMP_PACKETS
DEBUGF 1,'K : GETMAXLUN: %x %x %x %x %x %x %x %x\n',[eax]:2,[eax+1]:2,[eax+2]:2,[eax+3]:2,[eax+4]:2,[eax+5]:2,[eax+6]:2,[eax+7]:2 DEBUGF 1,'K : GETMAXLUN: %x %x %x %x %x %x %x %x\n',[eax]:2,[eax+1]:2,[eax+2]:2,[eax+3]:2,[eax+4]:2,[eax+5]:2,[eax+6]:2,[eax+7]:2
end if end if
stdcall USBControlTransferAsync, [ebx+usb_device_data.ConfigPipe], eax, ecx, 1, known_lun_callback, ebx, 0 invoke USBControlTransferAsync, [ebx+usb_device_data.ConfigPipe], eax, ecx, 1, known_lun_callback, ebx, 0
; 13. Return with pointer to device data as returned value. ; 13. Return with pointer to device data as returned value.
xchg eax, ebx xchg eax, ebx
.return: .return:
@ -955,15 +925,15 @@ end virtual
mov eax, [ebx+usb_device_data.MaxLUN] mov eax, [ebx+usb_device_data.MaxLUN]
inc eax inc eax
DEBUGF 1,'K : %d logical unit(s)\n',eax DEBUGF 1,'K : %d logical unit(s)\n',eax
imul eax, usb_unit_data.sizeof imul eax, sizeof.usb_unit_data
push ebx push ebx
call Kmalloc invoke Kmalloc
pop ebx pop ebx
; If failed, print a message and do nothing. ; If failed, print a message and do nothing.
test eax, eax test eax, eax
jnz @f jnz @f
mov esi, nomemory mov esi, nomemory
call SysMsgBoardStr invoke SysMsgBoardStr
pop esi ebx pop esi ebx
ret 20 ret 20
@@: @@:
@ -980,12 +950,12 @@ end virtual
mov [esi+usb_unit_data.SectorSize], eax mov [esi+usb_unit_data.SectorSize], eax
mov [esi+usb_unit_data.UnitReadyAttempts], eax mov [esi+usb_unit_data.UnitReadyAttempts], eax
push ecx push ecx
call GetTimerTicks invoke GetTimerTicks
mov [esi+usb_unit_data.TimerTicks], eax mov [esi+usb_unit_data.TimerTicks], eax
stdcall queue_request, ebx, test_unit_ready_req, 0, test_unit_ready_callback, esi stdcall queue_request, ebx, test_unit_ready_req, 0, test_unit_ready_callback, esi
pop ecx pop ecx
inc ecx inc ecx
add esi, usb_unit_data.sizeof add esi, sizeof.usb_unit_data
cmp ecx, [ebx+usb_device_data.MaxLUN] cmp ecx, [ebx+usb_device_data.MaxLUN]
jbe .looplun jbe .looplun
; 4. Return. ; 4. Return.
@ -999,11 +969,11 @@ endp
proc inquiry_req proc inquiry_req
mov eax, [esp+8] mov eax, [esp+8]
mov al, [eax+usb_unit_data.LUN] mov al, [eax+usb_unit_data.LUN]
mov [edx+command_block_wrapper.Length], inquiry_data.sizeof mov [edx+command_block_wrapper.Length], sizeof.inquiry_data
mov [edx+command_block_wrapper.Flags], CBW_FLAG_IN mov [edx+command_block_wrapper.Flags], CBW_FLAG_IN
mov [edx+command_block_wrapper.LUN], al mov [edx+command_block_wrapper.LUN], al
mov byte [edx+command_block_wrapper.Command+0], SCSI_INQUIRY mov byte [edx+command_block_wrapper.Command+0], SCSI_INQUIRY
mov byte [edx+command_block_wrapper.Command+4], inquiry_data.sizeof mov byte [edx+command_block_wrapper.Command+4], sizeof.inquiry_data
ret 8 ret 8
endp endp
@ -1034,7 +1004,7 @@ proc inquiry_callback
movi ebx, 1 movi ebx, 1
mov ecx, new_disk_thread mov ecx, new_disk_thread
; edx = parameter ; edx = parameter
call CreateThread invoke CreateThread
pop edi esi ecx ebx pop edi esi ecx ebx
cmp eax, -1 cmp eax, -1
jnz .nothing jnz .nothing
@ -1046,7 +1016,7 @@ proc inquiry_callback
; 4. The command has failed. Print a message and do nothing. ; 4. The command has failed. Print a message and do nothing.
push esi push esi
mov esi, inquiry_fail mov esi, inquiry_fail
call SysMsgBoardStr invoke SysMsgBoardStr
pop esi pop esi
ret 8 ret 8
endp endp
@ -1079,7 +1049,7 @@ end virtual
; possibly after some repetitions. Print a debug message showing ; possibly after some repetitions. Print a debug message showing
; number and time of those. Remember that media is ready and go to 4. ; number and time of those. Remember that media is ready and go to 4.
DEBUGF 1,'K : media is ready\n' DEBUGF 1,'K : media is ready\n'
call GetTimerTicks invoke GetTimerTicks
sub eax, [edx+usb_unit_data.TimerTicks] sub eax, [edx+usb_unit_data.TimerTicks]
DEBUGF 1,'K : %d attempts, %d ticks\n',[edx+usb_unit_data.UnitReadyAttempts],eax DEBUGF 1,'K : %d attempts, %d ticks\n',[edx+usb_unit_data.UnitReadyAttempts],eax
inc [edx+usb_unit_data.MediaPresent] inc [edx+usb_unit_data.MediaPresent]
@ -1094,7 +1064,7 @@ end virtual
jz @f jz @f
push ecx edx esi push ecx edx esi
movi esi, 10 movi esi, 10
call Sleep invoke Sleep
pop esi edx ecx pop esi edx ecx
stdcall queue_request, ecx, test_unit_ready_req, 0, test_unit_ready_callback, edx stdcall queue_request, ecx, test_unit_ready_req, 0, test_unit_ready_callback, edx
ret 8 ret 8
@ -1120,7 +1090,7 @@ end virtual
; 1. Generate name. ; 1. Generate name.
; 1a. Find a free index. ; 1a. Find a free index.
mov ecx, free_numbers_lock mov ecx, free_numbers_lock
call MutexLock invoke MutexLock
xor eax, eax xor eax, eax
@@: @@:
bsf edx, [free_numbers+eax] bsf edx, [free_numbers+eax]
@ -1128,10 +1098,10 @@ end virtual
add eax, 4 add eax, 4
cmp eax, 4*4 cmp eax, 4*4
jnz @b jnz @b
call MutexUnlock invoke MutexUnlock
push esi push esi
mov esi, noindex mov esi, noindex
call SysMsgBoardStr invoke SysMsgBoardStr
pop esi pop esi
jmp .drop_reference jmp .drop_reference
@@: @@:
@ -1139,7 +1109,7 @@ end virtual
btr [free_numbers+eax], edx btr [free_numbers+eax], edx
lea eax, [eax*8+edx] lea eax, [eax*8+edx]
push eax push eax
call MutexUnlock invoke MutexUnlock
pop eax pop eax
; 1c. Generate a name of the form "usbhd<index>" in the stack. ; 1c. Generate a name of the form "usbhd<index>" in the stack.
mov dword [esp], 'usbh' mov dword [esp], 'usbh'
@ -1166,41 +1136,41 @@ end virtual
; 4. Notify the kernel about a new disk. ; 4. Notify the kernel about a new disk.
; 4a. Add a disk. ; 4a. Add a disk.
; stdcall queue_request, ecx, read_capacity_req, eax, read_capacity_callback, eax ; stdcall queue_request, ecx, read_capacity_req, eax, read_capacity_callback, eax
stdcall DiskAdd, disk_functions, edx, esi, 0 invoke DiskAdd, disk_functions, edx, esi, 0
mov ebx, eax mov ebx, eax
; 4b. If it failed, release the index and do nothing. ; 4b. If it failed, release the index and do nothing.
test eax, eax test eax, eax
jz .free_index jz .free_index
; 4c. Notify the kernel that a media is present. ; 4c. Notify the kernel that a media is present.
stdcall DiskMediaChanged, eax, 1 invoke DiskMediaChanged, eax, 1
; 5. Lock the requests queue, check that device is not disconnected, ; 5. Lock the requests queue, check that device is not disconnected,
; store the disk handle, unlock the requests queue. ; store the disk handle, unlock the requests queue.
mov ecx, [esi+usb_unit_data.Parent] mov ecx, [esi+usb_unit_data.Parent]
add ecx, usb_device_data.QueueLock add ecx, usb_device_data.QueueLock
call MutexLock invoke MutexLock
cmp byte [ecx+usb_device_data.DeviceDisconnected-usb_device_data.QueueLock], 0 cmp byte [ecx+usb_device_data.DeviceDisconnected-usb_device_data.QueueLock], 0
jnz .disconnected jnz .disconnected
mov [esi+usb_unit_data.DiskDevice], ebx mov [esi+usb_unit_data.DiskDevice], ebx
call MutexUnlock invoke MutexUnlock
jmp .exit jmp .exit
.disconnected: .disconnected:
call MutexUnlock invoke MutexUnlock
stdcall disk_close, ebx stdcall disk_close, ebx
jmp .exit jmp .exit
.free_index: .free_index:
mov ecx, free_numbers_lock mov ecx, free_numbers_lock
call MutexLock invoke MutexLock
movzx eax, [esi+usb_unit_data.DiskIndex] movzx eax, [esi+usb_unit_data.DiskIndex]
bts [free_numbers], eax bts [free_numbers], eax
call MutexUnlock invoke MutexUnlock
.drop_reference: .drop_reference:
mov esi, [esi+usb_unit_data.Parent] mov esi, [esi+usb_unit_data.Parent]
lock dec [esi+usb_device_data.NumReferences] lock dec [esi+usb_device_data.NumReferences]
jnz .exit jnz .exit
mov eax, [esi+usb_device_data.LogicalDevices] mov eax, [esi+usb_device_data.LogicalDevices]
call Kfree invoke Kfree
xchg eax, esi xchg eax, esi
call Kfree invoke Kfree
.exit: .exit:
or eax, -1 or eax, -1
int 0x40 int 0x40
@ -1216,7 +1186,7 @@ virtual at esp
end virtual end virtual
; 1. Say a message. ; 1. Say a message.
mov esi, disconnectmsg mov esi, disconnectmsg
call SysMsgBoardStr invoke SysMsgBoardStr
; 2. Lock the requests queue, set .DeviceDisconnected to 1, ; 2. Lock the requests queue, set .DeviceDisconnected to 1,
; unlock the requests queue. ; unlock the requests queue.
; Locking is required for synchronization with queue_request: ; Locking is required for synchronization with queue_request:
@ -1229,9 +1199,9 @@ end virtual
; then queue_request tries to use them. ; then queue_request tries to use them.
mov esi, [.device] mov esi, [.device]
lea ecx, [esi+usb_device_data.QueueLock] lea ecx, [esi+usb_device_data.QueueLock]
call MutexLock invoke MutexLock
mov [esi+usb_device_data.DeviceDisconnected], 1 mov [esi+usb_device_data.DeviceDisconnected], 1
call MutexUnlock invoke MutexUnlock
; 3. Drop one reference to the structure and check whether ; 3. Drop one reference to the structure and check whether
; that was the last reference. ; that was the last reference.
lock dec [esi+usb_device_data.NumReferences] lock dec [esi+usb_device_data.NumReferences]
@ -1247,9 +1217,9 @@ end virtual
mov eax, [esi+usb_unit_data.DiskDevice] mov eax, [esi+usb_unit_data.DiskDevice]
test eax, eax test eax, eax
jz @f jz @f
stdcall DiskDel, eax invoke DiskDel, eax
@@: @@:
add esi, usb_unit_data.sizeof add esi, sizeof.usb_unit_data
dec ebx dec ebx
jnz .diskdel jnz .diskdel
; In this case, some operations with those disks are still possible, ; In this case, some operations with those disks are still possible,
@ -1262,10 +1232,10 @@ end virtual
mov eax, [esi+usb_device_data.LogicalDevices] mov eax, [esi+usb_device_data.LogicalDevices]
test eax, eax test eax, eax
jz @f jz @f
call Kfree invoke Kfree
@@: @@:
xchg eax, esi xchg eax, esi
call Kfree invoke Kfree
jmp .return jmp .return
endp endp
@ -1286,17 +1256,17 @@ virtual at esp
end virtual end virtual
mov esi, [.userdata] mov esi, [.userdata]
mov ecx, free_numbers_lock mov ecx, free_numbers_lock
call MutexLock invoke MutexLock
movzx eax, [esi+usb_unit_data.DiskIndex] movzx eax, [esi+usb_unit_data.DiskIndex]
bts [free_numbers], eax bts [free_numbers], eax
call MutexUnlock invoke MutexUnlock
mov esi, [esi+usb_unit_data.Parent] mov esi, [esi+usb_unit_data.Parent]
lock dec [esi+usb_device_data.NumReferences] lock dec [esi+usb_device_data.NumReferences]
jnz .nothing jnz .nothing
mov eax, [esi+usb_device_data.LogicalDevices] mov eax, [esi+usb_device_data.LogicalDevices]
call Kfree invoke Kfree
xchg eax, esi xchg eax, esi
call Kfree invoke Kfree
.nothing: .nothing:
pop esi ebx pop esi ebx
ret 4 ret 4
@ -1308,7 +1278,7 @@ proc disk_querymedia stdcall uses ebx esi edi, \
; 1. Create event for waiting. ; 1. Create event for waiting.
xor esi, esi xor esi, esi
xor ecx, ecx xor ecx, ecx
call CreateEvent invoke CreateEvent
test eax, eax test eax, eax
jz .generic_fail jz .generic_fail
push eax push eax
@ -1340,7 +1310,7 @@ end virtual
; 3. Wait for event. This destroys it. ; 3. Wait for event. This destroys it.
mov eax, [.event] mov eax, [.event]
mov ebx, [.event_code] mov ebx, [.event_code]
call WaitEvent invoke WaitEvent
; 4. Get the status and results. ; 4. Get the status and results.
pop ecx pop ecx
bswap ecx ; .LastLBA bswap ecx ; .LastLBA
@ -1403,7 +1373,7 @@ proc read_capacity_callback
mov ebx, [ecx+disk_querymedia.event_code-disk_querymedia.locals] mov ebx, [ecx+disk_querymedia.event_code-disk_querymedia.locals]
xor edx, edx xor edx, edx
xor esi, esi xor esi, esi
call RaiseEvent invoke RaiseEvent
pop edi esi ebx pop edi esi ebx
ret 8 ret 8
endp endp
@ -1443,7 +1413,7 @@ max_sectors_at_time = 0xFFFF
; 4. Create event for waiting. ; 4. Create event for waiting.
xor esi, esi xor esi, esi
xor ecx, ecx xor ecx, ecx
call CreateEvent invoke CreateEvent
test eax, eax test eax, eax
jz .generic_fail jz .generic_fail
push eax ; .event push eax ; .event
@ -1476,7 +1446,7 @@ end virtual
; 6. Wait for event. This destroys it. ; 6. Wait for event. This destroys it.
mov eax, [.event] mov eax, [.event]
mov ebx, [.event_code] mov ebx, [.event_code]
call WaitEvent invoke WaitEvent
; 7. Get the status. If the operation has failed, abort. ; 7. Get the status. If the operation has failed, abort.
pop eax ; .status pop eax ; .status
pop ecx ecx ; cleanup .event_code, .event pop ecx ecx ; cleanup .event_code, .event
@ -1579,7 +1549,7 @@ end virtual
mov ebx, [esi+disk_read_write.event_code-disk_read_write.locals] mov ebx, [esi+disk_read_write.event_code-disk_read_write.locals]
xor edx, edx xor edx, edx
xor esi, esi xor esi, esi
call RaiseEvent invoke RaiseEvent
; 6. Return. ; 6. Return.
pop edi esi ebx pop edi esi ebx
ret 8 ret 8
@ -1599,9 +1569,7 @@ inquiry_fail db 'K : INQUIRY command failed',13,10,0
;read_fail db 'K : READ command failed',13,10,0 ;read_fail db 'K : READ command failed',13,10,0
noindex db 'K : failed to generate disk name',13,10,0 noindex db 'K : failed to generate disk name',13,10,0
; Exported variable: kernel API version.
align 4 align 4
version dd 50005h
; Structure with callback functions. ; Structure with callback functions.
usb_functions: usb_functions:
dd usb_functions_end - usb_functions dd usb_functions_end - usb_functions
@ -1620,12 +1588,12 @@ disk_functions:
dd 0 ; adjust_cache_size: use default cache dd 0 ; adjust_cache_size: use default cache
disk_functions_end: disk_functions_end:
data fixups
end data
free_numbers_lock rd 3 free_numbers_lock rd 3
; 128 devices should be enough for everybody ; 128 devices should be enough for everybody
free_numbers dd -1, -1, -1, -1 free_numbers dd -1, -1, -1, -1
; for DEBUGF macro ; for DEBUGF macro
include_debug_strings include_debug_strings
; for uninitialized data
section '.data' data readable writable align 16