Subversion Repositories Kolibri OS

Rev

Rev 4587 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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