Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc92660b81 | ||
|
|
14977ed33f | ||
|
|
5234aadac8 |
+249
-24
@@ -167,6 +167,8 @@ LogicalDevices dd ? ; pointer to array of usb_unit_data
|
||||
; 1 for a connected USB device, 1 for each disk device
|
||||
; the structure can be freed when .NumReferences decreases to zero
|
||||
NumReferences dd ? ; number of references
|
||||
PollNext dd ?
|
||||
PollPrev dd ?
|
||||
ConfigRequest rb 8 ; buffer for configuration requests
|
||||
LengthRest dd ? ; Length - (size of data which were transferred)
|
||||
; All requests to a given device are serialized,
|
||||
@@ -193,7 +195,7 @@ Parent dd ? ; pointer to parent usb_device_data
|
||||
LUN db ? ; index in usb_device_data.LogicalDevices array
|
||||
DiskIndex db ? ; for name "usbhd<index>"
|
||||
MediaPresent db ?
|
||||
db ? ; alignment
|
||||
Polled db ?
|
||||
DiskDevice dd ? ; handle of disk device or NULL
|
||||
SectorSize dd ? ; sector size
|
||||
; For some devices, the first request to the medium fails with 'unit not ready'.
|
||||
@@ -248,6 +250,20 @@ end virtual
|
||||
; The name is my_driver = 'usbstor'; IOCTL interface is not supported;
|
||||
; usb_functions is an offset of a structure with callback functions.
|
||||
invoke RegUSBDriver, my_driver, 0, usb_functions
|
||||
test eax, eax
|
||||
jz .nothing
|
||||
push eax ebx
|
||||
mov ecx, poll_lock
|
||||
invoke MutexInit
|
||||
mov [poll_head], poll_list
|
||||
mov [poll_head+4], poll_list
|
||||
movi ebx, 1
|
||||
mov ecx, poll_thread
|
||||
xor edx, edx
|
||||
invoke CreateThread
|
||||
cmp eax, -1
|
||||
setnz [poll_running]
|
||||
pop ebx eax
|
||||
; 4. Return the returned value of RegUSBDriver.
|
||||
.nothing:
|
||||
ret
|
||||
@@ -324,6 +340,9 @@ endp
|
||||
proc complete_request
|
||||
; 1. Print common debug messages on fails.
|
||||
if DEBUG
|
||||
mov ebx, [esi+usb_device_data.RequestsQueue+request_queue_item.Next]
|
||||
cmp [ebx+request_queue_item.Callback], poll_tur_callback
|
||||
jz .normal
|
||||
cmp [esi+usb_device_data.Status.Status], CSW_STATUS_FAIL
|
||||
jb .normal
|
||||
jz .fail
|
||||
@@ -1293,6 +1312,7 @@ end virtual
|
||||
mov [esi+usb_unit_data.LUN], cl
|
||||
xor eax, eax
|
||||
mov [esi+usb_unit_data.MediaPresent], al
|
||||
mov [esi+usb_unit_data.Polled], al
|
||||
mov [esi+usb_unit_data.DiskDevice], eax
|
||||
mov [esi+usb_unit_data.SectorSize], eax
|
||||
mov [esi+usb_unit_data.UnitReadyAttempts], eax
|
||||
@@ -1305,6 +1325,19 @@ end virtual
|
||||
add esi, sizeof.usb_unit_data
|
||||
cmp ecx, [ebx+usb_device_data.MaxLUN]
|
||||
jbe .looplun
|
||||
cmp [poll_running], 0
|
||||
jz @f
|
||||
lock inc [ebx+usb_device_data.NumReferences]
|
||||
mov ecx, poll_lock
|
||||
invoke MutexLock
|
||||
mov eax, [poll_head+4]
|
||||
mov [ebx+usb_device_data.PollNext], poll_list
|
||||
mov [ebx+usb_device_data.PollPrev], eax
|
||||
mov [eax+usb_device_data.PollNext], ebx
|
||||
mov [poll_head+4], ebx
|
||||
mov ecx, poll_lock
|
||||
invoke MutexUnlock
|
||||
@@:
|
||||
; 4. Return.
|
||||
pop esi ebx
|
||||
ret 20
|
||||
@@ -1338,11 +1371,14 @@ proc inquiry_callback
|
||||
test al, al
|
||||
jnz .nothing
|
||||
DEBUGF 1,'K : direct-access mass storage device detected\n'
|
||||
; Units that report 'medium not present' (the empty card slot of an LTE
|
||||
; modem or card reader) are not registered: the kernel has no media
|
||||
; change detection, so such a disk would only sit dead in the file
|
||||
; managers. Replugging the device after inserting a card registers it.
|
||||
mov edx, [esp+8]
|
||||
cmp [ecx+usb_device_data.MaxLUN], 0
|
||||
jnz .poll
|
||||
cmp [edx+usb_unit_data.MediaPresent], 0
|
||||
jnz @f
|
||||
.poll:
|
||||
mov [edx+usb_unit_data.Polled], 1
|
||||
@@:
|
||||
cmp [edx+usb_unit_data.MediaPresent], 0
|
||||
jnz @f
|
||||
DEBUGF 1,'K : no media, not registering the disk\n'
|
||||
@@ -1435,15 +1471,16 @@ end virtual
|
||||
endp
|
||||
|
||||
; Temporary thread for initial actions with a new disk device.
|
||||
proc new_disk_thread
|
||||
new_disk_thread:
|
||||
stdcall add_disk, [esp]
|
||||
or eax, -1
|
||||
int 0x40
|
||||
|
||||
proc add_disk
|
||||
push ebx esi edi
|
||||
mov esi, [esp+16]
|
||||
sub esp, 32
|
||||
virtual at esp
|
||||
.name rb 32 ; device name
|
||||
.param dd ? ; contents of edx at the moment of int 0x40/eax=51
|
||||
dd ? ; stack segment
|
||||
end virtual
|
||||
; We are ready to notify the kernel about a new disk device.
|
||||
mov esi, [.param]
|
||||
; 1. Generate name.
|
||||
; 1a. Find a free index.
|
||||
mov ecx, free_numbers_lock
|
||||
@@ -1512,7 +1549,7 @@ end virtual
|
||||
jmp .exit
|
||||
.disconnected:
|
||||
invoke MutexUnlock
|
||||
stdcall disk_close, ebx
|
||||
invoke DiskDel, ebx
|
||||
jmp .exit
|
||||
.free_index:
|
||||
mov ecx, free_numbers_lock
|
||||
@@ -1521,6 +1558,7 @@ end virtual
|
||||
bts [free_numbers], eax
|
||||
invoke MutexUnlock
|
||||
.drop_reference:
|
||||
mov [esi+usb_unit_data.MediaPresent], 0
|
||||
mov esi, [esi+usb_unit_data.Parent]
|
||||
lock dec [esi+usb_device_data.NumReferences]
|
||||
jnz .exit
|
||||
@@ -1529,8 +1567,186 @@ end virtual
|
||||
xchg eax, esi
|
||||
invoke Kfree
|
||||
.exit:
|
||||
or eax, -1
|
||||
add esp, 32
|
||||
pop edi esi ebx
|
||||
ret 4
|
||||
endp
|
||||
|
||||
; Every POLL_INTERVAL, check removable units for inserted or removed media.
|
||||
POLL_INTERVAL = 200
|
||||
|
||||
POLL_READY = 0
|
||||
POLL_NO_MEDIA = 1
|
||||
POLL_CHANGED = 2
|
||||
POLL_OTHER = 3
|
||||
|
||||
proc poll_thread
|
||||
.loop:
|
||||
movi eax, 5
|
||||
mov ebx, POLL_INTERVAL
|
||||
int 0x40
|
||||
mov ecx, poll_lock
|
||||
invoke MutexLock
|
||||
mov ebx, [poll_head]
|
||||
.device:
|
||||
cmp ebx, poll_list
|
||||
jz .done
|
||||
mov ecx, poll_lock
|
||||
invoke MutexUnlock
|
||||
cmp [ebx+usb_device_data.DeviceDisconnected], 0
|
||||
jnz .remove
|
||||
mov esi, [ebx+usb_device_data.LogicalDevices]
|
||||
mov edi, [ebx+usb_device_data.MaxLUN]
|
||||
inc edi
|
||||
.unit:
|
||||
cmp [esi+usb_unit_data.Polled], 0
|
||||
jz .next
|
||||
call poll_unit
|
||||
.next:
|
||||
add esi, sizeof.usb_unit_data
|
||||
dec edi
|
||||
jnz .unit
|
||||
mov ecx, poll_lock
|
||||
invoke MutexLock
|
||||
mov ebx, [ebx+usb_device_data.PollNext]
|
||||
jmp .device
|
||||
.remove:
|
||||
mov ecx, poll_lock
|
||||
invoke MutexLock
|
||||
mov eax, [ebx+usb_device_data.PollNext]
|
||||
mov edx, [ebx+usb_device_data.PollPrev]
|
||||
mov [edx+usb_device_data.PollNext], eax
|
||||
mov [eax+usb_device_data.PollPrev], edx
|
||||
push eax
|
||||
lock dec [ebx+usb_device_data.NumReferences]
|
||||
jnz @f
|
||||
mov eax, [ebx+usb_device_data.LogicalDevices]
|
||||
invoke Kfree
|
||||
xchg eax, ebx
|
||||
invoke Kfree
|
||||
@@:
|
||||
pop ebx
|
||||
jmp .device
|
||||
.done:
|
||||
mov ecx, poll_lock
|
||||
invoke MutexUnlock
|
||||
jmp .loop
|
||||
endp
|
||||
|
||||
proc poll_unit
|
||||
push edi
|
||||
stdcall poll_tur, ebx, esi
|
||||
cmp [esi+usb_unit_data.MediaPresent], 0
|
||||
jnz .registered
|
||||
cmp eax, POLL_CHANGED
|
||||
jnz @f
|
||||
stdcall poll_tur, ebx, esi
|
||||
@@:
|
||||
cmp eax, POLL_READY
|
||||
jnz .done
|
||||
movzx eax, [esi+usb_unit_data.LUN]
|
||||
DEBUGF 1,'K : medium inserted, LUN %d\n',eax
|
||||
mov [esi+usb_unit_data.MediaPresent], 1
|
||||
lock inc [ebx+usb_device_data.NumReferences]
|
||||
stdcall add_disk, esi
|
||||
jmp .done
|
||||
.registered:
|
||||
cmp eax, POLL_NO_MEDIA
|
||||
jz .removed
|
||||
cmp eax, POLL_CHANGED
|
||||
jnz .done
|
||||
.removed:
|
||||
lea ecx, [ebx+usb_device_data.QueueLock]
|
||||
invoke MutexLock
|
||||
xor edi, edi
|
||||
cmp [ebx+usb_device_data.DeviceDisconnected], 0
|
||||
jnz @f
|
||||
xchg edi, [esi+usb_unit_data.DiskDevice]
|
||||
@@:
|
||||
lea ecx, [ebx+usb_device_data.QueueLock]
|
||||
invoke MutexUnlock
|
||||
test edi, edi
|
||||
jz .done
|
||||
movzx eax, [esi+usb_unit_data.LUN]
|
||||
DEBUGF 1,'K : medium removed, LUN %d\n',eax
|
||||
invoke DiskDel, edi
|
||||
.done:
|
||||
pop edi
|
||||
ret
|
||||
endp
|
||||
|
||||
proc poll_tur stdcall uses ebx esi edi, device:dword, unit:dword
|
||||
xor esi, esi
|
||||
xor ecx, ecx
|
||||
invoke CreateEvent
|
||||
test eax, eax
|
||||
jz .fail
|
||||
push eax
|
||||
push edx
|
||||
push POLL_OTHER
|
||||
push [unit]
|
||||
mov edx, esp
|
||||
stdcall queue_request, [device], poll_tur_req, 0, poll_tur_callback, edx
|
||||
mov eax, [esp+12]
|
||||
mov ebx, [esp+8]
|
||||
invoke WaitEvent
|
||||
mov eax, [esp+4]
|
||||
add esp, 16
|
||||
ret
|
||||
.fail:
|
||||
movi eax, POLL_OTHER
|
||||
ret
|
||||
endp
|
||||
|
||||
proc poll_tur_req
|
||||
mov eax, [esp+8]
|
||||
mov eax, [eax]
|
||||
mov al, [eax+usb_unit_data.LUN]
|
||||
mov [edx+command_block_wrapper.Length], 0
|
||||
mov [edx+command_block_wrapper.Flags], CBW_FLAG_IN
|
||||
mov [edx+command_block_wrapper.LUN], al
|
||||
mov byte [edx+usb_device_data.Sense.ErrorCode-usb_device_data.Command], 0
|
||||
ret 8
|
||||
endp
|
||||
|
||||
proc poll_tur_callback
|
||||
mov ecx, [esp+4]
|
||||
xor eax, eax
|
||||
mov dl, [ecx+usb_device_data.Status.Status]
|
||||
cmp dl, CSW_STATUS_OK
|
||||
jz .done
|
||||
mov al, POLL_OTHER
|
||||
cmp dl, CSW_STATUS_FAIL
|
||||
jnz .done
|
||||
mov dl, [ecx+usb_device_data.Sense.ErrorCode]
|
||||
and dl, 7Eh
|
||||
cmp dl, 70h
|
||||
jnz .done
|
||||
mov dl, [ecx+usb_device_data.Sense.SenseKey]
|
||||
and dl, 0Fh
|
||||
mov dh, [ecx+usb_device_data.Sense.AdditionalSenseCode]
|
||||
cmp dx, (3Ah shl 8) + SENSE_NOT_READY
|
||||
jz .no_media
|
||||
cmp dx, (3Ah shl 8) + SENSE_UNIT_ATTENTION
|
||||
jnz @f
|
||||
.no_media:
|
||||
mov al, POLL_NO_MEDIA
|
||||
jmp .done
|
||||
@@:
|
||||
cmp dx, (28h shl 8) + SENSE_UNIT_ATTENTION
|
||||
jnz .done
|
||||
mov al, POLL_CHANGED
|
||||
.done:
|
||||
mov ecx, [esp+8]
|
||||
mov [ecx+4], eax
|
||||
push ebx esi edi
|
||||
mov eax, [ecx+12]
|
||||
mov ebx, [ecx+8]
|
||||
xor edx, edx
|
||||
xor esi, esi
|
||||
invoke RaiseEvent
|
||||
pop edi esi ebx
|
||||
ret 8
|
||||
endp
|
||||
|
||||
; This function is called when the device is disconnected.
|
||||
@@ -1559,16 +1775,15 @@ end virtual
|
||||
invoke MutexLock
|
||||
mov [esi+usb_device_data.DeviceDisconnected], 1
|
||||
invoke MutexUnlock
|
||||
; 3. Drop one reference to the structure and check whether
|
||||
; that was the last reference.
|
||||
lock dec [esi+usb_device_data.NumReferences]
|
||||
jz .free
|
||||
; 4. If not, there are some additional references due to disk devices;
|
||||
; notify the kernel that those disks are deleted.
|
||||
; 3. Notify the kernel that all disk devices are deleted.
|
||||
; Note that new disks cannot be added while we are looping here,
|
||||
; because new_disk_thread checks for .DeviceDisconnected.
|
||||
mov eax, [esi+usb_device_data.LogicalDevices]
|
||||
test eax, eax
|
||||
jz .unref
|
||||
push esi
|
||||
mov ebx, [esi+usb_device_data.MaxLUN]
|
||||
mov esi, [esi+usb_device_data.LogicalDevices]
|
||||
mov esi, eax
|
||||
inc ebx
|
||||
.diskdel:
|
||||
mov eax, [esi+usb_unit_data.DiskDevice]
|
||||
@@ -1579,12 +1794,17 @@ end virtual
|
||||
add esi, sizeof.usb_unit_data
|
||||
dec ebx
|
||||
jnz .diskdel
|
||||
; In this case, some operations with those disks are still possible,
|
||||
; so we can't do anything more now. disk_close will take care of the rest.
|
||||
pop esi
|
||||
.unref:
|
||||
; 4. Drop one reference to the structure and check whether
|
||||
; that was the last reference. If not, some operations with the disks
|
||||
; are still possible; disk_close will take care of the rest.
|
||||
lock dec [esi+usb_device_data.NumReferences]
|
||||
jz .free
|
||||
.return:
|
||||
pop esi ebx
|
||||
ret 4
|
||||
; 5. If there are no disk devices, free all resources which were allocated.
|
||||
; 5. If that was the last reference, free all resources which were allocated.
|
||||
.free:
|
||||
mov eax, [esi+usb_device_data.LogicalDevices]
|
||||
test eax, eax
|
||||
@@ -1617,6 +1837,7 @@ end virtual
|
||||
movzx eax, [esi+usb_unit_data.DiskIndex]
|
||||
bts [free_numbers], eax
|
||||
invoke MutexUnlock
|
||||
mov [esi+usb_unit_data.MediaPresent], 0
|
||||
mov esi, [esi+usb_unit_data.Parent]
|
||||
lock dec [esi+usb_device_data.NumReferences]
|
||||
jnz .nothing
|
||||
@@ -2066,6 +2287,10 @@ data fixups
|
||||
end data
|
||||
|
||||
free_numbers_lock rd 3
|
||||
poll_lock rd 3
|
||||
poll_head rd 2
|
||||
poll_list = poll_head - usb_device_data.PollNext
|
||||
poll_running db ?
|
||||
; 128 devices should be enough for everybody
|
||||
free_numbers dd -1, -1, -1, -1
|
||||
|
||||
|
||||
Reference in new issue
Block a user