Subversion Repositories Kolibri OS

Rev

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