Subversion Repositories Kolibri OS

Rev

Rev 4346 | Blame | Last modification | View Log | Download | RSS feed

  1. ; standard driver stuff
  2. format MS COFF
  3.  
  4. DEBUG = 1
  5. DUMP_PACKETS = 0
  6.  
  7. ; this is for DEBUGF macro from 'fdo.inc'
  8. __DEBUG__ = 1
  9. __DEBUG_LEVEL__ = 1
  10.  
  11. include 'proc32.inc'
  12. include 'imports.inc'
  13. include 'fdo.inc'
  14.  
  15. public START
  16. public version
  17.  
  18. ; USB constants
  19. DEVICE_DESCR_TYPE = 1
  20. CONFIG_DESCR_TYPE = 2
  21. STRING_DESCR_TYPE = 3
  22. INTERFACE_DESCR_TYPE = 4
  23. ENDPOINT_DESCR_TYPE = 5
  24. DEVICE_QUALIFIER_DESCR_TYPE = 6
  25.  
  26. CONTROL_PIPE = 0
  27. ISOCHRONOUS_PIPE = 1
  28. BULK_PIPE = 2
  29. INTERRUPT_PIPE = 3
  30.  
  31. ; USB structures
  32. virtual at 0
  33. config_descr:
  34. .bLength                db      ?
  35. .bDescriptorType        db      ?
  36. .wTotalLength           dw      ?
  37. .bNumInterfaces         db      ?
  38. .bConfigurationValue    db      ?
  39. .iConfiguration         db      ?
  40. .bmAttributes           db      ?
  41. .bMaxPower              db      ?
  42. .sizeof:
  43. end virtual
  44.  
  45. virtual at 0
  46. interface_descr:
  47. .bLength                db      ?
  48. .bDescriptorType        db      ?
  49. .bInterfaceNumber       db      ?
  50. .bAlternateSetting      db      ?
  51. .bNumEndpoints          db      ?
  52. .bInterfaceClass        db      ?
  53. .bInterfaceSubClass     db      ?
  54. .bInterfaceProtocol     db      ?
  55. .iInterface             db      ?
  56. .sizeof:
  57. end virtual
  58.  
  59. virtual at 0
  60. endpoint_descr:
  61. .bLength                db      ?
  62. .bDescriptorType        db      ?
  63. .bEndpointAddress       db      ?
  64. .bmAttributes           db      ?
  65. .wMaxPacketSize         dw      ?
  66. .bInterval              db      ?
  67. .sizeof:
  68. end virtual
  69.  
  70. ; Mass storage protocol constants, USB layer
  71. REQUEST_GETMAXLUN = 0xFE        ; get max lun
  72. REQUEST_BORESET = 0xFF          ; bulk-only reset
  73.  
  74. ; Mass storage protocol structures, USB layer
  75. ; Sent from host to device in the first stage of an operation.
  76. struc command_block_wrapper
  77. {
  78. .Signature      dd      ?       ; the constant 'USBC'
  79. .Tag            dd      ?       ; identifies response with request
  80. .Length         dd      ?       ; length of data-transport phase
  81. .Flags          db      ?       ; one of CBW_FLAG_*
  82. CBW_FLAG_OUT = 0
  83. 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. }
  89. virtual at 0
  90. command_block_wrapper   command_block_wrapper
  91. end virtual
  92.  
  93. ; Sent from device to host in the last stage of an operation.
  94. struc command_status_wrapper
  95. {
  96. .Signature      dd      ?       ; the constant 'USBS'
  97. .Tag            dd      ?       ; identifies response with request
  98. .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:
  104. }
  105. virtual at 0
  106. command_status_wrapper  command_status_wrapper
  107. end virtual
  108.  
  109. ; Constants of SCSI layer
  110. SCSI_REQUEST_SENSE = 3
  111. SCSI_INQUIRY = 12h
  112. SCSI_READ_CAPACITY = 25h
  113. SCSI_READ10 = 28h
  114. SCSI_WRITE10 = 2Ah
  115.  
  116. ; Result of SCSI REQUEST SENSE command.
  117. SENSE_UNKNOWN = 0
  118. SENSE_RECOVERED_ERROR = 1
  119. SENSE_NOT_READY = 2
  120. SENSE_MEDIUM_ERROR = 3
  121. SENSE_HARDWARE_ERROR = 4
  122. SENSE_ILLEGAL_REQUEST = 5
  123. SENSE_UNIT_ATTENTION = 6
  124. SENSE_DATA_PROTECT = 7
  125. SENSE_BLANK_CHECK = 8
  126. ; 9 is vendor-specific
  127. SENSE_COPY_ABORTED = 10
  128. SENSE_ABORTED_COMMAND = 11
  129. SENSE_EQUAL = 12
  130. SENSE_VOLUME_OVERFLOW = 13
  131. SENSE_MISCOMPARE = 14
  132. ; 15 is reserved
  133.  
  134. ; Structures of SCSI layer
  135. ; Result of SCSI INQUIRY request.
  136. struc inquiry_data
  137. {
  138. .PeripheralDevice       db      ?       ; lower 5 bits are PeripheralDeviceType
  139.                                         ; upper 3 bits are PeripheralQualifier
  140. .RemovableMedium        db      ?       ; upper bit is RemovableMedium
  141.                                         ; other bits are for compatibility
  142. .Version                db      ?       ; lower 3 bits are ANSI-Approved version
  143.                                         ; next 3 bits are ECMA version
  144.                                         ; upper 2 bits are ISO version
  145. .ResponseDataFormat     db      ?       ; lower 4 bits are ResponseDataFormat
  146.                                         ; bit 6 is TrmIOP
  147.                                         ; bit 7 is AENC
  148. .AdditionalLength       db      ?
  149.                         dw      ?       ; reserved
  150. .Flags                  db      ?
  151. .VendorID               rb      8       ; vendor ID, big-endian
  152. .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
  158. end virtual
  159.  
  160. struc sense_data
  161. {
  162. .ErrorCode              db      ?       ; lower 7 bits are error code:
  163.                                         ; 70h = current error,
  164.                                         ; 71h = deferred error
  165.                                         ; upper bit is InformationValid
  166. .SegmentNumber          db      ?       ; number of segment descriptor
  167.                                         ; for commands COPY [+VERIFY], COMPARE
  168. .SenseKey               db      ?       ; bits 0-3 are one of SENSE_*
  169.                                         ; bit 4 is reserved
  170.                                         ; bit 5 is IncorrectLengthIndicator
  171.                                         ; bits 6 and 7 are used by
  172.                                         ; sequential-access devices
  173. .Information            dd      ?       ; command-specific
  174. .AdditionalLength       db      ?       ; length of data starting here
  175. .CommandInformation     dd      ?       ; command-specific
  176. .AdditionalSenseCode    db      ?       ; \ more detailed error code
  177. .AdditionalSenseQual    db      ?       ; / standard has a large table of them
  178. .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
  184. sense_data sense_data
  185. end virtual
  186.  
  187. ; 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
  190. ; minus 1, can be obtained via control request Get Max LUN.
  191. virtual at 0
  192. usb_device_data:
  193. .ConfigPipe             dd      ?       ; configuration pipe
  194. .OutPipe                dd      ?       ; pipe for OUT bulk endpoint
  195. .InPipe                 dd      ?       ; pipe for IN bulk endpoint
  196. .MaxLUN                 dd      ?       ; maximum Logical Unit Number
  197. .LogicalDevices         dd      ?       ; pointer to array of usb_unit_data
  198. ; 1 for a connected USB device, 1 for each disk device
  199. ; the structure can be freed when .NumReferences decreases to zero
  200. .NumReferences          dd      ?       ; number of references
  201. .ConfigRequest          rb      8       ; buffer for configuration requests
  202. .LengthRest             dd      ?       ; Length - (size of data which were transferred)
  203. ; All requests to a given device are serialized,
  204. ; 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
  206. ; queue, the head being the current request.
  207. ; 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
  209. ; what request the data are associated with is to guarantee that only one
  210. ; request is processing at the time.
  211. .RequestsQueue          rd      2
  212. .QueueLock              rd      3       ; protects .RequestsQueue
  213. .InquiryData            inquiry_data    ; information about device
  214. ; data for the current request
  215. .Command                command_block_wrapper
  216. .DeviceDisconnected     db      ?
  217. .Status                 command_status_wrapper
  218. .Sense                  sense_data
  219. .sizeof:
  220. end virtual
  221.  
  222. ; Information about one logical device.
  223. virtual at 0
  224. usb_unit_data:
  225. .Parent         dd      ?       ; pointer to parent usb_device_data
  226. .LUN            db      ?       ; index in usb_device_data.LogicalDevices array
  227. .DiskIndex      db      ?       ; for name "usbhd<index>"
  228. .MediaPresent   db      ?
  229.                 db      ?       ; alignment
  230. .DiskDevice     dd      ?       ; handle of disk device or NULL
  231. .SectorSize     dd      ?       ; sector size
  232. ; 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.
  234. ; Two following variables track the retry count and total time for those;
  235. ; total time is currently used only for debug output.
  236. .UnitReadyAttempts      dd      ?
  237. .TimerTicks             dd      ?
  238. .sizeof:
  239. end virtual
  240.  
  241. ; This is the structure for items in the queue usb_device_data.RequestsQueue.
  242. virtual at 0
  243. request_queue_item:
  244. .Next           dd      ?       ; next item in the queue
  245. .Prev           dd      ?       ; prev item in the queue
  246. .ReqBuilder     dd      ?       ; procedure to fill command_block_wrapper
  247. .Buffer         dd      ?       ; input or output data
  248.                                 ; (length is command_block_wrapper.Length)
  249. .Callback       dd      ?       ; procedure to call in the end of transfer
  250. .UserData       dd      ?       ; passed as-is to .Callback
  251. ; There are 3 possible stages of any request, one of them optional:
  252. ; command stage (host sends command_block_wrapper to device),
  253. ; optional data stage,
  254. ; status stage (device sends command_status_wrapper to host).
  255. ; Also, if a request fails, the code queues additional request
  256. ; SCSI_REQUEST_SENSE; sense_data from SCSI_REQUEST_SENSE
  257. ; contains some information about the error.
  258. .Stage          db      ?
  259. .sizeof:
  260. end virtual
  261.  
  262. section '.flat' code readable align 16
  263. ; The start procedure.
  264. proc START
  265. virtual at esp
  266.         dd      ?       ; return address
  267. .reason dd      ?       ; DRV_ENTRY or DRV_EXIT
  268. end virtual
  269. ; 1. Test whether the procedure is called with the argument DRV_ENTRY.
  270. ; If not, return 0.
  271.         xor     eax, eax        ; initialize return value
  272.         cmp     [.reason], 1    ; compare the argument
  273.         jnz     .nothing
  274. ; 2. Initialize: we have one global mutex.
  275.         mov     ecx, free_numbers_lock
  276.         call    MutexInit
  277. ; 3. Register self as a USB driver.
  278. ; The name is my_driver = 'usbstor'; IOCTL interface is not supported;
  279. ; usb_functions is an offset of a structure with callback functions.
  280.         stdcall RegUSBDriver, my_driver, 0, usb_functions
  281. ; 4. Return the returned value of RegUSBDriver.
  282. .nothing:
  283.         ret     4
  284. endp
  285.  
  286. ; Helper procedures to work with requests queue.
  287.  
  288. ; Add a request to the queue. Stdcall with 5 arguments.
  289. proc queue_request
  290.         push    ebx esi
  291. virtual at esp
  292.                 rd      2       ; saved registers
  293.                 dd      ?       ; return address
  294. .device         dd      ?       ; pointer to usb_device_data
  295. .ReqBuilder     dd      ?       ; request_queue_item.ReqBuilder
  296. .Buffer         dd      ?       ; request_queue_item.Buffer
  297. .Callback       dd      ?       ; request_queue_item.Callback
  298. .UserData       dd      ?       ; request_queue_item.UserData
  299. end virtual
  300. ; 1. Allocate the memory for the request description.
  301.         movi    eax, request_queue_item.sizeof
  302.         call    Kmalloc
  303.         test    eax, eax
  304.         jnz     @f
  305.         mov     esi, nomemory
  306.         call    SysMsgBoardStr
  307.         pop     esi ebx
  308.         ret     20
  309. @@:
  310. ; 2. Fill user-provided parts of the request description.
  311.         push    edi
  312.         xchg    eax, ebx
  313.         lea     esi, [.ReqBuilder+4]
  314.         lea     edi, [ebx+request_queue_item.ReqBuilder]
  315.         movsd   ; ReqBuilder
  316.         movsd   ; Buffer
  317.         movsd   ; Callback
  318.         movsd   ; UserData
  319.         pop     edi
  320. ; 3. Set stage to zero: not started.
  321.         mov     [ebx+request_queue_item.Stage], 0
  322. ; 4. Lock the queue.
  323.         mov     esi, [.device]
  324.         lea     ecx, [esi+usb_device_data.QueueLock]
  325.         call    MutexLock
  326. ; 5. Insert the request to the tail of the queue.
  327.         add     esi, usb_device_data.RequestsQueue
  328.         mov     edx, [esi+request_queue_item.Prev]
  329.         mov     [ebx+request_queue_item.Next], esi
  330.         mov     [ebx+request_queue_item.Prev], edx
  331.         mov     [edx+request_queue_item.Next], ebx
  332.         mov     [esi+request_queue_item.Prev], ebx
  333. ; 6. Test whether the queue was empty
  334. ; and the request should be started immediately.
  335.         cmp     [esi+request_queue_item.Next], ebx
  336.         jnz     .unlock
  337. ; 8. If the step 6 shows that the request is the first in the queue,
  338. ; start it.
  339.         sub     esi, usb_device_data.RequestsQueue
  340.         call    setup_request
  341.         jmp     .nothing
  342. .unlock:
  343.         call    MutexUnlock
  344. ; 9. Return.
  345. .nothing:
  346.         pop     esi ebx
  347.         ret     20
  348. endp
  349.  
  350. ; The current request is completed. Call the callback,
  351. ; remove the request from the queue, start the next
  352. ; request if there is one.
  353. ; esi points to usb_device_data
  354. proc complete_request
  355. ; 1. Print common debug messages on fails.
  356. if DEBUG
  357.         cmp     [esi+usb_device_data.Status.Status], CSW_STATUS_FAIL
  358.         jb      .normal
  359.         jz      .fail
  360.         DEBUGF 1, 'K : Fatal error during execution of command %x\n', [esi+usb_device_data.Command.Command]:2
  361.         jmp     .normal
  362. .fail:
  363.         DEBUGF 1, 'K : Command %x failed\n', [esi+usb_device_data.Command.Command]:2
  364. .normal:
  365. end if
  366. ; 2. Get the current request.
  367.         mov     ebx, [esi+usb_device_data.RequestsQueue+request_queue_item.Next]
  368. ; 3. Call the callback.
  369.         stdcall [ebx+request_queue_item.Callback], esi, [ebx+request_queue_item.UserData]
  370. ; 4. Lock the queue.
  371.         lea     ecx, [esi+usb_device_data.QueueLock]
  372.         call    MutexLock
  373. ; 5. Remove the request.
  374.         lea     edx, [esi+usb_device_data.RequestsQueue]
  375.         mov     eax, [ebx+request_queue_item.Next]
  376.         mov     [eax+request_queue_item.Prev], edx
  377.         mov     [edx+request_queue_item.Next], eax
  378. ; 6. Free the request memory.
  379.         push    eax edx
  380.         xchg    eax, ebx
  381.         call    Kfree
  382.         pop     edx ebx
  383. ; 7. If there is a next request, start processing.
  384.         cmp     ebx, edx
  385.         jnz     setup_request
  386. ; 8. Unlock the queue and return.
  387.         lea     ecx, [esi+usb_device_data.QueueLock]
  388.         call    MutexUnlock
  389.         ret
  390. endp
  391.  
  392. ; Start processing the request. Called either by queue_request
  393. ; or when the previous request has been processed.
  394. ; Do not call directly, use queue_request.
  395. ; Must be called when queue is locked; unlocks the queue when returns.
  396. proc setup_request
  397.         xor     eax, eax
  398. ; 1. If DeviceDisconnected has been run, then all handles of pipes
  399. ; are invalid, so we must fail immediately.
  400. ; (That is why this function needs the locked queue: this
  401. ; guarantee that either DeviceDisconnected has been already run, or
  402. ; DeviceDisconnected will not return before the queue is unlocked.)
  403.         cmp     [esi+usb_device_data.DeviceDisconnected], al
  404.         jnz     .fatal
  405. ; 2. If the previous command has encountered a fatal error,
  406. ; perform reset recovery.
  407.         cmp     [esi+usb_device_data.Status.Status], CSW_STATUS_FATAL
  408.         jb      .norecovery
  409. ; 2a. Send Bulk-Only Mass Storage Reset command to config pipe.
  410.         lea     edx, [esi+usb_device_data.ConfigRequest]
  411.         mov     word [edx], (REQUEST_BORESET shl 8) + 21h       ; class request
  412.         mov     word [edx+6], ax        ; length = 0
  413.         stdcall USBControlTransferAsync, [esi+usb_device_data.ConfigPipe], edx, eax, eax, recovery_callback1, esi, eax
  414. ; 2b. Fail here = fatal error.
  415.         test    eax, eax
  416.         jz      .fatal
  417. ; 2c. Otherwise, unlock the queue and return. recovery_callback1 will continue processing.
  418. .unlock_return:
  419.         lea     ecx, [esi+usb_device_data.QueueLock]
  420.         call    MutexUnlock
  421.         ret
  422. .norecovery:
  423. ; 3. Send the command. Fail (no memory or device disconnected) = fatal error.
  424. ; Otherwise, go to 2c.
  425.         call    request_stage1
  426.         test    eax, eax
  427.         jnz     .unlock_return
  428. .fatal:
  429. ; 4. Fatal error. Set status = FATAL, unlock the queue, complete the request.
  430.         mov     [esi+usb_device_data.Status.Status], CSW_STATUS_FATAL
  431.         lea     ecx, [esi+usb_device_data.QueueLock]
  432.         call    MutexUnlock
  433.         jmp     complete_request
  434. endp
  435.  
  436. ; Initiate USB transfer for the first stage of a request (send command).
  437. proc request_stage1
  438.         mov     ebx, [esi+usb_device_data.RequestsQueue+request_queue_item.Next]
  439. ; 1. Set the stage to 1 = command stage.
  440.         inc     [ebx+request_queue_item.Stage]
  441. ; 2. Generate the command. Zero-initialize and use the caller-provided proc.
  442.         lea     edx, [esi+usb_device_data.Command]
  443.         xor     eax, eax
  444.         mov     [edx+command_block_wrapper.CommandLength], 12
  445.         mov     dword [edx+command_block_wrapper.Command], eax
  446.         mov     dword [edx+command_block_wrapper.Command+4], eax
  447.         mov     dword [edx+command_block_wrapper.Command+8], eax
  448.         mov     dword [edx+command_block_wrapper.Command+12], eax
  449.         inc     [edx+command_block_wrapper.Tag]
  450.         stdcall [ebx+request_queue_item.ReqBuilder], edx, [ebx+request_queue_item.UserData]
  451. ; 4. Initiate USB transfer.
  452.         lea     edx, [esi+usb_device_data.Command]
  453. if DUMP_PACKETS
  454.         DEBUGF 1,'K : USBSTOR out:'
  455.         mov     eax, edx
  456.         mov     ecx, command_block_wrapper.sizeof
  457.         call    debug_dump
  458.         DEBUGF 1,'\n'
  459. end if
  460.         stdcall USBNormalTransferAsync, [esi+usb_device_data.OutPipe], edx, command_block_wrapper.sizeof, request_callback1, esi, 0
  461.         test    eax, eax
  462.         jz      .nothing
  463. ; 5. If the next stage is data stage in the same direction, enqueue it here.
  464.         cmp     [esi+usb_device_data.Command.Flags], 0
  465.         js      .nothing
  466.         cmp     [esi+usb_device_data.Command.Length], 0
  467.         jz      .nothing
  468.         mov     edx, [esi+usb_device_data.RequestsQueue+request_queue_item.Next]
  469. if DUMP_PACKETS
  470.         DEBUGF 1,'K : USBSTOR out:'
  471.         mov     eax, [edx+request_queue_item.Buffer]
  472.         mov     ecx, [esi+usb_device_data.Command.Length]
  473.         call    debug_dump
  474.         DEBUGF 1,'\n'
  475. 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
  477. .nothing:
  478.         ret
  479. endp
  480.  
  481. if DUMP_PACKETS
  482. proc debug_dump
  483.         test    ecx, ecx
  484.         jz      .done
  485. .loop:
  486.         test    ecx, 0Fh
  487.         jnz     @f
  488.         DEBUGF 1,'\nK :'
  489. @@:
  490.         DEBUGF 1,' %x',[eax]:2
  491.         inc     eax
  492.         dec     ecx
  493.         jnz     .loop
  494. .done:
  495.         ret
  496. endp
  497. end if
  498.  
  499. ; Called when the Reset command is completed,
  500. ; either successfully or not.
  501. proc recovery_callback1
  502. virtual at esp
  503.                 dd      ?       ; return address
  504. .pipe           dd      ?
  505. .status         dd      ?
  506. .buffer         dd      ?
  507. .length         dd      ?
  508. .calldata       dd      ?
  509. end virtual
  510.         cmp     [.status], 0
  511.         jnz     .error
  512. ; todo: reset pipes
  513.         push    ebx esi
  514.         mov     esi, [.calldata+8]
  515.         call    request_stage1
  516.         pop     esi ebx
  517.         test    eax, eax
  518.         jz      .error
  519.         ret     20
  520. .error:
  521.         DEBUGF 1, 'K : error %d while resetting', [.status+24h]
  522.         jmp     request_callback1.common_error
  523. endp
  524.  
  525. ; Called when the first stage of request is completed,
  526. ; either successfully or not.
  527. proc request_callback1
  528. virtual at esp
  529.                 dd      ?       ; return address
  530. .pipe           dd      ?
  531. .status         dd      ?
  532. .buffer         dd      ?
  533. .length         dd      ?
  534. .calldata       dd      ?
  535. end virtual
  536. ; 1. Initialize.
  537.         mov     ecx, [.calldata]
  538.         mov     eax, [.status]
  539. ; 2. Test for error.
  540.         test    eax, eax
  541.         jnz     .error
  542. ; No error.
  543. ; 3. Increment the stage.
  544.         mov     edx, [ecx+usb_device_data.RequestsQueue+request_queue_item.Next]
  545.         inc     [edx+request_queue_item.Stage]
  546. ; 4. Check whether we need to send the data.
  547. ; 4a. If there is no data, skip this stage.
  548.         cmp     [ecx+usb_device_data.Command.Length], 0
  549.         jz      ..request_get_status
  550. ; 4b. If data were enqueued in the first stage, do nothing, wait for request_callback2.
  551.         cmp     [ecx+usb_device_data.Command.Flags], 0
  552.         jns     .nothing
  553. ; 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
  555.         test    eax, eax
  556.         jz      .error
  557. ; 6. The status stage goes to the same direction, enqueue it now.
  558.         mov     ecx, [.calldata]
  559.         jmp     ..enqueue_status
  560. .nothing:
  561.         ret     20
  562. .error:
  563. ; Error.
  564. ; 7. Print debug message and complete the request as failed.
  565.         DEBUGF 1,'K : error %d after %d bytes in request stage\n',eax,[.length+24h]
  566. ; If device is disconnected and data stage is enqueued, do nothing;
  567. ; data stage callback will do everything.
  568.         cmp     eax, 16
  569.         jnz     .common_error
  570.         cmp     [ecx+usb_device_data.Command.Flags], 0
  571.         js      .common_error
  572.         cmp     [ecx+usb_device_data.Command.Length], 0
  573.         jz      .common_error
  574.         ret     20
  575. .common_error:
  576. ; TODO: add recovery after STALL
  577.         mov     ecx, [.calldata]
  578.         mov     [ecx+usb_device_data.Status.Status], CSW_STATUS_FATAL
  579.         push    ebx esi
  580.         mov     esi, ecx
  581.         call    complete_request
  582.         pop     esi ebx
  583.         ret     20
  584. endp
  585.  
  586. ; Called when the second stage of request is completed,
  587. ; either successfully or not.
  588. proc request_callback2
  589. virtual at esp
  590.                 dd      ?       ; return address
  591. .pipe           dd      ?
  592. .status         dd      ?
  593. .buffer         dd      ?
  594. .length         dd      ?
  595. .calldata       dd      ?
  596. end virtual
  597. if DUMP_PACKETS
  598.         mov     eax, [.calldata]
  599.         mov     eax, [eax+usb_device_data.InPipe]
  600.         cmp     [.pipe], eax
  601.         jnz     @f
  602.         DEBUGF 1,'K : USBSTOR in:'
  603.         push    eax ecx
  604.         mov     eax, [.buffer+8]
  605.         mov     ecx, [.length+8]
  606.         call    debug_dump
  607.         pop     ecx eax
  608.         DEBUGF 1,'\n'
  609. @@:
  610. end if
  611. ; 1. Initialize.
  612.         mov     ecx, [.calldata]
  613.         mov     eax, [.status]
  614. ; 2. Test for error.
  615.         test    eax, eax
  616.         jnz     .error
  617. ; No error.
  618. ; If the previous stage was in same direction, do nothing; status request is already enqueued.
  619.         cmp     [ecx+usb_device_data.Command.Flags], 0
  620.         js      .nothing
  621. ..request_get_status:
  622. ; 3. Increment the stage.
  623.         mov     edx, [ecx+usb_device_data.RequestsQueue+request_queue_item.Next]
  624.         inc     [edx+request_queue_item.Stage]
  625. ; 4. Initiate USB transfer. If this fails, go to the error handler.
  626. ..enqueue_status:
  627.         lea     edx, [ecx+usb_device_data.Status]
  628.         stdcall USBNormalTransferAsync, [ecx+usb_device_data.InPipe], edx, command_status_wrapper.sizeof, request_callback3, ecx, 0
  629.         test    eax, eax
  630.         jz      .error
  631. .nothing:
  632.         ret     20
  633. .error:
  634. ; Error.
  635. ; 5. Print debug message and complete the request as failed.
  636.         DEBUGF 1,'K : error %d after %d bytes in data stage\n',eax,[.length+24h]
  637. ; If device is disconnected and data stage is enqueued, do nothing;
  638. ; status stage callback will do everything.
  639.         cmp     [ecx+usb_device_data.Command.Flags], 0
  640.         js      .nothing
  641.         jmp     request_callback1.common_error
  642. endp
  643.  
  644. ; Called when the third stage of request is completed,
  645. ; either successfully or not.
  646. proc request_callback3
  647. virtual at esp
  648.                 dd      ?       ; return address
  649. .pipe           dd      ?
  650. .status         dd      ?
  651. .buffer         dd      ?
  652. .length         dd      ?
  653. .calldata       dd      ?
  654. end virtual
  655. if DUMP_PACKETS
  656.         DEBUGF 1,'K : USBSTOR in:'
  657.         mov     eax, [.buffer]
  658.         mov     ecx, [.length]
  659.         call    debug_dump
  660.         DEBUGF 1,'\n'
  661. end if
  662. ; 1. Initialize.
  663.         mov     eax, [.status]
  664. ; 2. Test for error.
  665.         test    eax, eax
  666.         jnz     .transfer_error
  667. ; Transfer is OK.
  668. ; 3. Validate the status. Invalid status = fatal error.
  669.         push    ebx esi
  670.         mov     esi, [.calldata+8]
  671.         mov     ebx, [esi+usb_device_data.RequestsQueue+request_queue_item.Next]
  672.         cmp     [esi+usb_device_data.Status.Signature], 'USBS'
  673.         jnz     .invalid
  674.         mov     eax, [esi+usb_device_data.Command.Tag]
  675.         cmp     [esi+usb_device_data.Status.Tag], eax
  676.         jnz     .invalid
  677.         cmp     [esi+usb_device_data.Status.Status], CSW_STATUS_FATAL
  678.         ja      .invalid
  679. ; 4. The status block is valid. Check the status code.
  680.         jz      .complete
  681. ; 5. If this command was not REQUEST_SENSE, copy status data to safe place.
  682. ; Otherwise, the original command has failed, so restore the fail status.
  683.         cmp     byte [esi+usb_device_data.Command.Command], SCSI_REQUEST_SENSE
  684.         jz      .request_sense
  685.         mov     eax, [esi+usb_device_data.Status.LengthRest]
  686.         mov     [esi+usb_device_data.LengthRest], eax
  687.         cmp     [esi+usb_device_data.Status.Status], CSW_STATUS_FAIL
  688.         jz      .fail
  689. .complete:
  690.         call    complete_request
  691. .nothing:
  692.         pop     esi ebx
  693.         ret     20
  694. .request_sense:
  695.         mov     [esi+usb_device_data.Status.Status], CSW_STATUS_FAIL
  696.         jmp     .complete
  697. .invalid:
  698. ; 6. Invalid status block. Say error, set status to fatal and complete request.
  699.         push    esi
  700.         mov     esi, invresponse
  701.         call    SysMsgBoardStr
  702.         pop     esi
  703.         mov     [esi+usb_device_data.Status.Status], CSW_STATUS_FATAL
  704.         jmp     .complete
  705. .fail:
  706. ; 7. The command has failed.
  707. ; If this command was not REQUEST_SENSE, schedule the REQUEST_SENSE command
  708. ; to determine the reason of fail. Otherwise, assume that there is no error data.
  709.         cmp     [esi+usb_device_data.Command.Command], SCSI_REQUEST_SENSE
  710.         jz      .fail_request_sense
  711.         mov     [ebx+request_queue_item.ReqBuilder], request_sense_req
  712.         lea     eax, [esi+usb_device_data.Sense]
  713.         mov     [ebx+request_queue_item.Buffer], eax
  714.         call    request_stage1
  715.         test    eax, eax
  716.         jnz     .nothing
  717. .fail_request_sense:
  718.         DEBUGF 1,'K : fail during REQUEST SENSE\n'
  719.         mov     byte [esi+usb_device_data.Sense], 0
  720.         jmp     .complete
  721. .transfer_error:
  722. ; TODO: add recovery after STALL
  723.         DEBUGF 1,'K : error %d after %d bytes in status stage\n',eax,[.length+24h]
  724.         jmp     request_callback1.common_error
  725. endp
  726.  
  727. ; Builder for SCSI_REQUEST_SENSE request.
  728. ; edx = first argument = pointer to usb_device_data.Command,
  729. ; second argument = custom data given to queue_request (ignored).
  730. proc request_sense_req
  731.         mov     [edx+command_block_wrapper.Length], sense_data.sizeof
  732.         mov     [edx+command_block_wrapper.Flags], CBW_FLAG_IN
  733.         mov     byte [edx+command_block_wrapper.Command+0], SCSI_REQUEST_SENSE
  734.         mov     byte [edx+command_block_wrapper.Command+4], sense_data.sizeof
  735.         ret     8
  736. endp
  737.  
  738. ; This procedure is called when new mass-storage device is detected.
  739. ; It initializes the device.
  740. ; Technically, initialization implies sending several USB queries,
  741. ; so it is split in several procedures. The first is AddDevice,
  742. ; other are callbacks which will be called at some time in the future,
  743. ; when the device will respond.
  744. ; The general scheme:
  745. ; * AddDevice parses descriptors, opens pipes; if everything is ok,
  746. ;   AddDevice sends REQUEST_GETMAXLUN with callback known_lun_callback;
  747. ; * known_lun_callback allocates memory for LogicalDevices and sends
  748. ;   SCSI_TEST_UNIT_READY to all logical devices with test_unit_ready_callback;
  749. ; * test_unit_ready_callback checks whether the unit is ready;
  750. ;   if not, it repeats the same request several times;
  751. ;   if ok or there were too many attempts, it sends SCSI_INQUIRY with
  752. ;   callback inquiry_callback;
  753. ; * inquiry_callback checks that a logical device is a block device
  754. ;   and the unit was ready; if so, it notifies the kernel about new disk device.
  755. proc AddDevice
  756.         push    ebx esi
  757. virtual at esp
  758.                 rd      2       ; saved registers ebx, esi
  759.                 dd      ?       ; return address
  760. .pipe0          dd      ?       ; handle of the config pipe
  761. .config         dd      ?       ; pointer to config_descr
  762. .interface      dd      ?       ; pointer to interface_descr
  763. end virtual
  764. ; 1. Check device type. Currently only SCSI-command-set Bulk-only devices
  765. ; are supported.
  766. ; 1a. Get the subclass and the protocol. Since bInterfaceSubClass and
  767. ; bInterfaceProtocol are subsequent in interface_descr, just one
  768. ; memory reference is used for both.
  769.         mov     esi, [.interface]
  770.         xor     ebx, ebx
  771.         mov     cx, word [esi+interface_descr.bInterfaceSubClass]
  772. ; 1b. For Mass-storage SCSI-command-set Bulk-only devices subclass must be 6
  773. ; and protocol must be 50h. Check.
  774.         cmp     cx, 0x5006
  775.         jz      .known
  776. ; There are devices with subclass 5 which use the same protocol 50h.
  777. ; The difference is not important for the code except for this test,
  778. ; so allow them to proceed also.
  779.         cmp     cx, 0x5005
  780.         jz      .known
  781. ; 1c. If the device is unknown, print a message and go to 11c.
  782.         mov     esi, unkdevice
  783.         call    SysMsgBoardStr
  784.         jmp     .nothing
  785. ; 1d. If the device uses known command set, print a message and continue
  786. ; configuring.
  787. .known:
  788.         push    esi
  789.         mov     esi, okdevice
  790.         call    SysMsgBoardStr
  791.         pop     esi
  792. ; 2. Allocate memory for internal device data.
  793. ; 2a. Call the kernel.
  794.         mov     eax, usb_device_data.sizeof
  795.         call    Kmalloc
  796. ; 2b. Check return value.
  797.         test    eax, eax
  798.         jnz     @f
  799. ; 2c. If failed, say a message and go to 11c.
  800.         mov     esi, nomemory
  801.         call    SysMsgBoardStr
  802.         jmp     .nothing
  803. @@:
  804. ; 2d. If succeeded, zero the contents and continue configuring.
  805.         xchg    ebx, eax        ; ebx will point to usb_device_data
  806.         xor     eax, eax
  807.         mov     [ebx+usb_device_data.OutPipe], eax
  808.         mov     [ebx+usb_device_data.InPipe], eax
  809.         mov     [ebx+usb_device_data.MaxLUN], eax
  810.         mov     [ebx+usb_device_data.LogicalDevices], eax
  811.         mov     dword [ebx+usb_device_data.ConfigRequest], eax
  812.         mov     dword [ebx+usb_device_data.ConfigRequest+4], eax
  813.         mov     [ebx+usb_device_data.Status.Status], al
  814.         mov     [ebx+usb_device_data.DeviceDisconnected], al
  815. ; 2e. There is one reference: a connected USB device.
  816.         inc     eax
  817.         mov     [ebx+usb_device_data.NumReferences], eax
  818. ; 2f. Save handle of configuration pipe for reset recovery.
  819.         mov     eax, [.pipe0]
  820.         mov     [ebx+usb_device_data.ConfigPipe], eax
  821. ; 2g. Save the interface number for configuration requests.
  822.         mov     al, [esi+interface_descr.bInterfaceNumber]
  823.         mov     [ebx+usb_device_data.ConfigRequest+4], al
  824. ; 2h. Initialize common fields in command wrapper.
  825.         mov     [ebx+usb_device_data.Command.Signature], 'USBC'
  826.         mov     [ebx+usb_device_data.Command.Tag], 'xxxx'
  827. ; 2i. Initialize requests queue.
  828.         lea     eax, [ebx+usb_device_data.RequestsQueue]
  829.         mov     [eax+request_queue_item.Next], eax
  830.         mov     [eax+request_queue_item.Prev], eax
  831.         lea     ecx, [ebx+usb_device_data.QueueLock]
  832.         call    MutexInit
  833. ; Bulk-only mass storage devices use one OUT bulk endpoint for sending
  834. ; command/data and one IN bulk endpoint for receiving data/status.
  835. ; Look for those endpoints.
  836. ; 3. Get the upper bound of all descriptors' data.
  837.         mov     edx, [.config]  ; configuration descriptor
  838.         movzx   ecx, [edx+config_descr.wTotalLength]
  839.         add     edx, ecx
  840. ; 4. Loop over all descriptors until
  841. ; either end-of-data reached - this is fail
  842. ; or interface descriptor found - this is fail, all further data
  843. ;    correspond to that interface
  844. ; or both endpoint descriptors found.
  845. ; 4a. Loop start: esi points to the interface descriptor,
  846. .lookep:
  847. ; 4b. Get next descriptor.
  848.         movzx   ecx, byte [esi] ; the first byte of all descriptors is length
  849.         add     esi, ecx
  850. ; 4c. Check that at least two bytes are readable. The opposite is an error.
  851.         inc     esi
  852.         cmp     esi, edx
  853.         jae     .errorep
  854.         dec     esi
  855. ; 4d. Check that this descriptor is not interface descriptor. The opposite is
  856. ; an error.
  857.         cmp     byte [esi+endpoint_descr.bDescriptorType], INTERFACE_DESCR_TYPE
  858.         jz      .errorep
  859. ; 4e. Test whether this descriptor is an endpoint descriptor. If not, continue
  860. ; the loop.
  861.         cmp     byte [esi+endpoint_descr.bDescriptorType], ENDPOINT_DESCR_TYPE
  862.         jnz     .lookep
  863. ; 5. Check that the descriptor contains all required data and all data are
  864. ; readable. The opposite is an error.
  865.         cmp     byte [esi+endpoint_descr.bLength], endpoint_descr.sizeof
  866.         jb      .errorep
  867.         lea     ecx, [esi+endpoint_descr.sizeof]
  868.         cmp     ecx, edx
  869.         ja      .errorep
  870. ; 6. Check that the endpoint is bulk endpoint. The opposite is an error.
  871.         mov     cl, [esi+endpoint_descr.bmAttributes]
  872.         and     cl, 3
  873.         cmp     cl, BULK_PIPE
  874.         jnz     .errorep
  875. ; 7. Get the direction of this endpoint.
  876.         movzx   ecx, [esi+endpoint_descr.bEndpointAddress]
  877.         shr     ecx, 7
  878. ; 8. Test whether a pipe for this direction is already opened. If so, continue
  879. ; the loop.
  880.         cmp     [ebx+usb_device_data.OutPipe+ecx*4], 0
  881.         jnz     .lookep
  882. ; 9. Open pipe for this endpoint.
  883. ; 9a. Save registers.
  884.         push    ecx edx
  885. ; 9b. Load parameters from the descriptor.
  886.         movzx   ecx, [esi+endpoint_descr.bEndpointAddress]
  887.         movzx   edx, [esi+endpoint_descr.wMaxPacketSize]
  888.         movzx   eax, [esi+endpoint_descr.bInterval]     ; not used for USB1, may be important for USB2
  889. ; 9c. Call the kernel.
  890.         stdcall USBOpenPipe, [ebx+usb_device_data.ConfigPipe], ecx, edx, BULK_PIPE, eax
  891. ; 9d. Restore registers.
  892.         pop     edx ecx
  893. ; 9e. Check result. If failed, go to 11b.
  894.         test    eax, eax
  895.         jz      .free
  896. ; 9f. Save result.
  897.         mov     [ebx+usb_device_data.OutPipe+ecx*4], eax
  898. ; 10. Test whether the second pipe is already opened. If not, continue loop.
  899.         xor     ecx, 1
  900.         cmp     [ebx+usb_device_data.OutPipe+ecx*4], 0
  901.         jz      .lookep
  902.         jmp     .created
  903. ; 11. An error occured during processing endpoint descriptor.
  904. .errorep:
  905. ; 11a. Print a message.
  906.         DEBUGF 1,'K : error: invalid endpoint descriptor\n'
  907. .free:
  908. ; 11b. Free the allocated usb_device_data.
  909.         xchg    eax, ebx
  910.         call    Kfree
  911. .nothing:
  912. ; 11c. Return an error.
  913.         xor     eax, eax
  914.         jmp     .return
  915. .created:
  916. ; 12. Pipes are opened. Send GetMaxLUN control request.
  917.         lea     eax, [ebx+usb_device_data.ConfigRequest]
  918.         mov     byte [eax], 0A1h        ; class request from interface
  919.         mov     byte [eax+1], REQUEST_GETMAXLUN
  920.         mov     byte [eax+6], 1         ; transfer 1 byte
  921.         lea     ecx, [ebx+usb_device_data.MaxLUN]
  922. 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
  924. end if
  925.         stdcall 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.
  927.         xchg    eax, ebx
  928. .return:
  929.         pop     esi ebx
  930.         ret     12
  931. endp
  932.  
  933. ; This function is called when REQUEST_GETMAXLUN is done,
  934. ; either successful or unsuccessful.
  935. proc known_lun_callback
  936.         push    ebx esi
  937. virtual at esp
  938.                 rd      2       ; saved registers
  939.                 dd      ?       ; return address
  940. .pipe           dd      ?
  941. .status         dd      ?
  942. .buffer         dd      ?
  943. .length         dd      ?
  944. .calldata       dd      ?
  945. end virtual
  946. ; 1. Check the status. If the request failed, assume that MaxLUN is zero.
  947.         mov     ebx, [.calldata]
  948.         mov     eax, [.status]
  949.         test    eax, eax
  950.         jz      @f
  951.         DEBUGF 1, 'K : GETMAXLUN failed with status %d, assuming zero\n', eax
  952.         mov     [ebx+usb_device_data.MaxLUN], 0
  953. @@:
  954. ; 2. Allocate the memory for logical devices.
  955.         mov     eax, [ebx+usb_device_data.MaxLUN]
  956.         inc     eax
  957.         DEBUGF 1,'K : %d logical unit(s)\n',eax
  958.         imul    eax, usb_unit_data.sizeof
  959.         push    ebx
  960.         call    Kmalloc
  961.         pop     ebx
  962. ; If failed, print a message and do nothing.
  963.         test    eax, eax
  964.         jnz     @f
  965.         mov     esi, nomemory
  966.         call    SysMsgBoardStr
  967.         pop     esi ebx
  968.         ret     20
  969. @@:
  970.         mov     [ebx+usb_device_data.LogicalDevices], eax
  971. ; 3. Initialize logical devices and initiate TEST_UNIT_READY request.
  972.         xchg    esi, eax
  973.         xor     ecx, ecx
  974. .looplun:
  975.         mov     [esi+usb_unit_data.Parent], ebx
  976.         mov     [esi+usb_unit_data.LUN], cl
  977.         xor     eax, eax
  978.         mov     [esi+usb_unit_data.MediaPresent], al
  979.         mov     [esi+usb_unit_data.DiskDevice], eax
  980.         mov     [esi+usb_unit_data.SectorSize], eax
  981.         mov     [esi+usb_unit_data.UnitReadyAttempts], eax
  982.         push    ecx
  983.         call    GetTimerTicks
  984.         mov     [esi+usb_unit_data.TimerTicks], eax
  985.         stdcall queue_request, ebx, test_unit_ready_req, 0, test_unit_ready_callback, esi
  986.         pop     ecx
  987.         inc     ecx
  988.         add     esi, usb_unit_data.sizeof
  989.         cmp     ecx, [ebx+usb_device_data.MaxLUN]
  990.         jbe     .looplun
  991. ; 4. Return.
  992.         pop     esi ebx
  993.         ret     20
  994. endp
  995.  
  996. ; Builder for SCSI INQUIRY request.
  997. ; edx = first argument = pointer to usb_device_data.Command,
  998. ; second argument = custom data given to queue_request.
  999. proc inquiry_req
  1000.         mov     eax, [esp+8]
  1001.         mov     al, [eax+usb_unit_data.LUN]
  1002.         mov     [edx+command_block_wrapper.Length], inquiry_data.sizeof
  1003.         mov     [edx+command_block_wrapper.Flags], CBW_FLAG_IN
  1004.         mov     [edx+command_block_wrapper.LUN], al
  1005.         mov     byte [edx+command_block_wrapper.Command+0], SCSI_INQUIRY
  1006.         mov     byte [edx+command_block_wrapper.Command+4], inquiry_data.sizeof
  1007.         ret     8
  1008. endp
  1009.  
  1010. ; Called when SCSI INQUIRY request is completed.
  1011. proc inquiry_callback
  1012. ; 1. Check the status.
  1013.         mov     ecx, [esp+4]
  1014.         cmp     [ecx+usb_device_data.Status.Status], CSW_STATUS_OK
  1015.         jnz     .fail
  1016. ; 2. The command has completed successfully.
  1017. ; Print a message showing device type, ignore anything but block devices.
  1018.         mov     al, [ecx+usb_device_data.InquiryData.PeripheralDevice]
  1019.         and     al, 1Fh
  1020.         DEBUGF 1,'K : peripheral device type is %x\n',al
  1021.         test    al, al
  1022.         jnz     .nothing
  1023.         DEBUGF 1,'K : direct-access mass storage device detected\n'
  1024. ; 3. We have found a new disk device. Increment number of references.
  1025.         lock inc [ecx+usb_device_data.NumReferences]
  1026. ; Unfortunately, we are now in the context of the USB thread,
  1027. ; so we can't notify the kernel immediately: it would try to do something
  1028. ; with a new disk, those actions would be synchronous and would require
  1029. ; waiting for results of USB requests, but we need to exit this callback
  1030. ; to allow the USB thread to continue working and handling those requests.
  1031. ; 4. Thus, create a temporary kernel thread which would do it.
  1032.         mov     edx, [esp+8]
  1033.         push    ebx ecx esi edi
  1034.         movi    ebx, 1
  1035.         mov     ecx, new_disk_thread
  1036.         ; edx = parameter
  1037.         call    CreateThread
  1038.         pop     edi esi ecx ebx
  1039.         cmp     eax, -1
  1040.         jnz     .nothing
  1041. ; on error, reverse step 3
  1042.         lock dec [ecx+usb_device_data.NumReferences]
  1043. .nothing:
  1044.         ret     8
  1045. .fail:
  1046. ; 4. The command has failed. Print a message and do nothing.
  1047.         push    esi
  1048.         mov     esi, inquiry_fail
  1049.         call    SysMsgBoardStr
  1050.         pop     esi
  1051.         ret     8
  1052. endp
  1053.  
  1054. ; Builder for SCSI TEST_UNIT_READY request.
  1055. ; edx = first argument = pointer to usb_device_data.Command,
  1056. ; second argument = custom data given to queue_request.
  1057. proc test_unit_ready_req
  1058.         mov     eax, [esp+8]
  1059.         mov     al, [eax+usb_unit_data.LUN]
  1060.         mov     [edx+command_block_wrapper.Length], 0
  1061.         mov     [edx+command_block_wrapper.Flags], CBW_FLAG_IN
  1062.         mov     [edx+command_block_wrapper.LUN], al
  1063.         ret     8
  1064. endp
  1065.  
  1066. ; Called when SCSI TEST_UNIT_READY request is completed.
  1067. proc test_unit_ready_callback
  1068. virtual at esp
  1069.                 dd      ?       ; return address
  1070. .device         dd      ?
  1071. .calldata       dd      ?
  1072. end virtual
  1073. ; 1. Check the status.
  1074.         mov     ecx, [.device]
  1075.         mov     edx, [.calldata]
  1076.         cmp     [ecx+usb_device_data.Status.Status], CSW_STATUS_OK
  1077.         jnz     .fail
  1078. ; 2. The command has completed successfully,
  1079. ; possibly after some repetitions. Print a debug message showing
  1080. ; number and time of those. Remember that media is ready and go to 4.
  1081.         DEBUGF 1,'K : media is ready\n'
  1082.         call    GetTimerTicks
  1083.         sub     eax, [edx+usb_unit_data.TimerTicks]
  1084.         DEBUGF 1,'K : %d attempts, %d ticks\n',[edx+usb_unit_data.UnitReadyAttempts],eax
  1085.         inc     [edx+usb_unit_data.MediaPresent]
  1086.         jmp     .inquiry
  1087. .fail:
  1088. ; 3. The command has failed.
  1089. ; Retry the same request up to 3 times with 10ms delay;
  1090. ; if limit of retries is not reached, exit from the function.
  1091. ; Otherwise, go to 4.
  1092.         inc     [edx+usb_unit_data.UnitReadyAttempts]
  1093.         cmp     [edx+usb_unit_data.UnitReadyAttempts], 3
  1094.         jz      @f
  1095.         push    ecx edx esi
  1096.         movi    esi, 10
  1097.         call    Sleep
  1098.         pop     esi edx ecx
  1099.         stdcall queue_request, ecx, test_unit_ready_req, 0, test_unit_ready_callback, edx
  1100.         ret     8
  1101. @@:
  1102.         DEBUGF 1,'K : media not ready\n'
  1103. .inquiry:
  1104. ; 4. initiate INQUIRY request.
  1105.         lea     eax, [ecx+usb_device_data.InquiryData]
  1106.         stdcall queue_request, ecx, inquiry_req, eax, inquiry_callback, edx
  1107.         ret     8
  1108. endp
  1109.  
  1110. ; Temporary thread for initial actions with a new disk device.
  1111. proc new_disk_thread
  1112.         sub     esp, 32
  1113. virtual at esp
  1114. .name   rb      32      ; device name
  1115. .param  dd      ?       ; contents of edx at the moment of int 0x40/eax=51
  1116.         dd      ?       ; stack segment
  1117. end virtual
  1118. ; We are ready to notify the kernel about a new disk device.
  1119.         mov     esi, [.param]
  1120. ; 1. Generate name.
  1121. ; 1a. Find a free index.
  1122.         mov     ecx, free_numbers_lock
  1123.         call    MutexLock
  1124.         xor     eax, eax
  1125. @@:
  1126.         bsf     edx, [free_numbers+eax]
  1127.         jnz     @f
  1128.         add     eax, 4
  1129.         cmp     eax, 4*4
  1130.         jnz     @b
  1131.         call    MutexUnlock
  1132.         push    esi
  1133.         mov     esi, noindex
  1134.         call    SysMsgBoardStr
  1135.         pop     esi
  1136.         jmp     .drop_reference
  1137. @@:
  1138. ; 1b. Mark the index as busy.
  1139.         btr     [free_numbers+eax], edx
  1140.         lea     eax, [eax*8+edx]
  1141.         push    eax
  1142.         call    MutexUnlock
  1143.         pop     eax
  1144. ; 1c. Generate a name of the form "usbhd<index>" in the stack.
  1145.         mov     dword [esp], 'usbh'
  1146.         lea     edi, [esp+5]
  1147.         mov     byte [edi-1], 'd'
  1148.         push    eax
  1149.         push    -'0'
  1150.         movi    ecx, 10
  1151. @@:
  1152.         cdq
  1153.         div     ecx
  1154.         push    edx
  1155.         test    eax, eax
  1156.         jnz     @b
  1157. @@:
  1158.         pop     eax
  1159.         add     al, '0'
  1160.         stosb
  1161.         jnz     @b
  1162.         pop     ecx
  1163.         mov     edx, esp
  1164. ; 3d. Store the index in usb_unit_data to free it later.
  1165.         mov     [esi+usb_unit_data.DiskIndex], cl
  1166. ; 4. Notify the kernel about a new disk.
  1167. ; 4a. Add a disk.
  1168. ;       stdcall queue_request, ecx, read_capacity_req, eax, read_capacity_callback, eax
  1169.         stdcall DiskAdd, disk_functions, edx, esi, 0
  1170.         mov     ebx, eax
  1171. ; 4b. If it failed, release the index and do nothing.
  1172.         test    eax, eax
  1173.         jz      .free_index
  1174. ; 4c. Notify the kernel that a media is present.
  1175.         stdcall DiskMediaChanged, eax, 1
  1176. ; 5. Lock the requests queue, check that device is not disconnected,
  1177. ; store the disk handle, unlock the requests queue.
  1178.         mov     ecx, [esi+usb_unit_data.Parent]
  1179.         add     ecx, usb_device_data.QueueLock
  1180.         call    MutexLock
  1181.         cmp     byte [ecx+usb_device_data.DeviceDisconnected-usb_device_data.QueueLock], 0
  1182.         jnz     .disconnected
  1183.         mov     [esi+usb_unit_data.DiskDevice], ebx
  1184.         call    MutexUnlock
  1185.         jmp     .exit
  1186. .disconnected:
  1187.         call    MutexUnlock
  1188.         stdcall disk_close, ebx
  1189.         jmp     .exit
  1190. .free_index:
  1191.         mov     ecx, free_numbers_lock
  1192.         call    MutexLock
  1193.         movzx   eax, [esi+usb_unit_data.DiskIndex]
  1194.         bts     [free_numbers], eax
  1195.         call    MutexUnlock
  1196. .drop_reference:
  1197.         mov     esi, [esi+usb_unit_data.Parent]
  1198.         lock dec [esi+usb_device_data.NumReferences]
  1199.         jnz     .exit
  1200.         mov     eax, [esi+usb_device_data.LogicalDevices]
  1201.         call    Kfree
  1202.         xchg    eax, esi
  1203.         call    Kfree
  1204. .exit:
  1205.         or      eax, -1
  1206.         int     0x40
  1207. endp
  1208.  
  1209. ; This function is called when the device is disconnected.
  1210. proc DeviceDisconnected
  1211.         push    ebx esi
  1212. virtual at esp
  1213.         rd      2       ; saved registers
  1214.         dd      ?       ; return address
  1215. .device dd      ?
  1216. end virtual
  1217. ; 1. Say a message.
  1218.         mov     esi, disconnectmsg
  1219.         call    SysMsgBoardStr
  1220. ; 2. Lock the requests queue, set .DeviceDisconnected to 1,
  1221. ; unlock the requests queue.
  1222. ; Locking is required for synchronization with queue_request:
  1223. ; all USB callbacks are executed in the same thread and are
  1224. ; synchronized automatically, but queue_request can be running
  1225. ; from any thread which wants to do something with a filesystem.
  1226. ; Without locking, it would be possible that queue_request has
  1227. ; been started, has checked that device is not yet disconnected,
  1228. ; then DeviceDisconnected completes and all handles become invalid,
  1229. ; then queue_request tries to use them.
  1230.         mov     esi, [.device]
  1231.         lea     ecx, [esi+usb_device_data.QueueLock]
  1232.         call    MutexLock
  1233.         mov     [esi+usb_device_data.DeviceDisconnected], 1
  1234.         call    MutexUnlock
  1235. ; 3. Drop one reference to the structure and check whether
  1236. ; that was the last reference.
  1237.         lock dec [esi+usb_device_data.NumReferences]
  1238.         jz      .free
  1239. ; 4. If not, there are some additional references due to disk devices;
  1240. ; notify the kernel that those disks are deleted.
  1241. ; Note that new disks cannot be added while we are looping here,
  1242. ; because new_disk_thread checks for .DeviceDisconnected.
  1243.         mov     ebx, [esi+usb_device_data.MaxLUN]
  1244.         mov     esi, [esi+usb_device_data.LogicalDevices]
  1245.         inc     ebx
  1246. .diskdel:
  1247.         mov     eax, [esi+usb_unit_data.DiskDevice]
  1248.         test    eax, eax
  1249.         jz      @f
  1250.         stdcall DiskDel, eax
  1251. @@:
  1252.         add     esi, usb_unit_data.sizeof
  1253.         dec     ebx
  1254.         jnz     .diskdel
  1255. ; 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.
  1257. .return:
  1258.         pop     esi ebx
  1259.         ret     4
  1260. ; 5. If there are no disk devices, free all resources which were allocated.
  1261. .free:
  1262.         mov     eax, [esi+usb_device_data.LogicalDevices]
  1263.         test    eax, eax
  1264.         jz      @f
  1265.         call    Kfree
  1266. @@:
  1267.         xchg    eax, esi
  1268.         call    Kfree
  1269.         jmp     .return
  1270. endp
  1271.  
  1272. ; Disk functions.
  1273. DISK_STATUS_OK              = 0 ; success
  1274. DISK_STATUS_GENERAL_ERROR   = -1; if no other code is suitable
  1275. DISK_STATUS_INVALID_CALL    = 1 ; invalid input parameters
  1276. DISK_STATUS_NO_MEDIA        = 2 ; no media present
  1277. DISK_STATUS_END_OF_MEDIA    = 3 ; end of media while reading/writing data
  1278.  
  1279. ; Called when all operations with the given disk are done.
  1280. proc disk_close
  1281.         push    ebx esi
  1282. virtual at esp
  1283.         rd      2       ; saved registers
  1284.         dd      ?       ; return address
  1285. .userdata       dd      ?
  1286. end virtual
  1287.         mov     esi, [.userdata]
  1288.         mov     ecx, free_numbers_lock
  1289.         call    MutexLock
  1290.         movzx   eax, [esi+usb_unit_data.DiskIndex]
  1291.         bts     [free_numbers], eax
  1292.         call    MutexUnlock
  1293.         mov     esi, [esi+usb_unit_data.Parent]
  1294.         lock dec [esi+usb_device_data.NumReferences]
  1295.         jnz     .nothing
  1296.         mov     eax, [esi+usb_device_data.LogicalDevices]
  1297.         call    Kfree
  1298.         xchg    eax, esi
  1299.         call    Kfree
  1300. .nothing:
  1301.         pop     esi ebx
  1302.         ret     4
  1303. endp
  1304.  
  1305. ; Returns sector size, capacity and flags of the media.
  1306. proc disk_querymedia stdcall uses ebx esi edi, \
  1307.         userdata:dword, mediainfo:dword
  1308. ; 1. Create event for waiting.
  1309.         xor     esi, esi
  1310.         xor     ecx, ecx
  1311.         call    CreateEvent
  1312.         test    eax, eax
  1313.         jz      .generic_fail
  1314.         push    eax
  1315.         push    edx
  1316.         push    ecx
  1317.         push    0
  1318.         push    0
  1319. virtual at ebp-.localsize
  1320. .locals:
  1321. ; two following dwords are the output of READ_CAPACITY
  1322. .LastLBABE      dd      ?
  1323. .SectorSizeBE   dd      ?
  1324. .Status         dd      ?
  1325. ; two following dwords identify an event
  1326. .event_code     dd      ?
  1327. .event          dd      ?
  1328.                 rd      3       ; saved registers
  1329. .localsize = $ - .locals
  1330.                 dd      ?       ; saved ebp
  1331.                 dd      ?       ; return address
  1332. .userdata       dd      ?
  1333. .mediainfo      dd      ?
  1334. end virtual
  1335. ; 2. Initiate SCSI READ_CAPACITY request.
  1336.         mov     eax, [userdata]
  1337.         mov     ecx, [eax+usb_unit_data.Parent]
  1338.         mov     edx, esp
  1339.         stdcall queue_request, ecx, read_capacity_req, edx, read_capacity_callback, edx
  1340. ; 3. Wait for event. This destroys it.
  1341.         mov     eax, [.event]
  1342.         mov     ebx, [.event_code]
  1343.         call    WaitEvent
  1344. ; 4. Get the status and results.
  1345.         pop     ecx
  1346.         bswap   ecx     ; .LastLBA
  1347.         pop     edx
  1348.         bswap   edx     ; .SectorSize
  1349.         pop     eax     ; .Status
  1350. ; 5. If the request has completed successfully, store results.
  1351.         test    eax, eax
  1352.         jnz     @f
  1353.         DEBUGF 1,'K : sector size is %d, last sector is %d\n',edx,ecx
  1354.         mov     ebx, [mediainfo]
  1355.         mov     [ebx], eax      ; flags = 0
  1356.         mov     [ebx+4], edx    ; sectorsize
  1357.         add     ecx, 1
  1358.         adc     eax, 0
  1359.         mov     [ebx+8], ecx
  1360.         mov     [ebx+12], eax   ; capacity
  1361.         mov     eax, [userdata]
  1362.         mov     [eax+usb_unit_data.SectorSize], edx
  1363.         xor     eax, eax
  1364. @@:
  1365. ; 6. Restore the stack and return.
  1366.         pop     ecx
  1367.         pop     ecx
  1368.         ret
  1369. .generic_fail:
  1370.         or      eax, -1
  1371.         ret
  1372. endp
  1373.  
  1374. ; Builder for SCSI READ_CAPACITY request.
  1375. ; edx = first argument = pointer to usb_device_data.Command,
  1376. ; second argument = custom data given to queue_request,
  1377. ; pointer to disk_querymedia.locals.
  1378. proc read_capacity_req
  1379.         mov     eax, [esp+8]
  1380.         mov     eax, [eax+disk_querymedia.userdata-disk_querymedia.locals]
  1381.         mov     al, [eax+usb_unit_data.LUN]
  1382.         mov     [edx+command_block_wrapper.Length], 8
  1383.         mov     [edx+command_block_wrapper.Flags], CBW_FLAG_IN
  1384.         mov     [edx+command_block_wrapper.LUN], al
  1385.         mov     byte [edx+command_block_wrapper.Command+0], SCSI_READ_CAPACITY
  1386.         ret     8
  1387. endp
  1388.  
  1389. ; Called when SCSI READ_CAPACITY request is completed.
  1390. proc read_capacity_callback
  1391. ; Transform the status to return value of disk_querymedia
  1392. ; and set the event.
  1393.         mov     ecx, [esp+4]
  1394.         xor     eax, eax
  1395.         cmp     [ecx+usb_device_data.Status.Status], al
  1396.         jz      @f
  1397.         or      eax, -1
  1398. @@:
  1399.         mov     ecx, [esp+8]
  1400.         mov     [ecx+disk_querymedia.Status-disk_querymedia.locals], eax
  1401.         push    ebx esi edi
  1402.         mov     eax, [ecx+disk_querymedia.event-disk_querymedia.locals]
  1403.         mov     ebx, [ecx+disk_querymedia.event_code-disk_querymedia.locals]
  1404.         xor     edx, edx
  1405.         xor     esi, esi
  1406.         call    RaiseEvent
  1407.         pop     edi esi ebx
  1408.         ret     8
  1409. endp
  1410.  
  1411. disk_write:
  1412.         mov     al, SCSI_WRITE10
  1413.         jmp     disk_read_write
  1414.  
  1415. disk_read:
  1416.         mov     al, SCSI_READ10
  1417.  
  1418. ; Reads from the device or writes to the device.
  1419. proc disk_read_write stdcall uses ebx esi edi, \
  1420.         userdata:dword, buffer:dword, startsector:qword, numsectors:dword
  1421. ; 1. Initialize.
  1422.         push    eax     ; .command
  1423.         mov     eax, [userdata]
  1424.         mov     eax, [eax+usb_unit_data.SectorSize]
  1425.         push    eax     ; .SectorSize
  1426.         push    0       ; .processed
  1427.         mov     eax, [numsectors]
  1428.         mov     eax, [eax]
  1429. ; 2. The transfer length for SCSI_{READ,WRITE}10 commands can not be greater
  1430. ; than 0xFFFF, so split the request to slices with <= 0xFFFF sectors.
  1431. max_sectors_at_time = 0xFFFF
  1432. .split:
  1433.         push    eax     ; .length_rest
  1434.         cmp     eax, max_sectors_at_time
  1435.         jb      @f
  1436.         mov     eax, max_sectors_at_time
  1437. @@:
  1438.         sub     [esp], eax
  1439.         push    eax     ; .length_cur
  1440. ; 3. startsector must fit in 32 bits, otherwise abort the request.
  1441.         cmp     dword [startsector+4], 0
  1442.         jnz     .generic_fail
  1443. ; 4. Create event for waiting.
  1444.         xor     esi, esi
  1445.         xor     ecx, ecx
  1446.         call    CreateEvent
  1447.         test    eax, eax
  1448.         jz      .generic_fail
  1449.         push    eax     ; .event
  1450.         push    edx     ; .event_code
  1451.         push    ecx     ; .status
  1452. virtual at ebp-.localsize
  1453. .locals:
  1454. .status         dd      ?
  1455. .event_code     dd      ?
  1456. .event          dd      ?
  1457. .length_cur     dd      ?
  1458. .length_rest    dd      ?
  1459. .processed      dd      ?
  1460. .SectorSize     dd      ?
  1461. .command        db      ?
  1462.                 rb      3
  1463.                 rd      3       ; saved registers
  1464. .localsize = $ - .locals
  1465.                 dd      ?       ; saved ebp
  1466.                 dd      ?       ; return address
  1467. .userdata       dd      ?
  1468. .buffer         dd      ?
  1469. .startsector    dq      ?
  1470. .numsectors     dd      ?
  1471. end virtual
  1472. ; 5. Initiate SCSI READ10 or WRITE10 request.
  1473.         mov     eax, [userdata]
  1474.         mov     ecx, [eax+usb_unit_data.Parent]
  1475.         stdcall queue_request, ecx, read_write_req, [buffer], read_write_callback, esp
  1476. ; 6. Wait for event. This destroys it.
  1477.         mov     eax, [.event]
  1478.         mov     ebx, [.event_code]
  1479.         call    WaitEvent
  1480. ; 7. Get the status. If the operation has failed, abort.
  1481.         pop     eax     ; .status
  1482.         pop     ecx ecx ; cleanup .event_code, .event
  1483.         pop     ecx     ; .length_cur
  1484.         test    eax, eax
  1485.         jnz     .return
  1486. ; 8. Otherwise, continue the loop started at step 2.
  1487.         add     dword [startsector], ecx
  1488.         adc     dword [startsector+4], eax
  1489.         imul    ecx, [.SectorSize]
  1490.         add     [buffer], ecx
  1491.         pop     eax
  1492.         test    eax, eax
  1493.         jnz     .split
  1494.         push    eax
  1495. .return:
  1496. ; 9. Restore the stack, store .processed to [numsectors], return.
  1497.         pop     ecx     ; .length_rest
  1498.         pop     ecx     ; .processed
  1499.         mov     edx, [numsectors]
  1500.         mov     [edx], ecx
  1501.         pop     ecx     ; .SectorSize
  1502.         pop     ecx     ; .command
  1503.         ret
  1504. .generic_fail:
  1505.         or      eax, -1
  1506.         pop     ecx     ; .length_cur
  1507.         jmp     .return
  1508. endp
  1509.  
  1510. ; Builder for SCSI READ10 or WRITE10 request.
  1511. ; edx = first argument = pointer to usb_device_data.Command,
  1512. ; second argument = custom data given to queue_request,
  1513. ; pointer to disk_read_write.locals.
  1514. proc read_write_req
  1515.         mov     eax, [esp+8]
  1516.         mov     ecx, [eax+disk_read_write.userdata-disk_read_write.locals]
  1517.         mov     cl, [ecx+usb_unit_data.LUN]
  1518.         mov     [edx+command_block_wrapper.LUN], cl
  1519.         mov     ecx, [eax+disk_read_write.length_cur-disk_read_write.locals]
  1520.         imul    ecx, [eax+disk_read_write.SectorSize-disk_read_write.locals]
  1521.         mov     [edx+command_block_wrapper.Length], ecx
  1522.         mov     cl, [eax+disk_read_write.command-disk_read_write.locals]
  1523.         mov     [edx+command_block_wrapper.Flags], CBW_FLAG_OUT
  1524.         cmp     cl, SCSI_READ10
  1525.         jnz     @f
  1526.         mov     [edx+command_block_wrapper.Flags], CBW_FLAG_IN
  1527. @@:
  1528.         mov     byte [edx+command_block_wrapper.Command], cl
  1529.         mov     ecx, dword [eax+disk_read_write.startsector-disk_read_write.locals]
  1530.         bswap   ecx
  1531.         mov     dword [edx+command_block_wrapper.Command+2], ecx
  1532.         mov     ecx, [eax+disk_read_write.length_cur-disk_read_write.locals]
  1533.         xchg    cl, ch
  1534.         mov     word [edx+command_block_wrapper.Command+7], cx
  1535.         ret     8
  1536. endp
  1537.  
  1538. ; Called when SCSI READ10 or WRITE10 request is completed.
  1539. proc read_write_callback
  1540. ; 1. Initialize.
  1541.         push    ebx esi edi
  1542. virtual at esp
  1543.         rd      3       ; saved registers
  1544.         dd      ?       ; return address
  1545. .device         dd      ?
  1546. .calldata       dd      ?
  1547. end virtual
  1548.         mov     ecx, [.device]
  1549.         mov     esi, [.calldata]
  1550. ; 2. Get the number of sectors which were read.
  1551. ; If the status is OK or FAIL, the field .LengthRest is valid.
  1552. ; Otherwise, it is invalid, so assume zero sectors.
  1553.         xor     eax, eax
  1554.         cmp     [ecx+usb_device_data.Status.Status], CSW_STATUS_FAIL
  1555.         ja      .sectors_calculated
  1556.         mov     eax, [ecx+usb_device_data.LengthRest]
  1557.         xor     edx, edx
  1558.         div     [esi+disk_read_write.SectorSize-disk_read_write.locals]
  1559.         test    edx, edx
  1560.         jz      @f
  1561.         inc     eax
  1562. @@:
  1563.         mov     edx, eax
  1564.         mov     eax, [esi+disk_read_write.length_cur-disk_read_write.locals]
  1565.         sub     eax, edx
  1566.         jae     .sectors_calculated
  1567.         xor     eax, eax
  1568. .sectors_calculated:
  1569. ; 3. Increase the total number of processed sectors.
  1570.         add     [esi+disk_read_write.processed-disk_read_write.locals], eax
  1571. ; 4. Set status to OK if all sectors were read, to ERROR otherwise.
  1572.         cmp     eax, [esi+disk_read_write.length_cur-disk_read_write.locals]
  1573.         setz    al
  1574.         movzx   eax, al
  1575.         dec     eax
  1576.         mov     [esi+disk_read_write.status-disk_read_write.locals], eax
  1577. ; 5. Set the event.
  1578.         mov     eax, [esi+disk_read_write.event-disk_read_write.locals]
  1579.         mov     ebx, [esi+disk_read_write.event_code-disk_read_write.locals]
  1580.         xor     edx, edx
  1581.         xor     esi, esi
  1582.         call    RaiseEvent
  1583. ; 6. Return.
  1584.         pop     edi esi ebx
  1585.         ret     8
  1586. endp
  1587.  
  1588. ; strings
  1589. my_driver       db      'usbstor',0
  1590. disconnectmsg   db      'K : USB mass storage device disconnected',13,10,0
  1591. nomemory        db      'K : no memory',13,10,0
  1592. unkdevice       db      'K : unknown mass storage device',13,10,0
  1593. okdevice        db      'K : USB mass storage device detected',13,10,0
  1594. transfererror   db      'K : USB transfer error, disabling mass storage',13,10,0
  1595. invresponse     db      'K : invalid response from mass storage device',13,10,0
  1596. fatalerr        db      'K : mass storage device reports fatal error',13,10,0
  1597. inquiry_fail    db      'K : INQUIRY command failed',13,10,0
  1598. ;read_capacity_fail db  'K : READ CAPACITY command failed',13,10,0
  1599. ;read_fail      db      'K : READ command failed',13,10,0
  1600. noindex         db      'K : failed to generate disk name',13,10,0
  1601.  
  1602. ; Exported variable: kernel API version.
  1603. align 4
  1604. version dd      50005h
  1605. ; Structure with callback functions.
  1606. usb_functions:
  1607.         dd      usb_functions_end - usb_functions
  1608.         dd      AddDevice
  1609.         dd      DeviceDisconnected
  1610. usb_functions_end:
  1611.  
  1612. disk_functions:
  1613.         dd      disk_functions_end - disk_functions
  1614.         dd      disk_close
  1615.         dd      0       ; closemedia
  1616.         dd      disk_querymedia
  1617.         dd      disk_read
  1618.         dd      disk_write
  1619.         dd      0       ; flush
  1620.         dd      0       ; adjust_cache_size: use default cache
  1621. disk_functions_end:
  1622.  
  1623. free_numbers_lock       rd      3
  1624. ; 128 devices should be enough for everybody
  1625. free_numbers    dd      -1, -1, -1, -1
  1626.  
  1627. ; for DEBUGF macro
  1628. include_debug_strings
  1629.  
  1630. ; for uninitialized data
  1631. section '.data' data readable writable align 16
  1632.