Subversion Repositories Kolibri OS

Rev

Rev 3725 | Rev 4265 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ; Implementation of the USB protocol for device enumeration.
  2. ; Manage a USB device when it becomes ready for USB commands:
  3. ; configure, enumerate, load the corresponding driver(s),
  4. ; pass device information to the driver.
  5.  
  6. ; =============================================================================
  7. ; ================================= Constants =================================
  8. ; =============================================================================
  9. ; USB standard request codes
  10. USB_GET_STATUS        = 0
  11. USB_CLEAR_FEATURE     = 1
  12. USB_SET_FEATURE       = 3
  13. USB_SET_ADDRESS       = 5
  14. USB_GET_DESCRIPTOR    = 6
  15. USB_SET_DESCRIPTOR    = 7
  16. USB_GET_CONFIGURATION = 8
  17. USB_SET_CONFIGURATION = 9
  18. USB_GET_INTERFACE     = 10
  19. USB_SET_INTERFACE     = 11
  20. USB_SYNCH_FRAME       = 12
  21.  
  22. ; USB standard descriptor types
  23. USB_DEVICE_DESCR             = 1
  24. USB_CONFIG_DESCR             = 2
  25. USB_STRING_DESCR             = 3
  26. USB_INTERFACE_DESCR          = 4
  27. USB_ENDPOINT_DESCR           = 5
  28. USB_DEVICE_QUALIFIER_DESCR   = 6
  29. USB_OTHER_SPEED_CONFIG_DESCR = 7
  30. USB_INTERFACE_POWER_DESCR    = 8
  31.  
  32. ; Possible speeds of USB devices
  33. USB_SPEED_FS = 0 ; full-speed
  34. USB_SPEED_LS = 1 ; low-speed
  35. USB_SPEED_HS = 2 ; high-speed
  36.  
  37. ; Compile-time setting. If set, the code will dump all descriptors as they are
  38. ; read to the debug board.
  39. USB_DUMP_DESCRIPTORS = 1
  40.  
  41. ; =============================================================================
  42. ; ================================ Structures =================================
  43. ; =============================================================================
  44. ; USB descriptors. See USB specification for detailed explanations.
  45. ; First two bytes of every descriptor have the same meaning.
  46. struct usb_descr
  47. bLength                 db      ?
  48. ; Size of this descriptor in bytes
  49. bDescriptorType         db      ?
  50. ; One of USB_*_DESCR constants.
  51. ends
  52.  
  53. ; USB device descriptor
  54. struct usb_device_descr usb_descr
  55. bcdUSB                  dw      ?
  56. ; USB Specification Release number in BCD, e.g. 110h = USB 1.1
  57. bDeviceClass            db      ?
  58. ; USB Device Class Code
  59. bDeviceSubClass         db      ?
  60. ; USB Device Subclass Code
  61. bDeviceProtocol         db      ?
  62. ; USB Device Protocol Code
  63. bMaxPacketSize0         db      ?
  64. ; Maximum packet size for zero endpoint
  65. idVendor                dw      ?
  66. ; Vendor ID
  67. idProduct               dw      ?
  68. ; Product ID
  69. bcdDevice               dw      ?
  70. ; Device release number in BCD
  71. iManufacturer           db      ?
  72. ; Index of string descriptor describing manufacturer
  73. iProduct                db      ?
  74. ; Index of string descriptor describing product
  75. iSerialNumber           db      ?
  76. ; Index of string descriptor describing serial number
  77. bNumConfigurations      db      ?
  78. ; Number of possible configurations
  79. ends
  80.  
  81. ; USB configuration descriptor
  82. struct usb_config_descr usb_descr
  83. wTotalLength            dw      ?
  84. ; Total length of data returned for this configuration
  85. bNumInterfaces          db      ?
  86. ; Number of interfaces in this configuration
  87. bConfigurationValue     db      ?
  88. ; Value for SET_CONFIGURATION control request
  89. iConfiguration          db      ?
  90. ; Index of string descriptor describing this configuration
  91. bmAttributes            db      ?
  92. ; Bit 6 is SelfPowered, bit 5 is RemoteWakeupSupported,
  93. ; bit 7 must be 1, other bits must be 0
  94. bMaxPower               db      ?
  95. ; Maximum power consumption from the bus in 2mA units
  96. ends
  97.  
  98. ; USB interface descriptor
  99. struct usb_interface_descr usb_descr
  100. ; The following two fields work in pair. Sometimes one interface can work
  101. ; in different modes; e.g. videostream from web-cameras requires different
  102. ; bandwidth depending on resolution/quality/compression settings.
  103. ; Each mode of each interface has its own descriptor with its own endpoints
  104. ; following; all descriptors for one interface have the same bInterfaceNumber,
  105. ; and different bAlternateSetting.
  106. ; By default, any interface operates in mode with bAlternateSetting = 0.
  107. ; Often this is the only mode. If there are another modes, the active mode
  108. ; is selected by SET_INTERFACE(bAlternateSetting) control request.
  109. bInterfaceNumber        db      ?
  110. bAlternateSetting       db      ?
  111. bNumEndpoints           db      ?
  112. ; Number of endpoints used by this interface, excluding zero endpoint
  113. bInterfaceClass         db      ?
  114. ; USB Interface Class Code
  115. bInterfaceSubClass      db      ?
  116. ; USB Interface Subclass Code
  117. bInterfaceProtocol      db      ?
  118. ; USB Interface Protocol Code
  119. iInterface              db      ?
  120. ; Index of string descriptor describing this interface
  121. ends
  122.  
  123. ; USB endpoint descriptor
  124. struct usb_endpoint_descr usb_descr
  125. bEndpointAddress        db      ?
  126. ; Lower 4 bits form endpoint number,
  127. ; upper bit is 0 for OUT endpoints and 1 for IN endpoints,
  128. ; other bits must be zero
  129. bmAttributes            db      ?
  130. ; Lower 2 bits form transfer type, one of *_PIPE,
  131. ; other bits must be zero for non-isochronous endpoints;
  132. ; refer to the USB specification for meaning in isochronous case
  133. wMaxPacketSize          dw      ?
  134. ; Lower 11 bits form maximum packet size,
  135. ; next two bits specify the number of additional transactions per microframe
  136. ; for high-speed periodic endpoints, other bits must be zero.
  137. bInterval               db      ?
  138. ; Interval for polling endpoint for data transfers.
  139. ; Isochronous and high-speed interrupt endpoints: poll every 2^(bInterval-1)
  140. ; (micro)frames
  141. ; Full/low-speed interrupt endpoints: poll every bInterval frames
  142. ; High-speed bulk/control OUT endpoints: maximum NAK rate
  143. ends
  144.  
  145. ; =============================================================================
  146. ; =================================== Code ====================================
  147. ; =============================================================================
  148.  
  149. ; When a new device is ready to be configured, a controller-specific code
  150. ; calls usb_new_device.
  151. ; The sequence of further actions:
  152. ; * open pipe for the zero endpoint (usb_new_device);
  153. ;   maximum packet size is not known yet, but it must be at least 8 bytes,
  154. ;   so it is safe to send packets with <= 8 bytes
  155. ; * issue SET_ADDRESS control request (usb_new_device)
  156. ; * set the new device address in the pipe (usb_set_address_callback)
  157. ; * notify a controller-specific code that initialization of other ports
  158. ;   can be started (usb_set_address_callback)
  159. ; * issue GET_DESCRIPTOR control request for first 8 bytes of device descriptor
  160. ;   (usb_after_set_address)
  161. ; * first 8 bytes of device descriptor contain the true packet size for zero
  162. ;   endpoint, so set the true packet size (usb_get_descr8_callback)
  163. ; * first 8 bytes of a descriptor contain the full size of this descriptor,
  164. ;   issue GET_DESCRIPTOR control request for the full device descriptor
  165. ;   (usb_after_set_endpoint_size)
  166. ; * issue GET_DESCRIPTOR control request for first 8 bytes of configuration
  167. ;   descriptor (usb_get_descr_callback)
  168. ; * issue GET_DESCRIPTOR control request for full configuration descriptor
  169. ;   (usb_know_length_callback)
  170. ; * issue SET_CONFIGURATION control request (usb_set_config_callback)
  171. ; * parse configuration descriptor, load the corresponding driver(s),
  172. ;   pass the configuration descriptor to the driver and let the driver do
  173. ;   the further work (usb_got_config_callback)
  174.  
  175. ; This function is called from controller-specific part
  176. ; when a new device is ready to be configured.
  177. ; in: ecx -> pseudo-pipe, part of usb_pipe
  178. ; in: esi -> usb_controller
  179. ; in: [esi+usb_controller.ResettingHub] is the pointer to usb_hub for device,
  180. ;     NULL if the device is connected to the root hub
  181. ; in: [esi+usb_controller.ResettingPort] is the port for the device, zero-based
  182. ; in: [esi+usb_controller.ResettingSpeed] is the speed of the device, one of
  183. ;     USB_SPEED_xx.
  184. ; out: eax = 0 <=> failed, the caller should disable the port.
  185. proc usb_new_device
  186.         push    ebx edi         ; save used registers to be stdcall
  187. ; 1. Allocate resources. Any device uses the following resources:
  188. ; - device address in the bus
  189. ; - memory for device data
  190. ; - pipe for zero endpoint
  191. ; If some allocation fails, we must undo our actions. Closing the pipe
  192. ; is a hard task, so we avoid it and open the pipe as the last resource.
  193. ; The order for other two allocations is quite arbitrary.
  194. ; 1a. Allocate a bus address.
  195.         push    ecx
  196.         call    usb_set_address_request
  197.         pop     ecx
  198. ; 1b. If failed, just return zero.
  199.         test    eax, eax
  200.         jz      .nothing
  201. ; 1c. Allocate memory for device data.
  202. ; For now, we need sizeof.usb_device_data and extra 8 bytes for GET_DESCRIPTOR
  203. ; input and output, see usb_after_set_address. Later we will reallocate it
  204. ; to actual size needed for descriptors.
  205.         push    sizeof.usb_device_data + 8
  206.         pop     eax
  207.         push    ecx
  208.         call    malloc
  209.         pop     ecx
  210. ; 1d. If failed, free the bus address and return zero.
  211.         test    eax, eax
  212.         jz      .nomemory
  213. ; 1e. Open pipe for endpoint zero.
  214. ; For now, we do not know the actual maximum packet size;
  215. ; for full-speed devices it can be any of 8, 16, 32, 64 bytes,
  216. ; low-speed devices must have 8 bytes, high-speed devices must have 64 bytes.
  217. ; Thus, we must use some fake "maximum packet size" until the actual size
  218. ; will be known. However, the maximum packet size must be at least 8, and
  219. ; initial stages of the configuration process involves only packets of <= 8
  220. ; bytes, they will be transferred correctly as long as
  221. ; the fake "maximum packet size" is also at least 8.
  222. ; Thus, any number >= 8 is suitable for actual hardware.
  223. ; However, software emulation of EHCI in VirtualBox assumes that high-speed
  224. ; control transfers are those originating from pipes with max packet size = 64,
  225. ; even on early stages of the configuration process. This is incorrect,
  226. ; but we have no specific preferences, so let VirtualBox be happy and use 64
  227. ; as the fake "maximum packet size".
  228.         push    eax
  229. ; We will need many zeroes.
  230. ; "push edi" is one byte, "push 0" is two bytes; save space, use edi.
  231.         xor     edi, edi
  232.         stdcall usb_open_pipe, ecx, edi, 64, edi, edi
  233. ; Put pointer to pipe into ebx. "xchg eax,reg" is one byte, mov is two bytes.
  234.         xchg    eax, ebx
  235.         pop     eax
  236. ; 1f. If failed, free the memory, the bus address and return zero.
  237.         test    ebx, ebx
  238.         jz      .freememory
  239. ; 2. Store pointer to device data in the pipe structure.
  240.         mov     [ebx+usb_pipe.DeviceData], eax
  241. ; 3. Init device data, using usb_controller.Resetting* variables.
  242.         mov     [eax+usb_device_data.TTHub], edi
  243.         mov     [eax+usb_device_data.TTPort], 0
  244.         mov     [eax+usb_device_data.NumInterfaces], edi
  245.         mov     [eax+usb_device_data.DeviceDescrSize], 0
  246.         mov     dl, [esi+usb_controller.ResettingSpeed]
  247.         mov     [eax+usb_device_data.Speed], dl
  248.         mov     [eax+usb_device_data.NumPipes], 1
  249.         push    ebx
  250.         cmp     dl, USB_SPEED_HS
  251.         jz      .nott
  252.         mov     ebx, [esi+usb_controller.ResettingHub]
  253.         test    ebx, ebx
  254.         jz      .nott
  255.         mov     cl, [esi+usb_controller.ResettingPort]
  256.         mov     edx, [ebx+usb_hub.ConfigPipe]
  257.         mov     edx, [edx+usb_pipe.DeviceData]
  258.         cmp     [edx+usb_device_data.TTHub], 0
  259.         jz      @f
  260.         mov     cl, [edx+usb_device_data.TTPort]
  261.         mov     ebx, [edx+usb_device_data.TTHub]
  262.         jmp     .has_tt
  263. @@:
  264.         cmp     [edx+usb_device_data.Speed], USB_SPEED_HS
  265.         jnz     .nott
  266. .has_tt:
  267.         mov     [eax+usb_device_data.TTHub], ebx
  268.         mov     [eax+usb_device_data.TTPort], cl
  269. .nott:
  270.         pop     ebx
  271.         mov     [eax+usb_device_data.ConfigDataSize], edi
  272.         mov     [eax+usb_device_data.Interfaces], edi
  273.         movzx   ecx, [esi+usb_controller.ResettingPort]
  274.         mov     [eax+usb_device_data.Port], cl
  275.         mov     edx, [esi+usb_controller.ResettingHub]
  276.         mov     [eax+usb_device_data.Hub], edx
  277. ; 4. Store pointer to the config pipe in the hub data.
  278. ; Config pipe serves as device identifier.
  279. ; Root hubs use the array inside usb_controller structure,
  280. ; non-root hubs use the array immediately after usb_hub structure.
  281.         test    edx, edx
  282.         jz      .roothub
  283.         mov     edx, [edx+usb_hub.ConnectedDevicesPtr]
  284.         mov     [edx+ecx*4], ebx
  285.         jmp     @f
  286. .roothub:
  287.         mov     [esi+usb_controller.DevicesByPort+ecx*4], ebx
  288. @@:
  289.         call    usb_reinit_pipe_list
  290. ; 5. Issue SET_ADDRESS control request, using buffer filled in step 1a.
  291. ; Use the return value from usb_control_async as our return value;
  292. ; if it is zero, then something has failed.
  293.         lea     eax, [esi+usb_controller.SetAddressBuffer]
  294.         stdcall usb_control_async, ebx, eax, edi, edi, usb_set_address_callback, edi, edi
  295. .nothing:
  296. ; 6. Return.
  297.         pop     edi ebx         ; restore used registers to be stdcall
  298.         ret
  299. ; Handlers of failures in steps 1b, 1d, 1f.
  300. .freememory:
  301.         call    free
  302.         jmp     .freeaddr
  303. .nomemory:
  304.         dbgstr 'No memory for device data'
  305. .freeaddr:
  306.         mov     ecx, dword [esi+usb_controller.SetAddressBuffer+2]
  307.         bts     [esi+usb_controller.ExistingAddresses], ecx
  308.         xor     eax, eax
  309.         jmp     .nothing
  310. endp
  311.  
  312. ; Helper procedure for usb_new_device.
  313. ; Allocates a new USB address and fills usb_controller.SetAddressBuffer
  314. ; with data for SET_ADDRESS(allocated_address) request.
  315. ; out: eax = 0 <=> failed
  316. ; Destroys edi.
  317. proc usb_set_address_request
  318. ; There are 128 bits, one for each possible address.
  319. ; Note: only the USB thread works with usb_controller.ExistingAddresses,
  320. ; so there is no need for synchronization.
  321. ; We must find a bit set to 1 and clear it.
  322. ; 1. Find the first dword which has a nonzero bit = which is nonzero.
  323.         mov     ecx, 128/32
  324.         lea     edi, [esi+usb_controller.ExistingAddresses]
  325.         xor     eax, eax
  326.         repz scasd
  327. ; 2. If all dwords are zero, return an error.
  328.         jz      .error
  329. ; 3. The dword at [edi-4] is nonzero. Find the lowest nonzero bit.
  330.         bsf     eax, [edi-4]
  331. ; Now eax = bit number inside the dword at [edi-4].
  332. ; 4. Clear the bit.
  333.         btr     [edi-4], eax
  334. ; 5. Generate the address by edi = memory address and eax = bit inside dword.
  335. ; Address = eax + 8 * (edi-4 - (esi+usb_controller.ExistingAddress)).
  336.         sub     edi, esi
  337.         lea     edi, [eax+(edi-4-usb_controller.ExistingAddresses)*8]
  338. ; 6. Store the allocated address in SetAddressBuffer and fill remaining fields.
  339. ; Note that usb_controller is zeroed at allocation, so only command byte needs
  340. ; to be filled.
  341.         mov     byte [esi+usb_controller.SetAddressBuffer+1], USB_SET_ADDRESS
  342.         mov     dword [esi+usb_controller.SetAddressBuffer+2], edi
  343. ; 7. Return non-zero value in eax.
  344.         inc     eax
  345. .nothing:
  346.         ret
  347. .error:
  348.         dbgstr 'cannot allocate USB address'
  349.         xor     eax, eax
  350.         jmp     .nothing
  351. endp
  352.  
  353. ; This procedure is called by USB stack when SET_ADDRESS request initiated by
  354. ; usb_new_device is completed, either successfully or unsuccessfully.
  355. ; Note that USB stack uses esi = pointer to usb_controller.
  356. proc usb_set_address_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
  357.         push    ebx     ; save ebx to be stdcall
  358. ; Load data to registers for further references.
  359.         mov     ebx, [pipe]
  360.         mov     ecx, dword [esi+usb_controller.SetAddressBuffer+2]
  361.         mov     eax, [esi+usb_controller.HardwareFunc]
  362. ; 1. Check whether the device has accepted new address. If so, proceed to 2.
  363. ; Otherwise, go to 3.
  364.         cmp     [status], 0
  365.         jnz     .error
  366. ; 2. Address accepted.
  367. ; 2a. The controller-specific structure for the control pipe still uses
  368. ; zero address. Call the controller-specific function to change it to
  369. ; the actual address.
  370. ; Note that the hardware could cache the controller-specific structure,
  371. ; so setting the address could take some time until the cache is evicted.
  372. ; Thus, the call is asynchronous; meet us in usb_after_set_address when it will
  373. ; be safe to continue.
  374.         dbgstr 'address set in device'
  375.         call    [eax+usb_hardware_func.SetDeviceAddress]
  376. ; 2b. If the port is in non-root hub, clear 'reset in progress' flag.
  377. ; In any case, proceed to 4.
  378.         mov     eax, [esi+usb_controller.ResettingHub]
  379.         test    eax, eax
  380.         jz      .return
  381.         and     [eax+usb_hub.Actions], not HUB_RESET_IN_PROGRESS
  382. .return:
  383. ; 4. Address configuration done, we can proceed with other ports.
  384. ; Call the worker function for that.
  385.         call    usb_test_pending_port
  386. .nothing:
  387.         pop     ebx     ; restore ebx to be stdcall
  388.         ret
  389. .error:
  390. ; 3. Device error: device not responding, disconnect etc.
  391.         DEBUGF 1,'K : error %d in SET_ADDRESS, USB device disabled\n',[status]
  392. ; 3a. The address has not been accepted. Mark it as free.
  393.         bts     dword [esi+usb_controller.ExistingAddresses], ecx
  394. ; 3b. Disable the port with bad device.
  395. ; For the root hub, call the controller-specific function and go to 6.
  396. ; For non-root hubs, let the hub code do its work and return (the request
  397. ; could take some time, the hub code is responsible for proceeding).
  398.         cmp     [esi+usb_controller.ResettingHub], 0
  399.         jz      .roothub
  400.         mov     eax, [esi+usb_controller.ResettingHub]
  401.         call    usb_hub_disable_resetting_port
  402.         jmp     .nothing
  403. .roothub:
  404.         movzx   ecx, [esi+usb_controller.ResettingPort]
  405.         call    [eax+usb_hardware_func.PortDisable]
  406.         jmp     .return
  407. endp
  408.  
  409. ; This procedure is called from usb_subscription_done when the hardware cache
  410. ; is cleared after request from usb_set_address_callback.
  411. ; in: ebx -> usb_pipe
  412. proc usb_after_set_address
  413.         dbgstr 'address set for controller'
  414. ; Issue control transfer GET_DESCRIPTOR(DEVICE_DESCR) for first 8 bytes.
  415. ; Remember, we still do not know the actual packet size;
  416. ; 8-bytes-request is safe.
  417. ; usb_new_device has allocated 8 extra bytes besides sizeof.usb_device_data;
  418. ; use them for both input and output.
  419.         mov     eax, [ebx+usb_pipe.DeviceData]
  420.         add     eax, usb_device_data.DeviceDescriptor
  421.         mov     dword [eax], \
  422.                 80h + \         ; device-to-host, standard, device-wide
  423.                 (USB_GET_DESCRIPTOR shl 8) + \  ; request
  424.                 (0 shl 16) + \  ; descriptor index: there is only one
  425.                 (USB_DEVICE_DESCR shl 24)       ; descriptor type
  426.         mov     dword [eax+4], 8 shl 16         ; data length
  427.         stdcall usb_control_async, ebx, eax, eax, 8, usb_get_descr8_callback, eax, 0
  428.         ret
  429. endp
  430.  
  431. ; This procedure is called by USB stack when GET_DESCRIPTOR(DEVICE_DESCR)
  432. ; request initiated by usb_after_set_address is completed, either successfully
  433. ; or unsuccessfully.
  434. ; Note that USB stack uses esi = pointer to usb_controller.
  435. proc usb_get_descr8_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
  436. ;       mov     eax, [buffer]
  437. ;       DEBUGF 1,'K : descr8: l=%x; %x %x %x %x %x %x %x %x\n',[length],\
  438. ;               [eax]:2,[eax+1]:2,[eax+2]:2,[eax+3]:2,[eax+4]:2,[eax+5]:2,[eax+6]:2,[eax+7]:2
  439.         push    edi ebx         ; save used registers to be stdcall
  440.         mov     ebx, [pipe]
  441. ; 1. Check whether the operation was successful.
  442. ; If not, say something to the debug board and stop the initialization.
  443.         cmp     [status], 0
  444.         jnz     .error
  445. ; 2. Length of descriptor must be at least sizeof.usb_device_descr bytes.
  446. ; If not, say something to the debug board and stop the initialization.
  447.         mov     eax, [ebx+usb_pipe.DeviceData]
  448.         cmp     [eax+usb_device_data.DeviceDescriptor+usb_device_descr.bLength], sizeof.usb_device_descr
  449.         jb      .error
  450. ; 3. Now first 8 bytes of device descriptor are known;
  451. ; set DeviceDescrSize accordingly.
  452.         mov     [eax+usb_device_data.DeviceDescrSize], 8
  453. ; 4. The controller-specific structure for the control pipe still uses
  454. ; the fake "maximum packet size". Call the controller-specific function to
  455. ; change it to the actual packet size from the device.
  456. ; Note that the hardware could cache the controller-specific structure,
  457. ; so changing it could take some time until the cache is evicted.
  458. ; Thus, the call is asynchronous; meet us in usb_after_set_endpoint_size
  459. ; when it will be safe to continue.
  460.         movzx   ecx, [eax+usb_device_data.DeviceDescriptor+usb_device_descr.bMaxPacketSize0]
  461.         mov     eax, [esi+usb_controller.HardwareFunc]
  462.         call    [eax+usb_hardware_func.SetEndpointPacketSize]
  463. .nothing:
  464. ; 5. Return.
  465.         pop     ebx edi         ; restore used registers to be stdcall
  466.         ret
  467. .error:
  468.         dbgstr 'error with USB device descriptor'
  469.         jmp     .nothing
  470. endp
  471.  
  472. ; This procedure is called from usb_subscription_done when the hardware cache
  473. ; is cleared after request from usb_get_descr8_callback.
  474. ; in: ebx -> usb_pipe
  475. proc usb_after_set_endpoint_size
  476. ; 1. Reallocate memory for device data:
  477. ; add memory for now-known size of device descriptor and extra 8 bytes
  478. ; for further actions.
  479. ; 1a. Allocate new memory.
  480.         mov     eax, [ebx+usb_pipe.DeviceData]
  481.         movzx   eax, [eax+usb_device_data.DeviceDescriptor+usb_device_descr.bLength]
  482. ; save length for step 2
  483.         push    eax
  484.         add     eax, sizeof.usb_device_data + 8
  485.         call    malloc
  486. ; 1b. If failed, say something to the debug board and stop the initialization.
  487.         test    eax, eax
  488.         jz      .nomemory
  489. ; 1c. Copy data from old memory to new memory and switch the pointer in usb_pipe.
  490.         push    eax
  491.         push    esi edi
  492.         mov     esi, [ebx+usb_pipe.DeviceData]
  493.         mov     [ebx+usb_pipe.DeviceData], eax
  494.         mov     edi, eax
  495.         mov     eax, esi
  496.         mov     ecx, sizeof.usb_device_data / 4
  497.         rep movsd
  498.         pop     edi esi
  499.         call    usb_reinit_pipe_list
  500. ; 1d. Free the old memory.
  501. ; Note that free destroys ebx.
  502.         push    ebx
  503.         call    free
  504.         pop     ebx
  505.         pop     eax
  506. ; 2. Issue control transfer GET_DESCRIPTOR(DEVICE) for full descriptor.
  507. ; restore length saved in step 1a
  508.         pop     edx
  509.         add     eax, sizeof.usb_device_data
  510.         mov     dword [eax], \
  511.                 80h + \         ; device-to-host, standard, device-wide
  512.                 (USB_GET_DESCRIPTOR shl 8) + \  ; request
  513.                 (0 shl 16) + \  ; descriptor index: there is only one
  514.                 (USB_DEVICE_DESCR shl 24)       ; descriptor type
  515.         and     dword [eax+4], 0
  516.         mov     [eax+6], dl     ; data length
  517.         stdcall usb_control_async, ebx, eax, eax, edx, usb_get_descr_callback, eax, 0
  518. ; 3. Return.
  519.         ret
  520. .nomemory:
  521.         dbgstr 'No memory for device data'
  522.         ret
  523. endp
  524.  
  525. ; This procedure is called by USB stack when GET_DESCRIPTOR(DEVICE)
  526. ; request initiated by usb_after_set_endpoint_size is completed,
  527. ; either successfully or unsuccessfully.
  528. proc usb_get_descr_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
  529. ; Note: the prolog is the same as in usb_get_descr8_callback.
  530.         push    edi ebx         ; save used registers to be stdcall
  531. ; 1. Check whether the operation was successful.
  532. ; If not, say something to the debug board and stop the initialization.
  533.         cmp     [status], 0
  534.         jnz     usb_get_descr8_callback.error
  535. ; The full descriptor is known, dump it if specified by compile-time option.
  536. if USB_DUMP_DESCRIPTORS
  537.         mov     eax, [buffer]
  538.         mov     ecx, [length]
  539.         sub     ecx, 8
  540.         jbe     .skipdebug
  541.         DEBUGF 1,'K : device descriptor:'
  542. @@:
  543.         DEBUGF 1,' %x',[eax]:2
  544.         inc     eax
  545.         dec     ecx
  546.         jnz     @b
  547.         DEBUGF 1,'\n'
  548. .skipdebug:
  549. end if
  550. ; 2. Check that bLength is the same as was in the previous request.
  551. ; If not, say something to the debug board and stop the initialization.
  552. ; It is important, because usb_after_set_endpoint_size has allocated memory
  553. ; according to the old bLength. Note that [length] for control transfers
  554. ; includes 8 bytes of setup packet, so data length = [length] - 8.
  555.         mov     eax, [buffer]
  556.         movzx   ecx, [eax+usb_device_descr.bLength]
  557.         add     ecx, 8
  558.         cmp     [length], ecx
  559.         jnz     usb_get_descr8_callback.error
  560. ; Amuse the user if she is watching the debug board.
  561.         mov     cl, [eax+usb_device_descr.bNumConfigurations]
  562.         DEBUGF 1,'K : found USB device with ID %x:%x, %d configuration(s)\n',\
  563.                 [eax+usb_device_descr.idVendor]:4,\
  564.                 [eax+usb_device_descr.idProduct]:4,\
  565.                 cl
  566. ; 3. If there are no configurations, stop the initialization.
  567.         cmp     [eax+usb_device_descr.bNumConfigurations], 0
  568.         jz      .nothing
  569. ; 4. Copy length of device descriptor to device data structure.
  570.         movzx   edx, [eax+usb_device_descr.bLength]
  571.         mov     [eax+usb_device_data.DeviceDescrSize-usb_device_data.DeviceDescriptor], dl
  572. ; 5. Issue control transfer GET_DESCRIPTOR(CONFIGURATION). We do not know
  573. ; the full length of that descriptor, so start with first 8 bytes, they contain
  574. ; the full length.
  575. ; usb_after_set_endpoint_size has allocated 8 extra bytes after the
  576. ; device descriptor, use them for both input and output.
  577.         add     eax, edx
  578.         mov     dword [eax], \
  579.                 80h + \         ; device-to-host, standard, device-wide
  580.                 (USB_GET_DESCRIPTOR shl 8) + \  ; request
  581.                 (0 shl 16) + \  ; descriptor index: there is only one
  582.                 (USB_CONFIG_DESCR shl 24)       ; descriptor type
  583.         mov     dword [eax+4], 8 shl 16         ; data length
  584.         stdcall usb_control_async, [pipe], eax, eax, 8, usb_know_length_callback, eax, 0
  585. .nothing:
  586. ; 6. Return.
  587.         pop     ebx edi         ; restore used registers to be stdcall
  588.         ret
  589. endp
  590.  
  591. ; This procedure is called by USB stack when GET_DESCRIPTOR(CONFIGURATION)
  592. ; request initiated by usb_get_descr_callback is completed,
  593. ; either successfully or unsuccessfully.
  594. proc usb_know_length_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
  595.         push    ebx             ; save used registers to be stdcall
  596. ; 1. Check whether the operation was successful.
  597. ; If not, say something to the debug board and stop the initialization.
  598.         cmp     [status], 0
  599.         jnz     .error
  600. ; 2. Get the total length of data associated with config descriptor and store
  601. ; it in device data structure. The total length must be at least
  602. ; sizeof.usb_config_descr bytes; if not, say something to the debug board and
  603. ; stop the initialization.
  604.         mov     eax, [buffer]
  605.         mov     edx, [pipe]
  606.         movzx   ecx, [eax+usb_config_descr.wTotalLength]
  607.         mov     eax, [edx+usb_pipe.DeviceData]
  608.         cmp     ecx, sizeof.usb_config_descr
  609.         jb      .error
  610.         mov     [eax+usb_device_data.ConfigDataSize], ecx
  611. ; 3. Reallocate memory for device data:
  612. ; include usb_device_data structure, device descriptor,
  613. ; config descriptor with all associated data, and extra bytes
  614. ; sufficient for 8 bytes control packet and for one usb_interface_data struc.
  615. ; Align extra bytes to dword boundary.
  616. if sizeof.usb_interface_data > 8
  617. .extra_size = sizeof.usb_interface_data
  618. else
  619. .extra_size = 8
  620. end if
  621. ; 3a. Allocate new memory.
  622.         movzx   edx, [eax+usb_device_data.DeviceDescrSize]
  623.         lea     eax, [ecx+edx+sizeof.usb_device_data+.extra_size+3]
  624.         and     eax, not 3
  625.         push    eax
  626.         call    malloc
  627.         pop     edx
  628. ; 3b. If failed, say something to the debug board and stop the initialization.
  629.         test    eax, eax
  630.         jz      .nomemory
  631. ; 3c. Copy data from old memory to new memory and switch the pointer in usb_pipe.
  632.         push    eax
  633.         mov     ebx, [pipe]
  634.         push    esi edi
  635.         mov     esi, [ebx+usb_pipe.DeviceData]
  636.         mov     edi, eax
  637.         mov     [ebx+usb_pipe.DeviceData], eax
  638.         mov     eax, esi
  639.         movzx   ecx, [esi+usb_device_data.DeviceDescrSize]
  640.         sub     edx, .extra_size
  641.         mov     [esi+usb_device_data.Interfaces], edx
  642.         add     ecx, sizeof.usb_device_data + 8
  643.         mov     edx, ecx
  644.         shr     ecx, 2
  645.         and     edx, 3
  646.         rep movsd
  647.         mov     ecx, edx
  648.         rep movsb
  649.         pop     edi esi
  650.         call    usb_reinit_pipe_list
  651. ; 3d. Free old memory.
  652.         call    free
  653.         pop     eax
  654. ; 4. Issue control transfer GET_DESCRIPTOR(DEVICE) for full descriptor.
  655.         movzx   ecx, [eax+usb_device_data.DeviceDescrSize]
  656.         mov     edx, [eax+usb_device_data.ConfigDataSize]
  657.         lea     eax, [eax+ecx+sizeof.usb_device_data]
  658.         mov     dword [eax], \
  659.                 80h + \         ; device-to-host, standard, device-wide
  660.                 (USB_GET_DESCRIPTOR shl 8) + \  ; request
  661.                 (0 shl 16) + \  ; descriptor index: there is only one
  662.                 (USB_CONFIG_DESCR shl 24)       ; descriptor type
  663.         and     dword [eax+4], 0
  664.         mov     word [eax+6], dx        ; data length
  665.         stdcall usb_control_async, [pipe], eax, eax, edx, usb_set_config_callback, eax, 0
  666. .nothing:
  667. ; 5. Return.
  668.         pop     ebx             ; restore used registers to be stdcall
  669.         ret
  670. .error:
  671.         dbgstr 'error with USB configuration descriptor'
  672.         jmp     .nothing
  673. .nomemory:
  674.         dbgstr 'No memory for device data'
  675.         jmp     .nothing
  676. endp
  677.  
  678. ; This procedure is called by USB stack when GET_DESCRIPTOR(CONFIGURATION)
  679. ; request initiated by usb_know_length_callback is completed,
  680. ; either successfully or unsuccessfully.
  681. proc usb_set_config_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
  682. ; Note that the prolog is the same as in usb_know_length_callback.
  683.         push    ebx             ; save used registers to be stdcall
  684. ; 1. Check whether the operation was successful.
  685. ; If not, say something to the debug board and stop the initialization.
  686.         xor     ecx, ecx
  687.         mov     ebx, [pipe]
  688.         cmp     [status], ecx
  689.         jnz     usb_know_length_callback.error
  690. ; The full descriptor is known, dump it if specified by compile-time option.
  691. if USB_DUMP_DESCRIPTORS
  692.         mov     eax, [buffer]
  693.         mov     ecx, [length]
  694.         sub     ecx, 8
  695.         jbe     .skip_debug
  696.         DEBUGF 1,'K : config descriptor:'
  697. @@:
  698.         DEBUGF 1,' %x',[eax]:2
  699.         inc     eax
  700.         dec     ecx
  701.         jnz     @b
  702.         DEBUGF 1,'\n'
  703. .skip_debug:
  704.         xor     ecx, ecx
  705. end if
  706. ; 2. Issue control transfer SET_CONFIGURATION to activate this configuration.
  707. ; Usually this is the only configuration.
  708. ; Use extra bytes allocated by usb_know_length_callback;
  709. ; offset from device data start is stored in Interfaces.
  710.         mov     eax, [ebx+usb_pipe.DeviceData]
  711.         mov     edx, [buffer]
  712.         add     eax, [eax+usb_device_data.Interfaces]
  713.         mov     dl, [edx+usb_config_descr.bConfigurationValue]
  714.         mov     dword [eax], USB_SET_CONFIGURATION shl 8
  715.         mov     dword [eax+4], ecx
  716.         mov     byte [eax+2], dl
  717.         stdcall usb_control_async, [pipe], eax, ecx, ecx, usb_got_config_callback, [buffer], ecx
  718.         pop     ebx             ; restore used registers to be stdcall
  719.         ret
  720. endp
  721.  
  722. ; This procedure is called by USB stack when SET_CONFIGURATION
  723. ; request initiated by usb_set_config_callback is completed,
  724. ; either successfully or unsuccessfully.
  725. ; If successfully, the device is configured and ready to work,
  726. ; pass the device to the corresponding driver(s).
  727. proc usb_got_config_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
  728. locals
  729. InterfacesData  dd      ?
  730. NumInterfaces   dd      ?
  731. driver          dd      ?
  732. endl
  733. ; 1. If there was an error, say something to the debug board and stop the
  734. ; initialization.
  735.         cmp     [status], 0
  736.         jz      @f
  737.         dbgstr 'USB error in SET_CONFIGURATION'
  738.         ret
  739. @@:
  740.         push    ebx edi         ; save used registers to be stdcall
  741. ; 2. Sanity checks: the total length must be the same as before (because we
  742. ; have allocated memory assuming the old value), length of config descriptor
  743. ; must be at least sizeof.usb_config_descr (we use fields from it),
  744. ; there must be at least one interface.
  745.         mov     ebx, [pipe]
  746.         mov     ebx, [ebx+usb_pipe.DeviceData]
  747.         mov     eax, [calldata]
  748.         mov     edx, [ebx+usb_device_data.ConfigDataSize]
  749.         cmp     [eax+usb_config_descr.wTotalLength], dx
  750.         jnz     .invalid
  751.         cmp     [eax+usb_config_descr.bLength], 9
  752.         jb      .invalid
  753.         movzx   edx, [eax+usb_config_descr.bNumInterfaces]
  754.         test    edx, edx
  755.         jnz     @f
  756. .invalid:
  757.         dbgstr 'error: invalid configuration descriptor'
  758.         jmp     .nothing
  759. @@:
  760. ; 3. Store the number of interfaces in device data structure.
  761.         mov     [ebx+usb_device_data.NumInterfaces], edx
  762. ; 4. If there is only one interface (which happens quite often),
  763. ; the memory allocated in usb_know_length_callback is sufficient.
  764. ; Otherwise (which also happens quite often), reallocate device data.
  765. ; 4a. Check whether there is only one interface. If so, skip this step.
  766.         cmp     edx, 1
  767.         jz      .has_memory
  768. ; 4b. Allocate new memory.
  769.         mov     eax, [ebx+usb_device_data.Interfaces]
  770.         lea     eax, [eax+edx*sizeof.usb_interface_data]
  771.         call    malloc
  772. ; 4c. If failed, say something to the debug board and
  773. ; stop the initialization.
  774.         test    eax, eax
  775.         jnz     @f
  776.         dbgstr 'No memory for device data'
  777.         jmp     .nothing
  778. @@:
  779. ; 4d. Copy data from old memory to new memory and switch the pointer in usb_pipe.
  780.         push    eax
  781.         push    esi
  782.         mov     ebx, [pipe]
  783.         mov     edi, eax
  784.         mov     esi, [ebx+usb_pipe.DeviceData]
  785.         mov     [ebx+usb_pipe.DeviceData], eax
  786.         mov     eax, esi
  787.         mov     ecx, [esi+usb_device_data.Interfaces]
  788.         shr     ecx, 2
  789.         rep movsd
  790.         pop     esi
  791.         call    usb_reinit_pipe_list
  792. ; 4e. Free old memory.
  793.         call    free
  794.         pop     ebx
  795. .has_memory:
  796. ; 5. Initialize interfaces table: zero all contents.
  797.         mov     edi, [ebx+usb_device_data.Interfaces]
  798.         add     edi, ebx
  799.         mov     [InterfacesData], edi
  800.         mov     ecx, [ebx+usb_device_data.NumInterfaces]
  801. if sizeof.usb_interface_data <> 8
  802. You have changed sizeof.usb_interface_data? Modify this place too.
  803. end if
  804.         add     ecx, ecx
  805.         xor     eax, eax
  806.         rep stosd
  807. ; No interfaces are found yet.
  808.         mov     [NumInterfaces], eax
  809. ; 6. Get the pointer to config descriptor data.
  810. ; Note: if there was reallocation, [buffer] is not valid anymore,
  811. ; so calculate value based on usb_device_data.
  812.         movzx   eax, [ebx+usb_device_data.DeviceDescrSize]
  813.         lea     eax, [eax+ebx+sizeof.usb_device_data]
  814.         mov     [calldata], eax
  815.         mov     ecx, [ebx+usb_device_data.ConfigDataSize]
  816. ; 7. Loop over all descriptors,
  817. ; scan for interface descriptors with bAlternateSetting = 0,
  818. ; load the corresponding driver, call its AddDevice function.
  819. .descriptor_loop:
  820. ; While in loop: eax points to the current descriptor,
  821. ; ecx = number of bytes left, the iteration starts only if ecx is nonzero,
  822. ; edx = size of the current descriptor.
  823. ; 7a. The first byte is always accessible; it contains the length of
  824. ; the current descriptor. Validate that the length is at least 2 bytes,
  825. ; and the entire descriptor is readable (the length is at most number of
  826. ; bytes left).
  827.         movzx   edx, [eax+usb_descr.bLength]
  828.         cmp     edx, sizeof.usb_descr
  829.         jb      .invalid
  830.         cmp     ecx, edx
  831.         jb      .invalid
  832. ; 7b. Check descriptor type. Ignore all non-INTERFACE descriptor.
  833.         cmp     byte [eax+usb_descr.bDescriptorType], USB_INTERFACE_DESCR
  834.         jz      .interface
  835. .next_descriptor:
  836. ; 7c. Advance pointer, decrease length left, if there is still something left,
  837. ; continue the loop.
  838.         add     eax, edx
  839.         sub     ecx, edx
  840.         jnz     .descriptor_loop
  841. .done:
  842. .nothing:
  843.         pop     edi ebx         ; restore used registers to be stdcall
  844.         ret
  845. .interface:
  846. ; 7d. Validate the descriptor length.
  847.         cmp     edx, sizeof.usb_interface_descr
  848.         jb      .next_descriptor
  849. ; 7e. If bAlternateSetting is nonzero, this descriptor actually describes
  850. ; another mode of already known interface and belongs to the already loaded
  851. ; driver; amuse the user and continue to 7c.
  852.         cmp     byte [eax+usb_interface_descr.bAlternateSetting], 0
  853.         jz      @f
  854.         DEBUGF 1,'K : note: alternate setting with %x/%x/%x\n',\
  855.                 [eax+usb_interface_descr.bInterfaceClass]:2,\
  856.                 [eax+usb_interface_descr.bInterfaceSubClass]:2,\
  857.                 [eax+usb_interface_descr.bInterfaceProtocol]:2
  858.         jmp     .next_descriptor
  859. @@:
  860. ; 7f. Check that the new interface does not overflow allocated table.
  861.         mov     edx, [NumInterfaces]
  862.         inc     edx
  863.         cmp     edx, [ebx+usb_device_data.NumInterfaces]
  864.         ja      .invalid
  865. ; 7g. We have found a new interface. Advance bookkeeping vars.
  866.         mov     [NumInterfaces], edx
  867.         add     [InterfacesData], sizeof.usb_interface_data
  868. ; 7h. Save length left and pointer to the current interface descriptor.
  869.         push    ecx eax
  870. ; Amuse the user if she is watching the debug board.
  871.         DEBUGF 1,'K : USB interface class/subclass/protocol = %x/%x/%x\n',\
  872.                 [eax+usb_interface_descr.bInterfaceClass]:2,\
  873.                 [eax+usb_interface_descr.bInterfaceSubClass]:2,\
  874.                 [eax+usb_interface_descr.bInterfaceProtocol]:2
  875. ; 7i. Select the correct driver based on interface class.
  876. ; For hubs, go to 7j. Otherwise, go to 7k.
  877. ; Note: this should be rewritten as table-based lookup when more drivers will
  878. ; be available.
  879.         cmp     byte [eax+usb_interface_descr.bInterfaceClass], 9
  880.         jz      .found_hub
  881.         mov     edx, usb_hid_name
  882.         cmp     byte [eax+usb_interface_descr.bInterfaceClass], 3
  883.         jz      .load_driver
  884.         mov     edx, usb_print_name
  885.         cmp     byte [eax+usb_interface_descr.bInterfaceClass], 7
  886.         jz      .load_driver
  887.         mov     edx, usb_stor_name
  888.         cmp     byte [eax+usb_interface_descr.bInterfaceClass], 8
  889.         jz      .load_driver
  890.         mov     edx, usb_other_name
  891.         jmp     .load_driver
  892. .found_hub:
  893. ; 7j. Hubs are a part of USB stack, thus, integrated into the kernel.
  894. ; Use the pointer to hub callbacks and go to 7m.
  895.         mov     eax, usb_hub_pseudosrv - USBSRV.usb_func
  896.         jmp     .driver_loaded
  897. .load_driver:
  898. ; 7k. Load the corresponding driver.
  899.         push    ebx esi edi
  900.         stdcall get_service, edx
  901.         pop     edi esi ebx
  902. ; 7l. If failed, say something to the debug board and go to 7p.
  903.         test    eax, eax
  904.         jnz     .driver_loaded
  905.         dbgstr 'failed to load class driver'
  906.         jmp     .next_descriptor2
  907. .driver_loaded:
  908. ; 7m. Call AddDevice function of the driver.
  909. ; Note that top of stack contains a pointer to the current interface,
  910. ; saved by step 7h.
  911.         mov     [driver], eax
  912.         mov     eax, [eax+USBSRV.usb_func]
  913.         pop     edx
  914.         push    edx
  915. ; Note: usb_hub_init assumes that edx points to usb_interface_descr,
  916. ; ecx = length rest; if you change the code, modify usb_hub_init also.
  917.         stdcall [eax+USBFUNC.add_device], [pipe], [calldata], edx
  918. ; 7n. If failed, say something to the debug board and go to 7p.
  919.         test    eax, eax
  920.         jnz     .store_data
  921.         dbgstr 'USB device initialization failed'
  922.         jmp     .next_descriptor2
  923. .store_data:
  924. ; 7o. Store the returned value and the driver handle to InterfacesData.
  925. ; Note that step 7g has already advanced InterfacesData.
  926.         mov     edx, [InterfacesData]
  927.         mov     [edx+usb_interface_data.DriverData-sizeof.usb_interface_data], eax
  928.         mov     eax, [driver]
  929.         mov     [edx+usb_interface_data.DriverFunc-sizeof.usb_interface_data], eax
  930. .next_descriptor2:
  931. ; 7p. Restore registers saved in step 7h, get the descriptor length and
  932. ; continue to 7c.
  933.         pop     eax ecx
  934.         movzx   edx, byte [eax+usb_descr.bLength]
  935.         jmp     .next_descriptor
  936. endp
  937.  
  938. ; Driver names, see step 7i of usb_got_config_callback.
  939. iglobal
  940. usb_hid_name    db      'usbhid',0
  941. usb_stor_name   db      'usbstor',0
  942. usb_print_name  db      'usbprint',0
  943. usb_other_name  db      'usbother',0
  944. endg
  945.