Subversion Repositories Kolibri OS

Rev

Rev 4549 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4549 Rev 5051
Line 1... Line 1...
1
; standard driver stuff
1
; standard driver stuff; version of driver model = 5
2
format MS COFF
2
format PE DLL native 0.05
-
 
3
entry START
Line 3... Line 4...
3
 
4
 
4
DEBUG = 1
5
DEBUG = 1
Line 5... Line 6...
5
DUMP_PACKETS = 0
6
DUMP_PACKETS = 0
6
 
7
 
7
; this is for DEBUGF macro from 'fdo.inc'
8
; this is for DEBUGF macro from 'fdo.inc'
Line 8... Line -...
8
__DEBUG__ = 1
-
 
9
__DEBUG_LEVEL__ = 1
9
__DEBUG__ = 1
10
 
-
 
11
include 'proc32.inc'
-
 
12
include 'imports.inc'
-
 
13
include 'fdo.inc'
-
 
Line 14... Line 10...
14
 
10
__DEBUG_LEVEL__ = 1
15
public START
11
 
16
public version
12
include '../struct.inc'
17
 
13
 
Line 27... Line 23...
27
ISOCHRONOUS_PIPE = 1
23
ISOCHRONOUS_PIPE = 1
28
BULK_PIPE = 2
24
BULK_PIPE = 2
29
INTERRUPT_PIPE = 3
25
INTERRUPT_PIPE = 3
Line 30... Line 26...
30
 
26
 
31
; USB structures
-
 
32
virtual at 0
27
; USB structures
33
config_descr:
28
struct config_descr
34
.bLength                db      ?
29
bLength                 db      ?
35
.bDescriptorType        db      ?
30
bDescriptorType         db      ?
36
.wTotalLength           dw      ?
31
wTotalLength            dw      ?
37
.bNumInterfaces         db      ?
32
bNumInterfaces          db      ?
38
.bConfigurationValue    db      ?
33
bConfigurationValue     db      ?
39
.iConfiguration         db      ?
34
iConfiguration          db      ?
40
.bmAttributes           db      ?
35
bmAttributes            db      ?
41
.bMaxPower              db      ?
-
 
42
.sizeof:
36
bMaxPower               db      ?
43
end virtual
37
ends
44
 
-
 
45
virtual at 0
38
 
46
interface_descr:
39
struct interface_descr
47
.bLength                db      ?
40
bLength                 db      ?
48
.bDescriptorType        db      ?
41
bDescriptorType         db      ?
49
.bInterfaceNumber       db      ?
42
bInterfaceNumber        db      ?
50
.bAlternateSetting      db      ?
43
bAlternateSetting       db      ?
51
.bNumEndpoints          db      ?
44
bNumEndpoints           db      ?
52
.bInterfaceClass        db      ?
45
bInterfaceClass         db      ?
53
.bInterfaceSubClass     db      ?
46
bInterfaceSubClass      db      ?
54
.bInterfaceProtocol     db      ?
47
bInterfaceProtocol      db      ?
55
.iInterface             db      ?
-
 
56
.sizeof:
48
iInterface              db      ?
57
end virtual
49
ends
58
 
-
 
59
virtual at 0
50
 
60
endpoint_descr:
51
struct endpoint_descr
61
.bLength                db      ?
52
bLength                 db      ?
62
.bDescriptorType        db      ?
53
bDescriptorType         db      ?
63
.bEndpointAddress       db      ?
54
bEndpointAddress        db      ?
64
.bmAttributes           db      ?
55
bmAttributes            db      ?
65
.wMaxPacketSize         dw      ?
56
wMaxPacketSize          dw      ?
66
.bInterval              db      ?
-
 
67
.sizeof:
57
bInterval               db      ?
Line 68... Line 58...
68
end virtual
58
ends
69
 
59
 
70
; Mass storage protocol constants, USB layer
60
; Mass storage protocol constants, USB layer
Line 71... Line 61...
71
REQUEST_GETMAXLUN = 0xFE        ; get max lun
61
REQUEST_GETMAXLUN = 0xFE        ; get max lun
72
REQUEST_BORESET = 0xFF          ; bulk-only reset
62
REQUEST_BORESET = 0xFF          ; bulk-only reset
73
 
63
 
74
; Mass storage protocol structures, USB layer
-
 
75
; Sent from host to device in the first stage of an operation.
64
; Mass storage protocol structures, USB layer
76
struc command_block_wrapper
65
; Sent from host to device in the first stage of an operation.
77
{
66
struct command_block_wrapper
78
.Signature      dd      ?       ; the constant 'USBC'
67
Signature       dd      ?       ; the constant 'USBC'
79
.Tag            dd      ?       ; identifies response with request
68
Tag             dd      ?       ; identifies response with request
80
.Length         dd      ?       ; length of data-transport phase
69
Length          dd      ?       ; length of data-transport phase
81
.Flags          db      ?       ; one of CBW_FLAG_*
70
Flags           db      ?       ; one of CBW_FLAG_*
82
CBW_FLAG_OUT = 0
71
CBW_FLAG_OUT = 0
83
CBW_FLAG_IN = 80h
72
CBW_FLAG_IN = 80h
84
.LUN            db      ?       ; addressed unit
-
 
85
.CommandLength  db      ?       ; the length of the following field
-
 
86
.Command        rb      16
-
 
87
.sizeof:
-
 
88
}
73
LUN             db      ?       ; addressed unit
Line 89... Line 74...
89
virtual at 0
74
CommandLength   db      ?       ; the length of the following field
90
command_block_wrapper   command_block_wrapper
75
Command         rb      16
91
end virtual
-
 
92
 
76
ends
93
; Sent from device to host in the last stage of an operation.
77
 
94
struc command_status_wrapper
78
; Sent from device to host in the last stage of an operation.
95
{
79
struct command_status_wrapper
96
.Signature      dd      ?       ; the constant 'USBS'
80
Signature       dd      ?       ; the constant 'USBS'
97
.Tag            dd      ?       ; identifies response with request
81
Tag             dd      ?       ; identifies response with request
98
.LengthRest     dd      ?       ; .Length - (size of data which were transferred)
82
LengthRest      dd      ?       ; .Length - (size of data which were transferred)
99
.Status         db      ?       ; one of CSW_STATUS_*
-
 
100
CSW_STATUS_OK = 0
-
 
101
CSW_STATUS_FAIL = 1
-
 
102
CSW_STATUS_FATAL = 2
-
 
103
.sizeof:
83
Status          db      ?       ; one of CSW_STATUS_*
Line 104... Line 84...
104
}
84
CSW_STATUS_OK = 0
105
virtual at 0
85
CSW_STATUS_FAIL = 1
106
command_status_wrapper  command_status_wrapper
86
CSW_STATUS_FATAL = 2
107
end virtual
87
ends
Line 131... Line 111...
131
SENSE_MISCOMPARE = 14
111
SENSE_MISCOMPARE = 14
132
; 15 is reserved
112
; 15 is reserved
Line 133... Line 113...
133
 
113
 
134
; Structures of SCSI layer
114
; Structures of SCSI layer
135
; Result of SCSI INQUIRY request.
115
; Result of SCSI INQUIRY request.
136
struc inquiry_data
-
 
137
{
116
struct inquiry_data
138
.PeripheralDevice       db      ?       ; lower 5 bits are PeripheralDeviceType
117
PeripheralDevice        db      ?       ; lower 5 bits are PeripheralDeviceType
139
                                        ; upper 3 bits are PeripheralQualifier
118
                                        ; upper 3 bits are PeripheralQualifier
140
.RemovableMedium        db      ?       ; upper bit is RemovableMedium
119
RemovableMedium         db      ?       ; upper bit is RemovableMedium
141
                                        ; other bits are for compatibility
120
                                        ; other bits are for compatibility
142
.Version                db      ?       ; lower 3 bits are ANSI-Approved version
121
Version                 db      ?       ; lower 3 bits are ANSI-Approved version
143
                                        ; next 3 bits are ECMA version
122
                                        ; next 3 bits are ECMA version
144
                                        ; upper 2 bits are ISO version
123
                                        ; upper 2 bits are ISO version
145
.ResponseDataFormat     db      ?       ; lower 4 bits are ResponseDataFormat
124
ResponseDataFormat      db      ?       ; lower 4 bits are ResponseDataFormat
146
                                        ; bit 6 is TrmIOP
125
                                        ; bit 6 is TrmIOP
147
                                        ; bit 7 is AENC
126
                                        ; bit 7 is AENC
148
.AdditionalLength       db      ?
127
AdditionalLength        db      ?
149
                        dw      ?       ; reserved
128
                        dw      ?       ; reserved
150
.Flags                  db      ?
129
Flags                   db      ?
151
.VendorID               rb      8       ; vendor ID, big-endian
130
VendorID                rb      8       ; vendor ID, big-endian
152
.ProductID              rb      16      ; product ID, big-endian
131
ProductID               rb      16      ; product ID, big-endian
153
.ProductRevBE           dd      ?       ; product revision, big-endian
-
 
154
.sizeof:
-
 
155
}
-
 
156
virtual at 0
-
 
157
inquiry_data inquiry_data
132
ProductRevBE            dd      ?       ; product revision, big-endian
Line 158... Line 133...
158
end virtual
133
ends
159
 
-
 
160
struc sense_data
134
 
161
{
135
struct sense_data
162
.ErrorCode              db      ?       ; lower 7 bits are error code:
136
ErrorCode               db      ?       ; lower 7 bits are error code:
163
                                        ; 70h = current error,
137
                                        ; 70h = current error,
164
                                        ; 71h = deferred error
138
                                        ; 71h = deferred error
165
                                        ; upper bit is InformationValid
139
                                        ; upper bit is InformationValid
166
.SegmentNumber          db      ?       ; number of segment descriptor
140
SegmentNumber           db      ?       ; number of segment descriptor
167
                                        ; for commands COPY [+VERIFY], COMPARE
141
                                        ; for commands COPY [+VERIFY], COMPARE
168
.SenseKey               db      ?       ; bits 0-3 are one of SENSE_*
142
SenseKey                db      ?       ; bits 0-3 are one of SENSE_*
169
                                        ; bit 4 is reserved
143
                                        ; bit 4 is reserved
170
                                        ; bit 5 is IncorrectLengthIndicator
144
                                        ; bit 5 is IncorrectLengthIndicator
171
                                        ; bits 6 and 7 are used by
145
                                        ; bits 6 and 7 are used by
172
                                        ; sequential-access devices
146
                                        ; sequential-access devices
173
.Information            dd      ?       ; command-specific
147
Information             dd      ?       ; command-specific
174
.AdditionalLength       db      ?       ; length of data starting here
148
AdditionalLength        db      ?       ; length of data starting here
175
.CommandInformation     dd      ?       ; command-specific
149
CommandInformation      dd      ?       ; command-specific
176
.AdditionalSenseCode    db      ?       ; \ more detailed error code
150
AdditionalSenseCode     db      ?       ; \ more detailed error code
177
.AdditionalSenseQual    db      ?       ; / standard has a large table of them
151
AdditionalSenseQual     db      ?       ; / standard has a large table of them
178
.FRUCode                db      ?       ; which part of device has failed
152
FRUCode                 db      ?       ; which part of device has failed
179
                                        ; (device-specific, not regulated)
-
 
180
.SenseKeySpecific       rb      3       ; depends on SenseKey
-
 
181
.sizeof:
-
 
182
}
-
 
183
virtual at 0
153
                                        ; (device-specific, not regulated)
Line 184... Line 154...
184
sense_data sense_data
154
SenseKeySpecific        rb      3       ; depends on SenseKey
185
end virtual
155
ends
186
 
156
 
187
; Device data
157
; Device data
188
; USB Mass storage device has one or more logical units, identified by LUN,
-
 
189
; logical unit number. The highest value of LUN, that is, number of units
158
; USB Mass storage device has one or more logical units, identified by LUN,
190
; minus 1, can be obtained via control request Get Max LUN.
159
; logical unit number. The highest value of LUN, that is, number of units
191
virtual at 0
160
; minus 1, can be obtained via control request Get Max LUN.
192
usb_device_data:
161
struct usb_device_data
193
.ConfigPipe             dd      ?       ; configuration pipe
162
ConfigPipe              dd      ?       ; configuration pipe
194
.OutPipe                dd      ?       ; pipe for OUT bulk endpoint
163
OutPipe                 dd      ?       ; pipe for OUT bulk endpoint
195
.InPipe                 dd      ?       ; pipe for IN bulk endpoint
164
InPipe                  dd      ?       ; pipe for IN bulk endpoint
196
.MaxLUN                 dd      ?       ; maximum Logical Unit Number
165
MaxLUN                  dd      ?       ; maximum Logical Unit Number
197
.LogicalDevices         dd      ?       ; pointer to array of usb_unit_data
166
LogicalDevices          dd      ?       ; pointer to array of usb_unit_data
198
; 1 for a connected USB device, 1 for each disk device
167
; 1 for a connected USB device, 1 for each disk device
199
; the structure can be freed when .NumReferences decreases to zero
168
; the structure can be freed when .NumReferences decreases to zero
200
.NumReferences          dd      ?       ; number of references
169
NumReferences           dd      ?       ; number of references
201
.ConfigRequest          rb      8       ; buffer for configuration requests
170
ConfigRequest           rb      8       ; buffer for configuration requests
202
.LengthRest             dd      ?       ; Length - (size of data which were transferred)
171
LengthRest              dd      ?       ; Length - (size of data which were transferred)
203
; All requests to a given device are serialized,
172
; All requests to a given device are serialized,
204
; only one request to a given device can be processed at a time.
173
; only one request to a given device can be processed at a time.
205
; The current request and all pending requests are organized in the following
174
; The current request and all pending requests are organized in the following
206
; queue, the head being the current request.
175
; queue, the head being the current request.
207
; NB: the queue must be device-wide due to the protocol:
176
; NB: the queue must be device-wide due to the protocol:
208
; data stage is not tagged (unlike command_*_wrapper), so the only way to know
177
; data stage is not tagged (unlike command_*_wrapper), so the only way to know
209
; what request the data are associated with is to guarantee that only one
178
; what request the data are associated with is to guarantee that only one
210
; request is processing at the time.
179
; request is processing at the time.
211
.RequestsQueue          rd      2
180
RequestsQueue           rd      2
212
.QueueLock              rd      3       ; protects .RequestsQueue
181
QueueLock               rd      3       ; protects .RequestsQueue
213
.InquiryData            inquiry_data    ; information about device
182
InquiryData             inquiry_data    ; information about device
214
; data for the current request
183
; data for the current request
215
.Command                command_block_wrapper
184
Command                 command_block_wrapper
216
.DeviceDisconnected     db      ?
-
 
217
.Status                 command_status_wrapper
185
DeviceDisconnected      db      ?
Line 218... Line 186...
218
.Sense                  sense_data
186
Status                  command_status_wrapper
219
.sizeof:
-
 
220
end virtual
187
Sense                   sense_data
221
 
188
ends
222
; Information about one logical device.
189
 
223
virtual at 0
190
; Information about one logical device.
224
usb_unit_data:
191
struct usb_unit_data
225
.Parent         dd      ?       ; pointer to parent usb_device_data
192
Parent          dd      ?       ; pointer to parent usb_device_data
226
.LUN            db      ?       ; index in usb_device_data.LogicalDevices array
193
LUN             db      ?       ; index in usb_device_data.LogicalDevices array
227
.DiskIndex      db      ?       ; for name "usbhd"
194
DiskIndex       db      ?       ; for name "usbhd"
228
.MediaPresent   db      ?
195
MediaPresent    db      ?
229
                db      ?       ; alignment
196
                db      ?       ; alignment
230
.DiskDevice     dd      ?       ; handle of disk device or NULL
197
DiskDevice      dd      ?       ; handle of disk device or NULL
231
.SectorSize     dd      ?       ; sector size
198
SectorSize      dd      ?       ; sector size
232
; For some devices, the first request to the medium fails with 'unit not ready'.
199
; For some devices, the first request to the medium fails with 'unit not ready'.
233
; When the code sees this status, it retries the command several times.
200
; When the code sees this status, it retries the command several times.
234
; Two following variables track the retry count and total time for those;
-
 
235
; total time is currently used only for debug output.
201
; Two following variables track the retry count and total time for those;
Line 236... Line 202...
236
.UnitReadyAttempts      dd      ?
202
; total time is currently used only for debug output.
237
.TimerTicks             dd      ?
-
 
238
.sizeof:
203
UnitReadyAttempts       dd      ?
239
end virtual
204
TimerTicks              dd      ?
240
 
205
ends
241
; This is the structure for items in the queue usb_device_data.RequestsQueue.
206
 
242
virtual at 0
207
; This is the structure for items in the queue usb_device_data.RequestsQueue.
243
request_queue_item:
208
struct request_queue_item
244
.Next           dd      ?       ; next item in the queue
209
Next            dd      ?       ; next item in the queue
245
.Prev           dd      ?       ; prev item in the queue
210
Prev            dd      ?       ; prev item in the queue
246
.ReqBuilder     dd      ?       ; procedure to fill command_block_wrapper
211
ReqBuilder      dd      ?       ; procedure to fill command_block_wrapper
247
.Buffer         dd      ?       ; input or output data
212
Buffer          dd      ?       ; input or output data
248
                                ; (length is command_block_wrapper.Length)
213
                                ; (length is command_block_wrapper.Length)
249
.Callback       dd      ?       ; procedure to call in the end of transfer
214
Callback        dd      ?       ; procedure to call in the end of transfer
250
.UserData       dd      ?       ; passed as-is to .Callback
215
UserData        dd      ?       ; passed as-is to .Callback
251
; There are 3 possible stages of any request, one of them optional:
216
; There are 3 possible stages of any request, one of them optional:
252
; command stage (host sends command_block_wrapper to device),
217
; command stage (host sends command_block_wrapper to device),
253
; optional data stage,
218
; optional data stage,
254
; status stage (device sends command_status_wrapper to host).
219
; status stage (device sends command_status_wrapper to host).
-
 
220
; Also, if a request fails, the code queues additional request
-
 
221
; SCSI_REQUEST_SENSE; sense_data from SCSI_REQUEST_SENSE
-
 
222
; contains some information about the error.
255
; Also, if a request fails, the code queues additional request
223
Stage           db      ?
-
 
224
ends
-
 
225
 
Line 256... Line -...
256
; SCSI_REQUEST_SENSE; sense_data from SCSI_REQUEST_SENSE
-
 
257
; contains some information about the error.
226
section '.flat' code readable writable executable
258
.Stage          db      ?
227
include '../proc32.inc'
259
.sizeof:
228
include '../peimport.inc'
260
end virtual
229
include '../fdo.inc'
261
 
230
include '../macros.inc'
-
 
231
 
262
section '.flat' code readable align 16
232
; The start procedure.
263
; The start procedure.
233
proc START
264
proc START
234
virtual at esp
265
virtual at esp
235
        dd      ?       ; return address
266
        dd      ?       ; return address
236
.reason dd      ?       ; DRV_ENTRY or DRV_EXIT
267
.reason dd      ?       ; DRV_ENTRY or DRV_EXIT
237
.cmdline dd     ?
268
end virtual
238
end virtual
269
; 1. Test whether the procedure is called with the argument DRV_ENTRY.
239
; 1. Test whether the procedure is called with the argument DRV_ENTRY.
270
; If not, return 0.
240
; If not, return 0.
271
        xor     eax, eax        ; initialize return value
241
        xor     eax, eax        ; initialize return value
272
        cmp     [.reason], 1    ; compare the argument
242
        cmp     [.reason], 1    ; compare the argument
273
        jnz     .nothing
243
        jnz     .nothing
274
; 2. Initialize: we have one global mutex.
244
; 2. Initialize: we have one global mutex.
275
        mov     ecx, free_numbers_lock
245
        mov     ecx, free_numbers_lock
276
        call    MutexInit
246
        invoke  MutexInit
277
; 3. Register self as a USB driver.
247
; 3. Register self as a USB driver.
278
; The name is my_driver = 'usbstor'; IOCTL interface is not supported;
248
; The name is my_driver = 'usbstor'; IOCTL interface is not supported;
Line 279... Line 249...
279
; usb_functions is an offset of a structure with callback functions.
249
; usb_functions is an offset of a structure with callback functions.
Line 280... Line 250...
280
        stdcall RegUSBDriver, my_driver, 0, usb_functions
250
        invoke  RegUSBDriver, my_driver, 0, usb_functions
Line 296... Line 266...
296
.Buffer         dd      ?       ; request_queue_item.Buffer
266
.Buffer         dd      ?       ; request_queue_item.Buffer
297
.Callback       dd      ?       ; request_queue_item.Callback
267
.Callback       dd      ?       ; request_queue_item.Callback
298
.UserData       dd      ?       ; request_queue_item.UserData
268
.UserData       dd      ?       ; request_queue_item.UserData
299
end virtual
269
end virtual
300
; 1. Allocate the memory for the request description.
270
; 1. Allocate the memory for the request description.
301
        movi    eax, request_queue_item.sizeof
271
        movi    eax, sizeof.request_queue_item
302
        call    Kmalloc
272
        invoke  Kmalloc
303
        test    eax, eax
273
        test    eax, eax
304
        jnz     @f
274
        jnz     @f
305
        mov     esi, nomemory
275
        mov     esi, nomemory
306
        call    SysMsgBoardStr
276
        invoke  SysMsgBoardStr
307
        pop     esi ebx
277
        pop     esi ebx
308
        ret     20
278
        ret     20
309
@@:
279
@@:
310
; 2. Fill user-provided parts of the request description.
280
; 2. Fill user-provided parts of the request description.
311
        push    edi
281
        push    edi
Line 320... Line 290...
320
; 3. Set stage to zero: not started.
290
; 3. Set stage to zero: not started.
321
        mov     [ebx+request_queue_item.Stage], 0
291
        mov     [ebx+request_queue_item.Stage], 0
322
; 4. Lock the queue.
292
; 4. Lock the queue.
323
        mov     esi, [.device]
293
        mov     esi, [.device]
324
        lea     ecx, [esi+usb_device_data.QueueLock]
294
        lea     ecx, [esi+usb_device_data.QueueLock]
325
        call    MutexLock
295
        invoke  MutexLock
326
; 5. Insert the request to the tail of the queue.
296
; 5. Insert the request to the tail of the queue.
327
        add     esi, usb_device_data.RequestsQueue
297
        add     esi, usb_device_data.RequestsQueue
328
        mov     edx, [esi+request_queue_item.Prev]
298
        mov     edx, [esi+request_queue_item.Prev]
329
        mov     [ebx+request_queue_item.Next], esi
299
        mov     [ebx+request_queue_item.Next], esi
330
        mov     [ebx+request_queue_item.Prev], edx
300
        mov     [ebx+request_queue_item.Prev], edx
Line 338... Line 308...
338
; start it.
308
; start it.
339
        sub     esi, usb_device_data.RequestsQueue
309
        sub     esi, usb_device_data.RequestsQueue
340
        call    setup_request
310
        call    setup_request
341
        jmp     .nothing
311
        jmp     .nothing
342
.unlock:
312
.unlock:
343
        call    MutexUnlock
313
        invoke  MutexUnlock
344
; 9. Return.
314
; 9. Return.
345
.nothing:
315
.nothing:
346
        pop     esi ebx
316
        pop     esi ebx
347
        ret     20
317
        ret     20
348
endp
318
endp
Line 367... Line 337...
367
        mov     ebx, [esi+usb_device_data.RequestsQueue+request_queue_item.Next]
337
        mov     ebx, [esi+usb_device_data.RequestsQueue+request_queue_item.Next]
368
; 3. Call the callback.
338
; 3. Call the callback.
369
        stdcall [ebx+request_queue_item.Callback], esi, [ebx+request_queue_item.UserData]
339
        stdcall [ebx+request_queue_item.Callback], esi, [ebx+request_queue_item.UserData]
370
; 4. Lock the queue.
340
; 4. Lock the queue.
371
        lea     ecx, [esi+usb_device_data.QueueLock]
341
        lea     ecx, [esi+usb_device_data.QueueLock]
372
        call    MutexLock
342
        invoke  MutexLock
373
; 5. Remove the request.
343
; 5. Remove the request.
374
        lea     edx, [esi+usb_device_data.RequestsQueue]
344
        lea     edx, [esi+usb_device_data.RequestsQueue]
375
        mov     eax, [ebx+request_queue_item.Next]
345
        mov     eax, [ebx+request_queue_item.Next]
376
        mov     [eax+request_queue_item.Prev], edx
346
        mov     [eax+request_queue_item.Prev], edx
377
        mov     [edx+request_queue_item.Next], eax
347
        mov     [edx+request_queue_item.Next], eax
378
; 6. Free the request memory.
348
; 6. Free the request memory.
379
        push    eax edx
349
        push    eax edx
380
        xchg    eax, ebx
350
        xchg    eax, ebx
381
        call    Kfree
351
        invoke  Kfree
382
        pop     edx ebx
352
        pop     edx ebx
383
; 7. If there is a next request, start processing.
353
; 7. If there is a next request, start processing.
384
        cmp     ebx, edx
354
        cmp     ebx, edx
385
        jnz     setup_request
355
        jnz     setup_request
386
; 8. Unlock the queue and return.
356
; 8. Unlock the queue and return.
387
        lea     ecx, [esi+usb_device_data.QueueLock]
357
        lea     ecx, [esi+usb_device_data.QueueLock]
388
        call    MutexUnlock
358
        invoke  MutexUnlock
389
        ret
359
        ret
390
endp
360
endp
Line 391... Line 361...
391
 
361
 
392
; Start processing the request. Called either by queue_request
362
; Start processing the request. Called either by queue_request
Line 408... Line 378...
408
        jb      .norecovery
378
        jb      .norecovery
409
; 2a. Send Bulk-Only Mass Storage Reset command to config pipe.
379
; 2a. Send Bulk-Only Mass Storage Reset command to config pipe.
410
        lea     edx, [esi+usb_device_data.ConfigRequest]
380
        lea     edx, [esi+usb_device_data.ConfigRequest]
411
        mov     word [edx], (REQUEST_BORESET shl 8) + 21h       ; class request
381
        mov     word [edx], (REQUEST_BORESET shl 8) + 21h       ; class request
412
        mov     word [edx+6], ax        ; length = 0
382
        mov     word [edx+6], ax        ; length = 0
413
        stdcall USBControlTransferAsync, [esi+usb_device_data.ConfigPipe], edx, eax, eax, recovery_callback1, esi, eax
383
        invoke  USBControlTransferAsync, [esi+usb_device_data.ConfigPipe], edx, eax, eax, recovery_callback1, esi, eax
414
; 2b. Fail here = fatal error.
384
; 2b. Fail here = fatal error.
415
        test    eax, eax
385
        test    eax, eax
416
        jz      .fatal
386
        jz      .fatal
417
; 2c. Otherwise, unlock the queue and return. recovery_callback1 will continue processing.
387
; 2c. Otherwise, unlock the queue and return. recovery_callback1 will continue processing.
418
.unlock_return:
388
.unlock_return:
419
        lea     ecx, [esi+usb_device_data.QueueLock]
389
        lea     ecx, [esi+usb_device_data.QueueLock]
420
        call    MutexUnlock
390
        invoke  MutexUnlock
421
        ret
391
        ret
422
.norecovery:
392
.norecovery:
423
; 3. Send the command. Fail (no memory or device disconnected) = fatal error.
393
; 3. Send the command. Fail (no memory or device disconnected) = fatal error.
424
; Otherwise, go to 2c.
394
; Otherwise, go to 2c.
425
        call    request_stage1
395
        call    request_stage1
Line 427... Line 397...
427
        jnz     .unlock_return
397
        jnz     .unlock_return
428
.fatal:
398
.fatal:
429
; 4. Fatal error. Set status = FATAL, unlock the queue, complete the request.
399
; 4. Fatal error. Set status = FATAL, unlock the queue, complete the request.
430
        mov     [esi+usb_device_data.Status.Status], CSW_STATUS_FATAL
400
        mov     [esi+usb_device_data.Status.Status], CSW_STATUS_FATAL
431
        lea     ecx, [esi+usb_device_data.QueueLock]
401
        lea     ecx, [esi+usb_device_data.QueueLock]
432
        call    MutexUnlock
402
        invoke  MutexUnlock
433
        jmp     complete_request
403
        jmp     complete_request
434
endp
404
endp
Line 435... Line 405...
435
 
405
 
436
; Initiate USB transfer for the first stage of a request (send command).
406
; Initiate USB transfer for the first stage of a request (send command).
Line 451... Line 421...
451
; 4. Initiate USB transfer.
421
; 4. Initiate USB transfer.
452
        lea     edx, [esi+usb_device_data.Command]
422
        lea     edx, [esi+usb_device_data.Command]
453
if DUMP_PACKETS
423
if DUMP_PACKETS
454
        DEBUGF 1,'K : USBSTOR out:'
424
        DEBUGF 1,'K : USBSTOR out:'
455
        mov     eax, edx
425
        mov     eax, edx
456
        mov     ecx, command_block_wrapper.sizeof
426
        mov     ecx, sizeof.command_block_wrapper
457
        call    debug_dump
427
        call    debug_dump
458
        DEBUGF 1,'\n'
428
        DEBUGF 1,'\n'
459
end if
429
end if
460
        stdcall USBNormalTransferAsync, [esi+usb_device_data.OutPipe], edx, command_block_wrapper.sizeof, request_callback1, esi, 0
430
        invoke  USBNormalTransferAsync, [esi+usb_device_data.OutPipe], edx, sizeof.command_block_wrapper, request_callback1, esi, 0
461
        test    eax, eax
431
        test    eax, eax
462
        jz      .nothing
432
        jz      .nothing
463
; 5. If the next stage is data stage in the same direction, enqueue it here.
433
; 5. If the next stage is data stage in the same direction, enqueue it here.
464
        cmp     [esi+usb_device_data.Command.Flags], 0
434
        cmp     [esi+usb_device_data.Command.Flags], 0
465
        js      .nothing
435
        js      .nothing
Line 471... Line 441...
471
        mov     eax, [edx+request_queue_item.Buffer]
441
        mov     eax, [edx+request_queue_item.Buffer]
472
        mov     ecx, [esi+usb_device_data.Command.Length]
442
        mov     ecx, [esi+usb_device_data.Command.Length]
473
        call    debug_dump
443
        call    debug_dump
474
        DEBUGF 1,'\n'
444
        DEBUGF 1,'\n'
475
end if
445
end if
476
        stdcall USBNormalTransferAsync, [esi+usb_device_data.OutPipe], [edx+request_queue_item.Buffer], [esi+usb_device_data.Command.Length], request_callback2, esi, 0
446
        invoke  USBNormalTransferAsync, [esi+usb_device_data.OutPipe], [edx+request_queue_item.Buffer], [esi+usb_device_data.Command.Length], request_callback2, esi, 0
477
.nothing:
447
.nothing:
478
        ret
448
        ret
479
endp
449
endp
Line 480... Line 450...
480
 
450
 
Line 549... Line 519...
549
        jz      ..request_get_status
519
        jz      ..request_get_status
550
; 4b. If data were enqueued in the first stage, do nothing, wait for request_callback2.
520
; 4b. If data were enqueued in the first stage, do nothing, wait for request_callback2.
551
        cmp     [ecx+usb_device_data.Command.Flags], 0
521
        cmp     [ecx+usb_device_data.Command.Flags], 0
552
        jns     .nothing
522
        jns     .nothing
553
; 5. Initiate USB transfer. If this fails, go to the error handler.
523
; 5. Initiate USB transfer. If this fails, go to the error handler.
554
        stdcall USBNormalTransferAsync, [ecx+usb_device_data.InPipe], [edx+request_queue_item.Buffer], [ecx+usb_device_data.Command.Length], request_callback2, ecx, 0
524
        invoke  USBNormalTransferAsync, [ecx+usb_device_data.InPipe], [edx+request_queue_item.Buffer], [ecx+usb_device_data.Command.Length], request_callback2, ecx, 0
555
        test    eax, eax
525
        test    eax, eax
556
        jz      .error
526
        jz      .error
557
; 6. The status stage goes to the same direction, enqueue it now.
527
; 6. The status stage goes to the same direction, enqueue it now.
558
        mov     ecx, [.calldata]
528
        mov     ecx, [.calldata]
559
        jmp     ..enqueue_status
529
        jmp     ..enqueue_status
Line 623... Line 593...
623
        mov     edx, [ecx+usb_device_data.RequestsQueue+request_queue_item.Next]
593
        mov     edx, [ecx+usb_device_data.RequestsQueue+request_queue_item.Next]
624
        inc     [edx+request_queue_item.Stage]
594
        inc     [edx+request_queue_item.Stage]
625
; 4. Initiate USB transfer. If this fails, go to the error handler.
595
; 4. Initiate USB transfer. If this fails, go to the error handler.
626
..enqueue_status:
596
..enqueue_status:
627
        lea     edx, [ecx+usb_device_data.Status]
597
        lea     edx, [ecx+usb_device_data.Status]
628
        stdcall USBNormalTransferAsync, [ecx+usb_device_data.InPipe], edx, command_status_wrapper.sizeof, request_callback3, ecx, 0
598
        invoke  USBNormalTransferAsync, [ecx+usb_device_data.InPipe], edx, sizeof.command_status_wrapper, request_callback3, ecx, 0
629
        test    eax, eax
599
        test    eax, eax
630
        jz      .error
600
        jz      .error
631
.nothing:
601
.nothing:
632
        ret     20
602
        ret     20
633
.error:
603
.error:
Line 696... Line 666...
696
        jmp     .complete
666
        jmp     .complete
697
.invalid:
667
.invalid:
698
; 6. Invalid status block. Say error, set status to fatal and complete request.
668
; 6. Invalid status block. Say error, set status to fatal and complete request.
699
        push    esi
669
        push    esi
700
        mov     esi, invresponse
670
        mov     esi, invresponse
701
        call    SysMsgBoardStr
671
        invoke  SysMsgBoardStr
702
        pop     esi
672
        pop     esi
703
        mov     [esi+usb_device_data.Status.Status], CSW_STATUS_FATAL
673
        mov     [esi+usb_device_data.Status.Status], CSW_STATUS_FATAL
704
        jmp     .complete
674
        jmp     .complete
705
.fail:
675
.fail:
706
; 7. The command has failed. 
676
; 7. The command has failed. 
Line 726... Line 696...
726
 
696
 
727
; Builder for SCSI_REQUEST_SENSE request.
697
; Builder for SCSI_REQUEST_SENSE request.
728
; edx = first argument = pointer to usb_device_data.Command,
698
; edx = first argument = pointer to usb_device_data.Command,
729
; second argument = custom data given to queue_request (ignored).
699
; second argument = custom data given to queue_request (ignored).
730
proc request_sense_req
700
proc request_sense_req
731
        mov     [edx+command_block_wrapper.Length], sense_data.sizeof
701
        mov     [edx+command_block_wrapper.Length], sizeof.sense_data
732
        mov     [edx+command_block_wrapper.Flags], CBW_FLAG_IN
702
        mov     [edx+command_block_wrapper.Flags], CBW_FLAG_IN
733
        mov     byte [edx+command_block_wrapper.Command+0], SCSI_REQUEST_SENSE
703
        mov     byte [edx+command_block_wrapper.Command+0], SCSI_REQUEST_SENSE
734
        mov     byte [edx+command_block_wrapper.Command+4], sense_data.sizeof
704
        mov     byte [edx+command_block_wrapper.Command+4], sizeof.sense_data
735
        ret     8
705
        ret     8
Line 736... Line 706...
736
endp
706
endp
737
 
707
 
Line 778... Line 748...
778
; so allow them to proceed also.
748
; so allow them to proceed also.
779
        cmp     cx, 0x5005
749
        cmp     cx, 0x5005
780
        jz      .known
750
        jz      .known
781
; 1c. If the device is unknown, print a message and go to 11c.
751
; 1c. If the device is unknown, print a message and go to 11c.
782
        mov     esi, unkdevice
752
        mov     esi, unkdevice
783
        call    SysMsgBoardStr
753
        invoke  SysMsgBoardStr
784
        jmp     .nothing
754
        jmp     .nothing
785
; 1d. If the device uses known command set, print a message and continue
755
; 1d. If the device uses known command set, print a message and continue
786
; configuring.
756
; configuring.
787
.known:
757
.known:
788
        push    esi
758
        push    esi
789
        mov     esi, okdevice
759
        mov     esi, okdevice
790
        call    SysMsgBoardStr
760
        invoke  SysMsgBoardStr
791
        pop     esi
761
        pop     esi
792
; 2. Allocate memory for internal device data.
762
; 2. Allocate memory for internal device data.
793
; 2a. Call the kernel.
763
; 2a. Call the kernel.
794
        mov     eax, usb_device_data.sizeof
764
        mov     eax, sizeof.usb_device_data
795
        call    Kmalloc
765
        invoke  Kmalloc
796
; 2b. Check return value.
766
; 2b. Check return value.
797
        test    eax, eax
767
        test    eax, eax
798
        jnz     @f
768
        jnz     @f
799
; 2c. If failed, say a message and go to 11c.
769
; 2c. If failed, say a message and go to 11c.
800
        mov     esi, nomemory
770
        mov     esi, nomemory
801
        call    SysMsgBoardStr
771
        invoke  SysMsgBoardStr
802
        jmp     .nothing
772
        jmp     .nothing
803
@@:
773
@@:
804
; 2d. If succeeded, zero the contents and continue configuring.
774
; 2d. If succeeded, zero the contents and continue configuring.
805
        xchg    ebx, eax        ; ebx will point to usb_device_data
775
        xchg    ebx, eax        ; ebx will point to usb_device_data
806
        xor     eax, eax
776
        xor     eax, eax
Line 827... Line 797...
827
; 2i. Initialize requests queue.
797
; 2i. Initialize requests queue.
828
        lea     eax, [ebx+usb_device_data.RequestsQueue]
798
        lea     eax, [ebx+usb_device_data.RequestsQueue]
829
        mov     [eax+request_queue_item.Next], eax
799
        mov     [eax+request_queue_item.Next], eax
830
        mov     [eax+request_queue_item.Prev], eax
800
        mov     [eax+request_queue_item.Prev], eax
831
        lea     ecx, [ebx+usb_device_data.QueueLock]
801
        lea     ecx, [ebx+usb_device_data.QueueLock]
832
        call    MutexInit
802
        invoke  MutexInit
833
; Bulk-only mass storage devices use one OUT bulk endpoint for sending
803
; Bulk-only mass storage devices use one OUT bulk endpoint for sending
834
; command/data and one IN bulk endpoint for receiving data/status.
804
; command/data and one IN bulk endpoint for receiving data/status.
835
; Look for those endpoints.
805
; Look for those endpoints.
836
; 3. Get the upper bound of all descriptors' data.
806
; 3. Get the upper bound of all descriptors' data.
837
        mov     edx, [.config]  ; configuration descriptor
807
        mov     edx, [.config]  ; configuration descriptor
Line 860... Line 830...
860
; the loop.
830
; the loop.
861
        cmp     byte [esi+endpoint_descr.bDescriptorType], ENDPOINT_DESCR_TYPE
831
        cmp     byte [esi+endpoint_descr.bDescriptorType], ENDPOINT_DESCR_TYPE
862
        jnz     .lookep
832
        jnz     .lookep
863
; 5. Check that the descriptor contains all required data and all data are
833
; 5. Check that the descriptor contains all required data and all data are
864
; readable. The opposite is an error.
834
; readable. The opposite is an error.
865
        cmp     byte [esi+endpoint_descr.bLength], endpoint_descr.sizeof
835
        cmp     byte [esi+endpoint_descr.bLength], sizeof.endpoint_descr
866
        jb      .errorep
836
        jb      .errorep
867
        lea     ecx, [esi+endpoint_descr.sizeof]
837
        lea     ecx, [esi+sizeof.endpoint_descr]
868
        cmp     ecx, edx
838
        cmp     ecx, edx
869
        ja      .errorep
839
        ja      .errorep
870
; 6. Check that the endpoint is bulk endpoint. The opposite is an error.
840
; 6. Check that the endpoint is bulk endpoint. The opposite is an error.
871
        mov     cl, [esi+endpoint_descr.bmAttributes]
841
        mov     cl, [esi+endpoint_descr.bmAttributes]
872
        and     cl, 3
842
        and     cl, 3
Line 885... Line 855...
885
; 9b. Load parameters from the descriptor.
855
; 9b. Load parameters from the descriptor.
886
        movzx   ecx, [esi+endpoint_descr.bEndpointAddress]
856
        movzx   ecx, [esi+endpoint_descr.bEndpointAddress]
887
        movzx   edx, [esi+endpoint_descr.wMaxPacketSize]
857
        movzx   edx, [esi+endpoint_descr.wMaxPacketSize]
888
        movzx   eax, [esi+endpoint_descr.bInterval]     ; not used for USB1, may be important for USB2
858
        movzx   eax, [esi+endpoint_descr.bInterval]     ; not used for USB1, may be important for USB2
889
; 9c. Call the kernel.
859
; 9c. Call the kernel.
890
        stdcall USBOpenPipe, [ebx+usb_device_data.ConfigPipe], ecx, edx, BULK_PIPE, eax
860
        invoke  USBOpenPipe, [ebx+usb_device_data.ConfigPipe], ecx, edx, BULK_PIPE, eax
891
; 9d. Restore registers.
861
; 9d. Restore registers.
892
        pop     edx ecx
862
        pop     edx ecx
893
; 9e. Check result. If failed, go to 11b.
863
; 9e. Check result. If failed, go to 11b.
894
        test    eax, eax
864
        test    eax, eax
895
        jz      .free
865
        jz      .free
Line 905... Line 875...
905
; 11a. Print a message.
875
; 11a. Print a message.
906
        DEBUGF 1,'K : error: invalid endpoint descriptor\n'
876
        DEBUGF 1,'K : error: invalid endpoint descriptor\n'
907
.free:
877
.free:
908
; 11b. Free the allocated usb_device_data.
878
; 11b. Free the allocated usb_device_data.
909
        xchg    eax, ebx
879
        xchg    eax, ebx
910
        call    Kfree
880
        invoke  Kfree
911
.nothing:
881
.nothing:
912
; 11c. Return an error.
882
; 11c. Return an error.
913
        xor     eax, eax
883
        xor     eax, eax
914
        jmp     .return
884
        jmp     .return
915
.created:
885
.created:
Line 920... Line 890...
920
        mov     byte [eax+6], 1         ; transfer 1 byte
890
        mov     byte [eax+6], 1         ; transfer 1 byte
921
        lea     ecx, [ebx+usb_device_data.MaxLUN]
891
        lea     ecx, [ebx+usb_device_data.MaxLUN]
922
if DUMP_PACKETS
892
if DUMP_PACKETS
923
        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
893
        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
924
end if
894
end if
925
        stdcall USBControlTransferAsync, [ebx+usb_device_data.ConfigPipe], eax, ecx, 1, known_lun_callback, ebx, 0
895
        invoke  USBControlTransferAsync, [ebx+usb_device_data.ConfigPipe], eax, ecx, 1, known_lun_callback, ebx, 0
926
; 13. Return with pointer to device data as returned value.
896
; 13. Return with pointer to device data as returned value.
927
        xchg    eax, ebx
897
        xchg    eax, ebx
928
.return:
898
.return:
929
        pop     esi ebx
899
        pop     esi ebx
930
        ret     12
900
        ret     12
Line 953... Line 923...
953
@@:
923
@@:
954
; 2. Allocate the memory for logical devices.
924
; 2. Allocate the memory for logical devices.
955
        mov     eax, [ebx+usb_device_data.MaxLUN]
925
        mov     eax, [ebx+usb_device_data.MaxLUN]
956
        inc     eax
926
        inc     eax
957
        DEBUGF 1,'K : %d logical unit(s)\n',eax
927
        DEBUGF 1,'K : %d logical unit(s)\n',eax
958
        imul    eax, usb_unit_data.sizeof
928
        imul    eax, sizeof.usb_unit_data
959
        push    ebx
929
        push    ebx
960
        call    Kmalloc
930
        invoke  Kmalloc
961
        pop     ebx
931
        pop     ebx
962
; If failed, print a message and do nothing.
932
; If failed, print a message and do nothing.
963
        test    eax, eax
933
        test    eax, eax
964
        jnz     @f
934
        jnz     @f
965
        mov     esi, nomemory
935
        mov     esi, nomemory
966
        call    SysMsgBoardStr
936
        invoke  SysMsgBoardStr
967
        pop     esi ebx
937
        pop     esi ebx
968
        ret     20
938
        ret     20
969
@@:
939
@@:
970
        mov     [ebx+usb_device_data.LogicalDevices], eax
940
        mov     [ebx+usb_device_data.LogicalDevices], eax
971
; 3. Initialize logical devices and initiate TEST_UNIT_READY request.
941
; 3. Initialize logical devices and initiate TEST_UNIT_READY request.
Line 978... Line 948...
978
        mov     [esi+usb_unit_data.MediaPresent], al
948
        mov     [esi+usb_unit_data.MediaPresent], al
979
        mov     [esi+usb_unit_data.DiskDevice], eax
949
        mov     [esi+usb_unit_data.DiskDevice], eax
980
        mov     [esi+usb_unit_data.SectorSize], eax
950
        mov     [esi+usb_unit_data.SectorSize], eax
981
        mov     [esi+usb_unit_data.UnitReadyAttempts], eax
951
        mov     [esi+usb_unit_data.UnitReadyAttempts], eax
982
        push    ecx
952
        push    ecx
983
        call    GetTimerTicks
953
        invoke  GetTimerTicks
984
        mov     [esi+usb_unit_data.TimerTicks], eax
954
        mov     [esi+usb_unit_data.TimerTicks], eax
985
        stdcall queue_request, ebx, test_unit_ready_req, 0, test_unit_ready_callback, esi
955
        stdcall queue_request, ebx, test_unit_ready_req, 0, test_unit_ready_callback, esi
986
        pop     ecx
956
        pop     ecx
987
        inc     ecx
957
        inc     ecx
988
        add     esi, usb_unit_data.sizeof
958
        add     esi, sizeof.usb_unit_data
989
        cmp     ecx, [ebx+usb_device_data.MaxLUN]
959
        cmp     ecx, [ebx+usb_device_data.MaxLUN]
990
        jbe     .looplun
960
        jbe     .looplun
991
; 4. Return.
961
; 4. Return.
992
        pop     esi ebx
962
        pop     esi ebx
993
        ret     20
963
        ret     20
Line 997... Line 967...
997
; edx = first argument = pointer to usb_device_data.Command,
967
; edx = first argument = pointer to usb_device_data.Command,
998
; second argument = custom data given to queue_request.
968
; second argument = custom data given to queue_request.
999
proc inquiry_req
969
proc inquiry_req
1000
        mov     eax, [esp+8]
970
        mov     eax, [esp+8]
1001
        mov     al, [eax+usb_unit_data.LUN]
971
        mov     al, [eax+usb_unit_data.LUN]
1002
        mov     [edx+command_block_wrapper.Length], inquiry_data.sizeof
972
        mov     [edx+command_block_wrapper.Length], sizeof.inquiry_data
1003
        mov     [edx+command_block_wrapper.Flags], CBW_FLAG_IN
973
        mov     [edx+command_block_wrapper.Flags], CBW_FLAG_IN
1004
        mov     [edx+command_block_wrapper.LUN], al
974
        mov     [edx+command_block_wrapper.LUN], al
1005
        mov     byte [edx+command_block_wrapper.Command+0], SCSI_INQUIRY
975
        mov     byte [edx+command_block_wrapper.Command+0], SCSI_INQUIRY
1006
        mov     byte [edx+command_block_wrapper.Command+4], inquiry_data.sizeof
976
        mov     byte [edx+command_block_wrapper.Command+4], sizeof.inquiry_data
1007
        ret     8
977
        ret     8
1008
endp
978
endp
Line 1009... Line 979...
1009
 
979
 
1010
; Called when SCSI INQUIRY request is completed.
980
; Called when SCSI INQUIRY request is completed.
Line 1032... Line 1002...
1032
        mov     edx, [esp+8]
1002
        mov     edx, [esp+8]
1033
        push    ebx ecx esi edi
1003
        push    ebx ecx esi edi
1034
        movi    ebx, 1
1004
        movi    ebx, 1
1035
        mov     ecx, new_disk_thread
1005
        mov     ecx, new_disk_thread
1036
        ; edx = parameter
1006
        ; edx = parameter
1037
        call    CreateThread
1007
        invoke  CreateThread
1038
        pop     edi esi ecx ebx
1008
        pop     edi esi ecx ebx
1039
        cmp     eax, -1
1009
        cmp     eax, -1
1040
        jnz     .nothing
1010
        jnz     .nothing
1041
; on error, reverse step 3
1011
; on error, reverse step 3
1042
        lock dec [ecx+usb_device_data.NumReferences]
1012
        lock dec [ecx+usb_device_data.NumReferences]
Line 1044... Line 1014...
1044
        ret     8
1014
        ret     8
1045
.fail:
1015
.fail:
1046
; 4. The command has failed. Print a message and do nothing.
1016
; 4. The command has failed. Print a message and do nothing.
1047
        push    esi
1017
        push    esi
1048
        mov     esi, inquiry_fail
1018
        mov     esi, inquiry_fail
1049
        call    SysMsgBoardStr
1019
        invoke  SysMsgBoardStr
1050
        pop     esi
1020
        pop     esi
1051
        ret     8
1021
        ret     8
1052
endp
1022
endp
Line 1053... Line 1023...
1053
 
1023
 
Line 1077... Line 1047...
1077
        jnz     .fail
1047
        jnz     .fail
1078
; 2. The command has completed successfully,
1048
; 2. The command has completed successfully,
1079
; possibly after some repetitions. Print a debug message showing
1049
; possibly after some repetitions. Print a debug message showing
1080
; number and time of those. Remember that media is ready and go to 4.
1050
; number and time of those. Remember that media is ready and go to 4.
1081
        DEBUGF 1,'K : media is ready\n'
1051
        DEBUGF 1,'K : media is ready\n'
1082
        call    GetTimerTicks
1052
        invoke  GetTimerTicks
1083
        sub     eax, [edx+usb_unit_data.TimerTicks]
1053
        sub     eax, [edx+usb_unit_data.TimerTicks]
1084
        DEBUGF 1,'K : %d attempts, %d ticks\n',[edx+usb_unit_data.UnitReadyAttempts],eax
1054
        DEBUGF 1,'K : %d attempts, %d ticks\n',[edx+usb_unit_data.UnitReadyAttempts],eax
1085
        inc     [edx+usb_unit_data.MediaPresent]
1055
        inc     [edx+usb_unit_data.MediaPresent]
1086
        jmp     .inquiry
1056
        jmp     .inquiry
1087
.fail:
1057
.fail:
Line 1092... Line 1062...
1092
        inc     [edx+usb_unit_data.UnitReadyAttempts]
1062
        inc     [edx+usb_unit_data.UnitReadyAttempts]
1093
        cmp     [edx+usb_unit_data.UnitReadyAttempts], 3
1063
        cmp     [edx+usb_unit_data.UnitReadyAttempts], 3
1094
        jz      @f
1064
        jz      @f
1095
        push    ecx edx esi
1065
        push    ecx edx esi
1096
        movi    esi, 10
1066
        movi    esi, 10
1097
        call    Sleep
1067
        invoke  Sleep
1098
        pop     esi edx ecx
1068
        pop     esi edx ecx
1099
        stdcall queue_request, ecx, test_unit_ready_req, 0, test_unit_ready_callback, edx
1069
        stdcall queue_request, ecx, test_unit_ready_req, 0, test_unit_ready_callback, edx
1100
        ret     8
1070
        ret     8
1101
@@:
1071
@@:
1102
        DEBUGF 1,'K : media not ready\n'
1072
        DEBUGF 1,'K : media not ready\n'
Line 1118... Line 1088...
1118
; We are ready to notify the kernel about a new disk device.
1088
; We are ready to notify the kernel about a new disk device.
1119
        mov     esi, [.param]
1089
        mov     esi, [.param]
1120
; 1. Generate name.
1090
; 1. Generate name.
1121
; 1a. Find a free index.
1091
; 1a. Find a free index.
1122
        mov     ecx, free_numbers_lock
1092
        mov     ecx, free_numbers_lock
1123
        call    MutexLock
1093
        invoke  MutexLock
1124
        xor     eax, eax
1094
        xor     eax, eax
1125
@@:
1095
@@:
1126
        bsf     edx, [free_numbers+eax]
1096
        bsf     edx, [free_numbers+eax]
1127
        jnz     @f
1097
        jnz     @f
1128
        add     eax, 4
1098
        add     eax, 4
1129
        cmp     eax, 4*4
1099
        cmp     eax, 4*4
1130
        jnz     @b
1100
        jnz     @b
1131
        call    MutexUnlock
1101
        invoke  MutexUnlock
1132
        push    esi
1102
        push    esi
1133
        mov     esi, noindex
1103
        mov     esi, noindex
1134
        call    SysMsgBoardStr
1104
        invoke  SysMsgBoardStr
1135
        pop     esi
1105
        pop     esi
1136
        jmp     .drop_reference
1106
        jmp     .drop_reference
1137
@@:
1107
@@:
1138
; 1b. Mark the index as busy.
1108
; 1b. Mark the index as busy.
1139
        btr     [free_numbers+eax], edx
1109
        btr     [free_numbers+eax], edx
1140
        lea     eax, [eax*8+edx]
1110
        lea     eax, [eax*8+edx]
1141
        push    eax
1111
        push    eax
1142
        call    MutexUnlock
1112
        invoke  MutexUnlock
1143
        pop     eax
1113
        pop     eax
1144
; 1c. Generate a name of the form "usbhd" in the stack.
1114
; 1c. Generate a name of the form "usbhd" in the stack.
1145
        mov     dword [esp], 'usbh'
1115
        mov     dword [esp], 'usbh'
1146
        lea     edi, [esp+5]
1116
        lea     edi, [esp+5]
1147
        mov     byte [edi-1], 'd'
1117
        mov     byte [edi-1], 'd'
Line 1164... Line 1134...
1164
; 3d. Store the index in usb_unit_data to free it later.
1134
; 3d. Store the index in usb_unit_data to free it later.
1165
        mov     [esi+usb_unit_data.DiskIndex], cl
1135
        mov     [esi+usb_unit_data.DiskIndex], cl
1166
; 4. Notify the kernel about a new disk.
1136
; 4. Notify the kernel about a new disk.
1167
; 4a. Add a disk.
1137
; 4a. Add a disk.
1168
;       stdcall queue_request, ecx, read_capacity_req, eax, read_capacity_callback, eax
1138
;       stdcall queue_request, ecx, read_capacity_req, eax, read_capacity_callback, eax
1169
        stdcall DiskAdd, disk_functions, edx, esi, 0
1139
        invoke  DiskAdd, disk_functions, edx, esi, 0
1170
        mov     ebx, eax
1140
        mov     ebx, eax
1171
; 4b. If it failed, release the index and do nothing.
1141
; 4b. If it failed, release the index and do nothing.
1172
        test    eax, eax
1142
        test    eax, eax
1173
        jz      .free_index
1143
        jz      .free_index
1174
; 4c. Notify the kernel that a media is present.
1144
; 4c. Notify the kernel that a media is present.
1175
        stdcall DiskMediaChanged, eax, 1
1145
        invoke  DiskMediaChanged, eax, 1
1176
; 5. Lock the requests queue, check that device is not disconnected,
1146
; 5. Lock the requests queue, check that device is not disconnected,
1177
; store the disk handle, unlock the requests queue.
1147
; store the disk handle, unlock the requests queue.
1178
        mov     ecx, [esi+usb_unit_data.Parent]
1148
        mov     ecx, [esi+usb_unit_data.Parent]
1179
        add     ecx, usb_device_data.QueueLock
1149
        add     ecx, usb_device_data.QueueLock
1180
        call    MutexLock
1150
        invoke  MutexLock
1181
        cmp     byte [ecx+usb_device_data.DeviceDisconnected-usb_device_data.QueueLock], 0
1151
        cmp     byte [ecx+usb_device_data.DeviceDisconnected-usb_device_data.QueueLock], 0
1182
        jnz     .disconnected
1152
        jnz     .disconnected
1183
        mov     [esi+usb_unit_data.DiskDevice], ebx
1153
        mov     [esi+usb_unit_data.DiskDevice], ebx
1184
        call    MutexUnlock
1154
        invoke  MutexUnlock
1185
        jmp     .exit
1155
        jmp     .exit
1186
.disconnected:
1156
.disconnected:
1187
        call    MutexUnlock
1157
        invoke  MutexUnlock
1188
        stdcall disk_close, ebx
1158
        stdcall disk_close, ebx
1189
        jmp     .exit
1159
        jmp     .exit
1190
.free_index:
1160
.free_index:
1191
        mov     ecx, free_numbers_lock
1161
        mov     ecx, free_numbers_lock
1192
        call    MutexLock
1162
        invoke  MutexLock
1193
        movzx   eax, [esi+usb_unit_data.DiskIndex]
1163
        movzx   eax, [esi+usb_unit_data.DiskIndex]
1194
        bts     [free_numbers], eax
1164
        bts     [free_numbers], eax
1195
        call    MutexUnlock
1165
        invoke  MutexUnlock
1196
.drop_reference:
1166
.drop_reference:
1197
        mov     esi, [esi+usb_unit_data.Parent]
1167
        mov     esi, [esi+usb_unit_data.Parent]
1198
        lock dec [esi+usb_device_data.NumReferences]
1168
        lock dec [esi+usb_device_data.NumReferences]
1199
        jnz     .exit
1169
        jnz     .exit
1200
        mov     eax, [esi+usb_device_data.LogicalDevices]
1170
        mov     eax, [esi+usb_device_data.LogicalDevices]
1201
        call    Kfree
1171
        invoke  Kfree
1202
        xchg    eax, esi
1172
        xchg    eax, esi
1203
        call    Kfree
1173
        invoke  Kfree
1204
.exit:
1174
.exit:
1205
        or      eax, -1
1175
        or      eax, -1
1206
        int     0x40
1176
        int     0x40
1207
endp
1177
endp
Line 1214... Line 1184...
1214
        dd      ?       ; return address
1184
        dd      ?       ; return address
1215
.device dd      ?
1185
.device dd      ?
1216
end virtual
1186
end virtual
1217
; 1. Say a message.
1187
; 1. Say a message.
1218
        mov     esi, disconnectmsg
1188
        mov     esi, disconnectmsg
1219
        call    SysMsgBoardStr
1189
        invoke  SysMsgBoardStr
1220
; 2. Lock the requests queue, set .DeviceDisconnected to 1,
1190
; 2. Lock the requests queue, set .DeviceDisconnected to 1,
1221
; unlock the requests queue.
1191
; unlock the requests queue.
1222
; Locking is required for synchronization with queue_request:
1192
; Locking is required for synchronization with queue_request:
1223
; all USB callbacks are executed in the same thread and are
1193
; all USB callbacks are executed in the same thread and are
1224
; synchronized automatically, but queue_request can be running
1194
; synchronized automatically, but queue_request can be running
Line 1227... Line 1197...
1227
; been started, has checked that device is not yet disconnected,
1197
; been started, has checked that device is not yet disconnected,
1228
; then DeviceDisconnected completes and all handles become invalid,
1198
; then DeviceDisconnected completes and all handles become invalid,
1229
; then queue_request tries to use them.
1199
; then queue_request tries to use them.
1230
        mov     esi, [.device]
1200
        mov     esi, [.device]
1231
        lea     ecx, [esi+usb_device_data.QueueLock]
1201
        lea     ecx, [esi+usb_device_data.QueueLock]
1232
        call    MutexLock
1202
        invoke  MutexLock
1233
        mov     [esi+usb_device_data.DeviceDisconnected], 1
1203
        mov     [esi+usb_device_data.DeviceDisconnected], 1
1234
        call    MutexUnlock
1204
        invoke  MutexUnlock
1235
; 3. Drop one reference to the structure and check whether
1205
; 3. Drop one reference to the structure and check whether
1236
; that was the last reference.
1206
; that was the last reference.
1237
        lock dec [esi+usb_device_data.NumReferences]
1207
        lock dec [esi+usb_device_data.NumReferences]
1238
        jz      .free
1208
        jz      .free
1239
; 4. If not, there are some additional references due to disk devices;
1209
; 4. If not, there are some additional references due to disk devices;
Line 1245... Line 1215...
1245
        inc     ebx
1215
        inc     ebx
1246
.diskdel:
1216
.diskdel:
1247
        mov     eax, [esi+usb_unit_data.DiskDevice]
1217
        mov     eax, [esi+usb_unit_data.DiskDevice]
1248
        test    eax, eax
1218
        test    eax, eax
1249
        jz      @f
1219
        jz      @f
1250
        stdcall DiskDel, eax
1220
        invoke  DiskDel, eax
1251
@@:
1221
@@:
1252
        add     esi, usb_unit_data.sizeof
1222
        add     esi, sizeof.usb_unit_data
1253
        dec     ebx
1223
        dec     ebx
1254
        jnz     .diskdel
1224
        jnz     .diskdel
1255
; In this case, some operations with those disks are still possible,
1225
; In this case, some operations with those disks are still possible,
1256
; so we can't do anything more now. disk_close will take care of the rest.
1226
; so we can't do anything more now. disk_close will take care of the rest.
1257
.return:
1227
.return:
Line 1260... Line 1230...
1260
; 5. If there are no disk devices, free all resources which were allocated.
1230
; 5. If there are no disk devices, free all resources which were allocated.
1261
.free:
1231
.free:
1262
        mov     eax, [esi+usb_device_data.LogicalDevices]
1232
        mov     eax, [esi+usb_device_data.LogicalDevices]
1263
        test    eax, eax
1233
        test    eax, eax
1264
        jz      @f
1234
        jz      @f
1265
        call    Kfree
1235
        invoke  Kfree
1266
@@:
1236
@@:
1267
        xchg    eax, esi
1237
        xchg    eax, esi
1268
        call    Kfree
1238
        invoke  Kfree
1269
        jmp     .return
1239
        jmp     .return
1270
endp
1240
endp
Line 1271... Line 1241...
1271
 
1241
 
1272
; Disk functions.
1242
; Disk functions.
Line 1284... Line 1254...
1284
        dd      ?       ; return address
1254
        dd      ?       ; return address
1285
.userdata       dd      ?
1255
.userdata       dd      ?
1286
end virtual
1256
end virtual
1287
        mov     esi, [.userdata]
1257
        mov     esi, [.userdata]
1288
        mov     ecx, free_numbers_lock
1258
        mov     ecx, free_numbers_lock
1289
        call    MutexLock
1259
        invoke  MutexLock
1290
        movzx   eax, [esi+usb_unit_data.DiskIndex]
1260
        movzx   eax, [esi+usb_unit_data.DiskIndex]
1291
        bts     [free_numbers], eax
1261
        bts     [free_numbers], eax
1292
        call    MutexUnlock
1262
        invoke  MutexUnlock
1293
        mov     esi, [esi+usb_unit_data.Parent]
1263
        mov     esi, [esi+usb_unit_data.Parent]
1294
        lock dec [esi+usb_device_data.NumReferences]
1264
        lock dec [esi+usb_device_data.NumReferences]
1295
        jnz     .nothing
1265
        jnz     .nothing
1296
        mov     eax, [esi+usb_device_data.LogicalDevices]
1266
        mov     eax, [esi+usb_device_data.LogicalDevices]
1297
        call    Kfree
1267
        invoke  Kfree
1298
        xchg    eax, esi
1268
        xchg    eax, esi
1299
        call    Kfree
1269
        invoke  Kfree
1300
.nothing:
1270
.nothing:
1301
        pop     esi ebx
1271
        pop     esi ebx
1302
        ret     4
1272
        ret     4
1303
endp
1273
endp
Line 1306... Line 1276...
1306
proc disk_querymedia stdcall uses ebx esi edi, \
1276
proc disk_querymedia stdcall uses ebx esi edi, \
1307
        userdata:dword, mediainfo:dword
1277
        userdata:dword, mediainfo:dword
1308
; 1. Create event for waiting.
1278
; 1. Create event for waiting.
1309
        xor     esi, esi
1279
        xor     esi, esi
1310
        xor     ecx, ecx
1280
        xor     ecx, ecx
1311
        call    CreateEvent
1281
        invoke  CreateEvent
1312
        test    eax, eax
1282
        test    eax, eax
1313
        jz      .generic_fail
1283
        jz      .generic_fail
1314
        push    eax
1284
        push    eax
1315
        push    edx
1285
        push    edx
1316
        push    ecx
1286
        push    ecx
Line 1338... Line 1308...
1338
        mov     edx, esp
1308
        mov     edx, esp
1339
        stdcall queue_request, ecx, read_capacity_req, edx, read_capacity_callback, edx
1309
        stdcall queue_request, ecx, read_capacity_req, edx, read_capacity_callback, edx
1340
; 3. Wait for event. This destroys it.
1310
; 3. Wait for event. This destroys it.
1341
        mov     eax, [.event]
1311
        mov     eax, [.event]
1342
        mov     ebx, [.event_code]
1312
        mov     ebx, [.event_code]
1343
        call    WaitEvent
1313
        invoke  WaitEvent
1344
; 4. Get the status and results.
1314
; 4. Get the status and results.
1345
        pop     ecx
1315
        pop     ecx
1346
        bswap   ecx     ; .LastLBA
1316
        bswap   ecx     ; .LastLBA
1347
        pop     edx
1317
        pop     edx
1348
        bswap   edx     ; .SectorSize
1318
        bswap   edx     ; .SectorSize
Line 1401... Line 1371...
1401
        push    ebx esi edi
1371
        push    ebx esi edi
1402
        mov     eax, [ecx+disk_querymedia.event-disk_querymedia.locals]
1372
        mov     eax, [ecx+disk_querymedia.event-disk_querymedia.locals]
1403
        mov     ebx, [ecx+disk_querymedia.event_code-disk_querymedia.locals]
1373
        mov     ebx, [ecx+disk_querymedia.event_code-disk_querymedia.locals]
1404
        xor     edx, edx
1374
        xor     edx, edx
1405
        xor     esi, esi
1375
        xor     esi, esi
1406
        call    RaiseEvent
1376
        invoke  RaiseEvent
1407
        pop     edi esi ebx
1377
        pop     edi esi ebx
1408
        ret     8
1378
        ret     8
1409
endp
1379
endp
Line 1410... Line 1380...
1410
 
1380
 
Line 1441... Line 1411...
1441
        cmp     dword [startsector+4], 0
1411
        cmp     dword [startsector+4], 0
1442
        jnz     .generic_fail
1412
        jnz     .generic_fail
1443
; 4. Create event for waiting.
1413
; 4. Create event for waiting.
1444
        xor     esi, esi
1414
        xor     esi, esi
1445
        xor     ecx, ecx
1415
        xor     ecx, ecx
1446
        call    CreateEvent
1416
        invoke  CreateEvent
1447
        test    eax, eax
1417
        test    eax, eax
1448
        jz      .generic_fail
1418
        jz      .generic_fail
1449
        push    eax     ; .event
1419
        push    eax     ; .event
1450
        push    edx     ; .event_code
1420
        push    edx     ; .event_code
1451
        push    ecx     ; .status
1421
        push    ecx     ; .status
Line 1474... Line 1444...
1474
        mov     ecx, [eax+usb_unit_data.Parent]
1444
        mov     ecx, [eax+usb_unit_data.Parent]
1475
        stdcall queue_request, ecx, read_write_req, [buffer], read_write_callback, esp
1445
        stdcall queue_request, ecx, read_write_req, [buffer], read_write_callback, esp
1476
; 6. Wait for event. This destroys it.
1446
; 6. Wait for event. This destroys it.
1477
        mov     eax, [.event]
1447
        mov     eax, [.event]
1478
        mov     ebx, [.event_code]
1448
        mov     ebx, [.event_code]
1479
        call    WaitEvent
1449
        invoke  WaitEvent
1480
; 7. Get the status. If the operation has failed, abort.
1450
; 7. Get the status. If the operation has failed, abort.
1481
        pop     eax     ; .status
1451
        pop     eax     ; .status
1482
        pop     ecx ecx ; cleanup .event_code, .event
1452
        pop     ecx ecx ; cleanup .event_code, .event
1483
        pop     ecx     ; .length_cur
1453
        pop     ecx     ; .length_cur
1484
        test    eax, eax
1454
        test    eax, eax
Line 1577... Line 1547...
1577
; 5. Set the event.
1547
; 5. Set the event.
1578
        mov     eax, [esi+disk_read_write.event-disk_read_write.locals]
1548
        mov     eax, [esi+disk_read_write.event-disk_read_write.locals]
1579
        mov     ebx, [esi+disk_read_write.event_code-disk_read_write.locals]
1549
        mov     ebx, [esi+disk_read_write.event_code-disk_read_write.locals]
1580
        xor     edx, edx
1550
        xor     edx, edx
1581
        xor     esi, esi
1551
        xor     esi, esi
1582
        call    RaiseEvent
1552
        invoke  RaiseEvent
1583
; 6. Return.
1553
; 6. Return.
1584
        pop     edi esi ebx
1554
        pop     edi esi ebx
1585
        ret     8
1555
        ret     8
1586
endp
1556
endp
Line 1597... Line 1567...
1597
inquiry_fail    db      'K : INQUIRY command failed',13,10,0
1567
inquiry_fail    db      'K : INQUIRY command failed',13,10,0
1598
;read_capacity_fail db  'K : READ CAPACITY command failed',13,10,0
1568
;read_capacity_fail db  'K : READ CAPACITY command failed',13,10,0
1599
;read_fail      db      'K : READ command failed',13,10,0
1569
;read_fail      db      'K : READ command failed',13,10,0
1600
noindex         db      'K : failed to generate disk name',13,10,0
1570
noindex         db      'K : failed to generate disk name',13,10,0
Line 1601... Line -...
1601
 
-
 
1602
; Exported variable: kernel API version.
1571
 
1603
align 4
-
 
1604
version dd      50005h
1572
align 4
1605
; Structure with callback functions.
1573
; Structure with callback functions.
1606
usb_functions:
1574
usb_functions:
1607
        dd      usb_functions_end - usb_functions
1575
        dd      usb_functions_end - usb_functions
1608
        dd      AddDevice
1576
        dd      AddDevice
Line 1618... Line 1586...
1618
        dd      disk_write
1586
        dd      disk_write
1619
        dd      0       ; flush
1587
        dd      0       ; flush
1620
        dd      0       ; adjust_cache_size: use default cache
1588
        dd      0       ; adjust_cache_size: use default cache
1621
disk_functions_end:
1589
disk_functions_end:
Line -... Line 1590...
-
 
1590
 
-
 
1591
data fixups
-
 
1592
end data
1622
 
1593
 
1623
free_numbers_lock       rd      3
1594
free_numbers_lock       rd      3
1624
; 128 devices should be enough for everybody
1595
; 128 devices should be enough for everybody
Line 1625... Line 1596...
1625
free_numbers    dd      -1, -1, -1, -1
1596
free_numbers    dd      -1, -1, -1, -1
1626
 
1597
 
1627
; for DEBUGF macro
-
 
1628
include_debug_strings
-
 
1629
 
-