Changeset df6ded8 in mainline for uspace/lib
- Timestamp:
- 2018-02-28T16:37:50Z (8 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 1b20da0
- Parents:
- f5e5f73 (diff), b2dca8de (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - git-author:
- Jakub Jermar <jakub@…> (2018-02-28 16:06:42)
- git-committer:
- Jakub Jermar <jakub@…> (2018-02-28 16:37:50)
- Location:
- uspace/lib
- Files:
-
- 15 added
- 2 deleted
- 48 edited
-
c/include/bitops.h (modified) (1 diff)
-
c/include/byteorder.h (modified) (1 diff)
-
c/include/ipc/dev_iface.h (modified) (2 diffs)
-
drv/Makefile (modified) (1 diff)
-
drv/generic/dev_iface.c (modified) (3 diffs)
-
drv/generic/driver.c (modified) (1 diff)
-
drv/generic/private/remote_usbdiag.h (added)
-
drv/generic/private/remote_usbhc.h (modified) (1 diff)
-
drv/generic/remote_usb.c (modified) (5 diffs)
-
drv/generic/remote_usbdiag.c (added)
-
drv/generic/remote_usbhc.c (modified) (7 diffs)
-
drv/include/usb_iface.h (modified) (4 diffs)
-
drv/include/usbdiag_iface.h (added)
-
drv/include/usbhc_iface.h (modified) (3 diffs)
-
pcm/src/format.c (modified) (1 diff)
-
usb/Makefile (modified) (1 diff)
-
usb/include/usb/classes/hub.h (modified) (5 diffs)
-
usb/include/usb/descriptor.h (modified) (11 diffs)
-
usb/include/usb/dma_buffer.h (added)
-
usb/include/usb/port.h (added)
-
usb/include/usb/request.h (modified) (4 diffs)
-
usb/include/usb/usb.h (modified) (9 diffs)
-
usb/src/dma_buffer.c (added)
-
usb/src/dump.c (modified) (4 diffs)
-
usb/src/port.c (added)
-
usb/src/usb.c (modified) (2 diffs)
-
usbdev/include/usb/dev/device.h (modified) (4 diffs)
-
usbdev/include/usb/dev/driver.h (modified) (1 diff)
-
usbdev/include/usb/dev/pipes.h (modified) (6 diffs)
-
usbdev/include/usb/dev/poll.h (modified) (5 diffs)
-
usbdev/include/usb/dev/request.h (modified) (1 diff)
-
usbdev/src/devdrv.c (modified) (20 diffs)
-
usbdev/src/devpoll.c (modified) (8 diffs)
-
usbdev/src/dp.c (modified) (3 diffs)
-
usbdev/src/driver.c (modified) (4 diffs)
-
usbdev/src/pipes.c (modified) (13 diffs)
-
usbdev/src/pipesinit.c (modified) (14 diffs)
-
usbdev/src/request.c (modified) (8 diffs)
-
usbhid/src/hiddescriptor.c (modified) (6 diffs)
-
usbhid/src/hidparser.c (modified) (32 diffs)
-
usbhid/src/hidpath.c (modified) (20 diffs)
-
usbhid/src/hidreport.c (modified) (8 diffs)
-
usbhid/src/hidreq.c (modified) (13 diffs)
-
usbhost/Makefile (modified) (1 diff)
-
usbhost/include/usb/host/bandwidth.h (added)
-
usbhost/include/usb/host/bus.h (added)
-
usbhost/include/usb/host/ddf_helpers.h (modified) (2 diffs)
-
usbhost/include/usb/host/endpoint.h (modified) (3 diffs)
-
usbhost/include/usb/host/hcd.h (modified) (2 diffs)
-
usbhost/include/usb/host/usb2_bus.h (added)
-
usbhost/include/usb/host/usb_bus.h (deleted)
-
usbhost/include/usb/host/usb_transfer_batch.h (modified) (3 diffs)
-
usbhost/include/usb/host/utility.h (added)
-
usbhost/src/bandwidth.c (added)
-
usbhost/src/bus.c (added)
-
usbhost/src/ddf_helpers.c (modified) (16 diffs)
-
usbhost/src/endpoint.c (modified) (2 diffs)
-
usbhost/src/hcd.c (modified) (2 diffs)
-
usbhost/src/usb2_bus.c (added)
-
usbhost/src/usb_bus.c (deleted)
-
usbhost/src/usb_transfer_batch.c (modified) (2 diffs)
-
usbhost/src/utility.c (added)
-
usbvirt/src/ctrltransfer.c (modified) (1 diff)
-
usbvirt/src/ipc_hc.c (modified) (7 diffs)
-
usbvirt/src/transfer.c (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/include/bitops.h
rf5e5f73 rdf6ded8 54 54 #define BIT_RANGE_EXTRACT(type, hi, lo, value) \ 55 55 (((value) >> (lo)) & BIT_RRANGE(type, (hi) - (lo) + 1)) 56 57 /** Insert @a value between bits @a hi .. @a lo. */ 58 #define BIT_RANGE_INSERT(type, hi, lo, value) \ 59 (((value) & BIT_RRANGE(type, (hi) - (lo) + 1)) << (lo)) 56 60 57 61 /** Return position of first non-zero bit from left (i.e. [log_2(arg)]). -
uspace/lib/c/include/byteorder.h
rf5e5f73 rdf6ded8 85 85 #define ntohl(n) uint32_t_be2host((n)) 86 86 87 #define uint8_t_be2host(n) (n) 88 #define uint8_t_le2host(n) (n) 89 #define host2uint8_t_be(n) (n) 90 #define host2uint8_t_le(n) (n) 91 #define host2uint8_t_le(n) (n) 92 93 #define int8_t_le2host(n) uint8_t_le2host(n) 94 #define int16_t_le2host(n) uint16_t_le2host(n) 95 #define int32_t_le2host(n) uint32_t_le2host(n) 96 #define int64_t_le2host(n) uint64_t_le2host(n) 97 98 #define int8_t_be2host(n) uint8_t_be2host(n) 99 #define int16_t_be2host(n) uint16_t_be2host(n) 100 #define int32_t_be2host(n) uint32_t_be2host(n) 101 #define int64_t_be2host(n) uint64_t_be2host(n) 102 103 #define host2int8_t_le(n) host2uint8_t_le(n) 104 #define host2int16_t_le(n) host2uint16_t_le(n) 105 #define host2int32_t_le(n) host2uint32_t_le(n) 106 #define host2int64_t_le(n) host2uint64_t_le(n) 107 108 #define host2int8_t_be(n) host2uint8_t_be(n) 109 #define host2int16_t_be(n) host2uint16_t_be(n) 110 #define host2int32_t_be(n) host2uint32_t_be(n) 111 #define host2int64_t_be(n) host2uint64_t_be(n) 112 87 113 static inline uint64_t uint64_t_byteorder_swap(uint64_t n) 88 114 { -
uspace/lib/c/include/ipc/dev_iface.h
rf5e5f73 rdf6ded8 44 44 /** Audio device pcm buffer interface */ 45 45 AUDIO_PCM_BUFFER_IFACE, 46 46 47 47 /** Network interface controller interface */ 48 48 NIC_DEV_IFACE, 49 49 50 50 /** IEEE 802.11 interface controller interface */ 51 51 IEEE80211_DEV_IFACE, 52 52 53 53 /** Interface provided by any PCI device. */ 54 54 PCI_DEV_IFACE, … … 56 56 /** Interface provided by any USB device. */ 57 57 USB_DEV_IFACE, 58 /** Interface provided by USB host controller. */ 58 /** Interface provided by USB diagnostic devices. */ 59 USBDIAG_DEV_IFACE, 60 /** Interface provided by USB host controller to USB device. */ 59 61 USBHC_DEV_IFACE, 60 62 /** Interface provided by USB HID devices. */ -
uspace/lib/drv/Makefile
rf5e5f73 rdf6ded8 47 47 generic/remote_usb.c \ 48 48 generic/remote_pci.c \ 49 generic/remote_usbdiag.c \ 49 50 generic/remote_usbhc.c \ 50 51 generic/remote_usbhid.c \ -
uspace/lib/drv/generic/dev_iface.c
rf5e5f73 rdf6ded8 48 48 #include "remote_ieee80211.h" 49 49 #include "remote_usb.h" 50 #include "remote_usbdiag.h" 50 51 #include "remote_usbhc.h" 51 52 #include "remote_usbhid.h" … … 65 66 [PCI_DEV_IFACE] = &remote_pci_iface, 66 67 [USB_DEV_IFACE] = &remote_usb_iface, 68 [USBDIAG_DEV_IFACE] = &remote_usbdiag_iface, 67 69 [USBHC_DEV_IFACE] = &remote_usbhc_iface, 68 70 [USBHID_DEV_IFACE] = &remote_usbhid_iface, … … 85 87 if (iface_method_idx >= rem_iface->method_count) 86 88 return NULL; 87 89 88 90 return rem_iface->methods[iface_method_idx]; 89 91 } -
uspace/lib/drv/generic/driver.c
rf5e5f73 rdf6ded8 971 971 } 972 972 973 int ddf_driver_main(const driver_t *drv)973 errno_t ddf_driver_main(const driver_t *drv) 974 974 { 975 975 /* -
uspace/lib/drv/generic/private/remote_usbhc.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2010 Vojtech Horky 3 * Copyright (c) 2017 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * -
uspace/lib/drv/generic/remote_usb.c
rf5e5f73 rdf6ded8 2 2 * Copyright (c) 2010 Vojtech Horky 3 3 * Copyright (c) 2011 Jan Vesely 4 * Copyright (c) 2018 Michal Staruch, Ondrej Hlavaty 4 5 * All rights reserved. 5 6 * … … 51 52 usb_dev_session_t *usb_dev_connect_to_self(ddf_dev_t *dev) 52 53 { 53 return devman_parent_device_connect(ddf_dev_get_handle(dev), IPC_FLAG_BLOCKING); 54 return devman_parent_device_connect(ddf_dev_get_handle(dev), 55 IPC_FLAG_BLOCKING); 54 56 } 55 57 … … 61 63 62 64 typedef enum { 63 IPC_M_USB_GET_MY_INTERFACE, 64 IPC_M_USB_GET_MY_DEVICE_HANDLE, 65 IPC_M_USB_RESERVE_DEFAULT_ADDRESS, 66 IPC_M_USB_RELEASE_DEFAULT_ADDRESS, 67 IPC_M_USB_DEVICE_ENUMERATE, 68 IPC_M_USB_DEVICE_REMOVE, 69 IPC_M_USB_REGISTER_ENDPOINT, 70 IPC_M_USB_UNREGISTER_ENDPOINT, 71 IPC_M_USB_READ, 72 IPC_M_USB_WRITE, 65 IPC_M_USB_GET_MY_DESCRIPTION, 73 66 } usb_iface_funcs_t; 74 67 … … 79 72 * @return Error code. 80 73 */ 81 errno_t usb_get_my_interface(async_exch_t *exch, int *usb_iface) 82 { 83 if (!exch) 84 return EBADMEM; 85 sysarg_t iface_no; 86 const errno_t ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE), 87 IPC_M_USB_GET_MY_INTERFACE, &iface_no); 88 if (ret == EOK && usb_iface) 89 *usb_iface = (int)iface_no; 90 return ret; 91 } 92 93 /** Tell devman handle of the usb device function. 94 * 95 * @param[in] exch IPC communication exchange 96 * @param[out] handle devman handle of the HC used by the target device. 97 * 98 * @return Error code. 99 * 100 */ 101 errno_t usb_get_my_device_handle(async_exch_t *exch, devman_handle_t *handle) 102 { 103 devman_handle_t h = 0; 104 const errno_t ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE), 105 IPC_M_USB_GET_MY_DEVICE_HANDLE, &h); 106 if (ret == EOK && handle) 107 *handle = (devman_handle_t)h; 108 return ret; 109 } 110 111 /** Reserve default USB address. 112 * @param[in] exch IPC communication exchange 113 * @param[in] speed Communication speed of the newly attached device 114 * @return Error code. 115 */ 116 errno_t usb_reserve_default_address(async_exch_t *exch, usb_speed_t speed) 117 { 118 if (!exch) 119 return EBADMEM; 120 return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE), 121 IPC_M_USB_RESERVE_DEFAULT_ADDRESS, speed); 122 } 123 124 /** Release default USB address. 125 * 126 * @param[in] exch IPC communication exchange 127 * 128 * @return Error code. 129 * 130 */ 131 errno_t usb_release_default_address(async_exch_t *exch) 132 { 133 if (!exch) 134 return EBADMEM; 135 return async_req_1_0(exch, DEV_IFACE_ID(USB_DEV_IFACE), 136 IPC_M_USB_RELEASE_DEFAULT_ADDRESS); 137 } 138 139 /** Trigger USB device enumeration 140 * 141 * @param[in] exch IPC communication exchange 142 * @param[out] handle Identifier of the newly added device (if successful) 143 * 144 * @return Error code. 145 * 146 */ 147 errno_t usb_device_enumerate(async_exch_t *exch, unsigned port) 148 { 149 if (!exch) 150 return EBADMEM; 151 const errno_t ret = async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE), 152 IPC_M_USB_DEVICE_ENUMERATE, port); 153 return ret; 154 } 155 156 /** Trigger USB device enumeration 157 * 158 * @param[in] exch IPC communication exchange 159 * @param[in] handle Identifier of the device 160 * 161 * @return Error code. 162 * 163 */ 164 errno_t usb_device_remove(async_exch_t *exch, unsigned port) 165 { 166 if (!exch) 167 return EBADMEM; 168 return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE), 169 IPC_M_USB_DEVICE_REMOVE, port); 170 } 171 172 static_assert(sizeof(sysarg_t) >= 4); 173 174 typedef union { 175 uint8_t arr[sizeof(sysarg_t)]; 176 sysarg_t arg; 177 } pack8_t; 178 179 errno_t usb_register_endpoint(async_exch_t *exch, usb_endpoint_t endpoint, 180 usb_transfer_type_t type, usb_direction_t direction, 181 size_t mps, unsigned packets, unsigned interval) 182 { 183 if (!exch) 184 return EBADMEM; 185 pack8_t pack; 186 pack.arr[0] = type; 187 pack.arr[1] = direction; 188 pack.arr[2] = interval; 189 pack.arr[3] = packets; 190 191 return async_req_4_0(exch, DEV_IFACE_ID(USB_DEV_IFACE), 192 IPC_M_USB_REGISTER_ENDPOINT, endpoint, pack.arg, mps); 193 194 } 195 196 errno_t usb_unregister_endpoint(async_exch_t *exch, usb_endpoint_t endpoint, 197 usb_direction_t direction) 198 { 199 if (!exch) 200 return EBADMEM; 201 return async_req_3_0(exch, DEV_IFACE_ID(USB_DEV_IFACE), 202 IPC_M_USB_UNREGISTER_ENDPOINT, endpoint, direction); 203 } 204 205 errno_t usb_read(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup, 206 void *data, size_t size, size_t *rec_size) 74 errno_t usb_get_my_description(async_exch_t *exch, usb_device_desc_t *desc) 207 75 { 208 76 if (!exch) 209 77 return EBADMEM; 210 78 211 if (size == 0 && setup == 0) 212 return EOK; 79 usb_device_desc_t tmp_desc; 213 80 214 /* Make call identifying target USB device and type of transfer. */ 215 aid_t opening_request = async_send_4(exch, 216 DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_READ, endpoint, 217 (setup & UINT32_MAX), (setup >> 32), NULL); 218 219 if (opening_request == 0) { 220 return ENOMEM; 221 } 222 223 /* Retrieve the data. */ 224 ipc_call_t data_request_call; 225 aid_t data_request = 226 async_data_read(exch, data, size, &data_request_call); 227 228 if (data_request == 0) { 229 // FIXME: How to let the other side know that we want to abort? 230 async_forget(opening_request); 231 return ENOMEM; 232 } 233 234 /* Wait for the answer. */ 235 errno_t data_request_rc; 236 errno_t opening_request_rc; 237 async_wait_for(data_request, &data_request_rc); 238 async_wait_for(opening_request, &opening_request_rc); 239 240 if (data_request_rc != EOK) { 241 /* Prefer the return code of the opening request. */ 242 if (opening_request_rc != EOK) { 243 return (errno_t) opening_request_rc; 244 } else { 245 return (errno_t) data_request_rc; 246 } 247 } 248 if (opening_request_rc != EOK) { 249 return (errno_t) opening_request_rc; 250 } 251 252 *rec_size = IPC_GET_ARG2(data_request_call); 253 return EOK; 81 const errno_t ret = async_req_1_5(exch, DEV_IFACE_ID(USB_DEV_IFACE), 82 IPC_M_USB_GET_MY_DESCRIPTION, 83 (sysarg_t *) &tmp_desc.address, 84 (sysarg_t *) &tmp_desc.depth, 85 (sysarg_t *) &tmp_desc.speed, 86 &tmp_desc.handle, 87 (sysarg_t *) &tmp_desc.iface); 88 if (ret == EOK && desc) 89 *desc = tmp_desc; 90 return ret; 254 91 } 255 92 256 errno_t usb_write(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup, 257 const void *data, size_t size) 258 { 259 if (!exch) 260 return EBADMEM; 261 262 if (size == 0 && setup == 0) 263 return EOK; 264 265 aid_t opening_request = async_send_5(exch, 266 DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_WRITE, endpoint, size, 267 (setup & UINT32_MAX), (setup >> 32), NULL); 268 269 if (opening_request == 0) { 270 return ENOMEM; 271 } 272 273 /* Send the data if any. */ 274 if (size > 0) { 275 const errno_t ret = async_data_write_start(exch, data, size); 276 if (ret != EOK) { 277 async_forget(opening_request); 278 return ret; 279 } 280 } 281 282 /* Wait for the answer. */ 283 errno_t opening_request_rc; 284 async_wait_for(opening_request, &opening_request_rc); 285 286 return (errno_t) opening_request_rc; 287 } 288 289 static void remote_usb_get_my_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 290 static void remote_usb_get_my_device_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 291 static void remote_usb_reserve_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 292 static void remote_usb_release_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 293 static void remote_usb_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 294 static void remote_usb_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 295 static void remote_usb_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 296 static void remote_usb_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 297 static void remote_usb_read(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call); 298 static void remote_usb_write(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call); 93 static void remote_usb_get_my_description(ddf_fun_t *, void *, 94 ipc_callid_t, ipc_call_t *); 299 95 300 96 /** Remote USB interface operations. */ 301 97 static const remote_iface_func_ptr_t remote_usb_iface_ops [] = { 302 [IPC_M_USB_GET_MY_INTERFACE] = remote_usb_get_my_interface, 303 [IPC_M_USB_GET_MY_DEVICE_HANDLE] = remote_usb_get_my_device_handle, 304 [IPC_M_USB_RESERVE_DEFAULT_ADDRESS] = remote_usb_reserve_default_address, 305 [IPC_M_USB_RELEASE_DEFAULT_ADDRESS] = remote_usb_release_default_address, 306 [IPC_M_USB_DEVICE_ENUMERATE] = remote_usb_device_enumerate, 307 [IPC_M_USB_DEVICE_REMOVE] = remote_usb_device_remove, 308 [IPC_M_USB_REGISTER_ENDPOINT] = remote_usb_register_endpoint, 309 [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usb_unregister_endpoint, 310 [IPC_M_USB_READ] = remote_usb_read, 311 [IPC_M_USB_WRITE] = remote_usb_write, 98 [IPC_M_USB_GET_MY_DESCRIPTION] = remote_usb_get_my_description, 312 99 }; 313 100 … … 319 106 }; 320 107 321 void remote_usb_get_my_ interface(ddf_fun_t *fun, void *iface,108 void remote_usb_get_my_description(ddf_fun_t *fun, void *iface, 322 109 ipc_callid_t callid, ipc_call_t *call) 323 110 { 324 111 const usb_iface_t *usb_iface = (usb_iface_t *) iface; 325 112 326 if (usb_iface->get_my_ interface== NULL) {113 if (usb_iface->get_my_description == NULL) { 327 114 async_answer_0(callid, ENOTSUP); 328 115 return; 329 116 } 330 117 331 int iface_no;332 const errno_t ret = usb_iface->get_my_ interface(fun, &iface_no);118 usb_device_desc_t desc; 119 const errno_t ret = usb_iface->get_my_description(fun, &desc); 333 120 if (ret != EOK) { 334 121 async_answer_0(callid, ret); 335 122 } else { 336 async_answer_1(callid, EOK, iface_no); 123 async_answer_5(callid, EOK, 124 (sysarg_t) desc.address, 125 (sysarg_t) desc.depth, 126 (sysarg_t) desc.speed, 127 desc.handle, 128 desc.iface); 337 129 } 338 130 } 339 131 340 void remote_usb_get_my_device_handle(ddf_fun_t *fun, void *iface,341 ipc_callid_t callid, ipc_call_t *call)342 {343 const usb_iface_t *usb_iface = (usb_iface_t *) iface;344 345 if (usb_iface->get_my_device_handle == NULL) {346 async_answer_0(callid, ENOTSUP);347 return;348 }349 350 devman_handle_t handle;351 const errno_t ret = usb_iface->get_my_device_handle(fun, &handle);352 if (ret != EOK) {353 async_answer_0(callid, ret);354 }355 356 async_answer_1(callid, EOK, (sysarg_t) handle);357 }358 359 void remote_usb_reserve_default_address(ddf_fun_t *fun, void *iface,360 ipc_callid_t callid, ipc_call_t *call)361 {362 const usb_iface_t *usb_iface = (usb_iface_t *) iface;363 364 if (usb_iface->reserve_default_address == NULL) {365 async_answer_0(callid, ENOTSUP);366 return;367 }368 369 usb_speed_t speed = DEV_IPC_GET_ARG1(*call);370 const errno_t ret = usb_iface->reserve_default_address(fun, speed);371 async_answer_0(callid, ret);372 }373 374 void remote_usb_release_default_address(ddf_fun_t *fun, void *iface,375 ipc_callid_t callid, ipc_call_t *call)376 {377 const usb_iface_t *usb_iface = (usb_iface_t *) iface;378 379 if (usb_iface->release_default_address == NULL) {380 async_answer_0(callid, ENOTSUP);381 return;382 }383 384 const errno_t ret = usb_iface->release_default_address(fun);385 async_answer_0(callid, ret);386 }387 388 static void remote_usb_device_enumerate(ddf_fun_t *fun, void *iface,389 ipc_callid_t callid, ipc_call_t *call)390 {391 const usb_iface_t *usb_iface = (usb_iface_t *) iface;392 393 if (usb_iface->device_enumerate == NULL) {394 async_answer_0(callid, ENOTSUP);395 return;396 }397 398 const unsigned port = DEV_IPC_GET_ARG1(*call);399 const errno_t ret = usb_iface->device_enumerate(fun, port);400 async_answer_0(callid, ret);401 }402 403 static void remote_usb_device_remove(ddf_fun_t *fun, void *iface,404 ipc_callid_t callid, ipc_call_t *call)405 {406 const usb_iface_t *usb_iface = (usb_iface_t *) iface;407 408 if (usb_iface->device_remove == NULL) {409 async_answer_0(callid, ENOTSUP);410 return;411 }412 413 const unsigned port = DEV_IPC_GET_ARG1(*call);414 const errno_t ret = usb_iface->device_remove(fun, port);415 async_answer_0(callid, ret);416 }417 418 static void remote_usb_register_endpoint(ddf_fun_t *fun, void *iface,419 ipc_callid_t callid, ipc_call_t *call)420 {421 usb_iface_t *usb_iface = (usb_iface_t *) iface;422 423 if (!usb_iface->register_endpoint) {424 async_answer_0(callid, ENOTSUP);425 return;426 }427 428 const usb_endpoint_t endpoint = DEV_IPC_GET_ARG1(*call);429 const pack8_t pack = { .arg = DEV_IPC_GET_ARG2(*call)};430 const size_t max_packet_size = DEV_IPC_GET_ARG3(*call);431 432 const usb_transfer_type_t transfer_type = pack.arr[0];433 const usb_direction_t direction = pack.arr[1];434 unsigned packets = pack.arr[2];435 unsigned interval = pack.arr[3];436 437 const errno_t ret = usb_iface->register_endpoint(fun, endpoint,438 transfer_type, direction, max_packet_size, packets, interval);439 440 async_answer_0(callid, ret);441 }442 443 static void remote_usb_unregister_endpoint(ddf_fun_t *fun, void *iface,444 ipc_callid_t callid, ipc_call_t *call)445 {446 usb_iface_t *usb_iface = (usb_iface_t *) iface;447 448 if (!usb_iface->unregister_endpoint) {449 async_answer_0(callid, ENOTSUP);450 return;451 }452 453 usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG1(*call);454 usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG2(*call);455 456 errno_t rc = usb_iface->unregister_endpoint(fun, endpoint, direction);457 458 async_answer_0(callid, rc);459 }460 461 typedef struct {462 ipc_callid_t caller;463 ipc_callid_t data_caller;464 void *buffer;465 } async_transaction_t;466 467 static void async_transaction_destroy(async_transaction_t *trans)468 {469 if (trans == NULL) {470 return;471 }472 if (trans->buffer != NULL) {473 free(trans->buffer);474 }475 476 free(trans);477 }478 479 static async_transaction_t *async_transaction_create(ipc_callid_t caller)480 {481 async_transaction_t *trans = malloc(sizeof(async_transaction_t));482 if (trans == NULL) {483 return NULL;484 }485 486 trans->caller = caller;487 trans->data_caller = 0;488 trans->buffer = NULL;489 490 return trans;491 }492 493 static void callback_out(errno_t outcome, void *arg)494 {495 async_transaction_t *trans = arg;496 497 async_answer_0(trans->caller, outcome);498 499 async_transaction_destroy(trans);500 }501 502 static void callback_in(errno_t outcome, size_t actual_size, void *arg)503 {504 async_transaction_t *trans = (async_transaction_t *)arg;505 506 if (outcome != EOK) {507 async_answer_0(trans->caller, outcome);508 if (trans->data_caller) {509 async_answer_0(trans->data_caller, EINTR);510 }511 async_transaction_destroy(trans);512 return;513 }514 515 if (trans->data_caller) {516 async_data_read_finalize(trans->data_caller,517 trans->buffer, actual_size);518 }519 520 async_answer_0(trans->caller, EOK);521 522 async_transaction_destroy(trans);523 }524 525 void remote_usb_read(526 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)527 {528 assert(fun);529 assert(iface);530 assert(call);531 532 const usb_iface_t *usb_iface = iface;533 534 if (!usb_iface->read) {535 async_answer_0(callid, ENOTSUP);536 return;537 }538 539 const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);540 const uint64_t setup =541 ((uint64_t)DEV_IPC_GET_ARG2(*call)) |542 (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);543 544 async_transaction_t *trans = async_transaction_create(callid);545 if (trans == NULL) {546 async_answer_0(callid, ENOMEM);547 return;548 }549 550 size_t size = 0;551 if (!async_data_read_receive(&trans->data_caller, &size)) {552 async_answer_0(callid, EPARTY);553 async_transaction_destroy(trans);554 return;555 }556 557 trans->buffer = malloc(size);558 if (trans->buffer == NULL) {559 async_answer_0(trans->data_caller, ENOMEM);560 async_answer_0(callid, ENOMEM);561 async_transaction_destroy(trans);562 return;563 }564 565 const errno_t rc = usb_iface->read(566 fun, ep, setup, trans->buffer, size, callback_in, trans);567 568 if (rc != EOK) {569 async_answer_0(trans->data_caller, rc);570 async_answer_0(callid, rc);571 async_transaction_destroy(trans);572 }573 }574 575 void remote_usb_write(576 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)577 {578 assert(fun);579 assert(iface);580 assert(call);581 582 const usb_iface_t *usb_iface = iface;583 584 if (!usb_iface->write) {585 async_answer_0(callid, ENOTSUP);586 return;587 }588 589 const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);590 const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);591 const uint64_t setup =592 ((uint64_t)DEV_IPC_GET_ARG3(*call)) |593 (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32);594 595 async_transaction_t *trans = async_transaction_create(callid);596 if (trans == NULL) {597 async_answer_0(callid, ENOMEM);598 return;599 }600 601 size_t size = 0;602 if (data_buffer_len > 0) {603 const errno_t rc = async_data_write_accept(&trans->buffer, false,604 1, data_buffer_len, 0, &size);605 606 if (rc != EOK) {607 async_answer_0(callid, rc);608 async_transaction_destroy(trans);609 return;610 }611 }612 613 const errno_t rc = usb_iface->write(614 fun, ep, setup, trans->buffer, size, callback_out, trans);615 616 if (rc != EOK) {617 async_answer_0(callid, rc);618 async_transaction_destroy(trans);619 }620 }621 132 /** 622 133 * @} -
uspace/lib/drv/generic/remote_usbhc.c
rf5e5f73 rdf6ded8 1 1 /* 2 * Copyright (c) 2010 -2011Vojtech Horky2 * Copyright (c) 2010 Vojtech Horky 3 3 * Copyright (c) 2011 Jan Vesely 4 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek 4 5 * All rights reserved. 5 6 * … … 35 36 36 37 #include <async.h> 38 #include <macros.h> 37 39 #include <errno.h> 38 #include < assert.h>39 #include < macros.h>40 #include <devman.h> 41 #include <as.h> 40 42 41 43 #include "usbhc_iface.h" 42 44 #include "ddf/driver.h" 43 45 44 #define USB_MAX_PAYLOAD_SIZE 1020 45 46 /** IPC methods for communication with HC through DDF interface. 47 * 48 * Notes for async methods: 49 * 50 * Methods for sending data to device (OUT transactions) 51 * - e.g. IPC_M_USBHC_INTERRUPT_OUT - 52 * always use the same semantics: 53 * - first, IPC call with given method is made 54 * - argument #1 is target address 55 * - argument #2 is target endpoint 56 * - argument #3 is max packet size of the endpoint 57 * - this call is immediately followed by IPC data write (from caller) 58 * - the initial call (and the whole transaction) is answer after the 59 * transaction is scheduled by the HC and acknowledged by the device 60 * or immediately after error is detected 61 * - the answer carries only the error code 62 * 63 * Methods for retrieving data from device (IN transactions) 64 * - e.g. IPC_M_USBHC_INTERRUPT_IN - 65 * also use the same semantics: 66 * - first, IPC call with given method is made 67 * - argument #1 is target address 68 * - argument #2 is target endpoint 69 * - this call is immediately followed by IPC data read (async version) 70 * - the call is not answered until the device returns some data (or until 71 * error occurs) 72 * 73 * Some special methods (NO-DATA transactions) do not send any data. These 74 * might behave as both OUT or IN transactions because communication parts 75 * where actual buffers are exchanged are omitted. 76 ** 77 * For all these methods, wrap functions exists. Important rule: functions 78 * for IN transactions have (as parameters) buffers where retrieved data 79 * will be stored. These buffers must be already allocated and shall not be 80 * touch until the transaction is completed 81 * (e.g. not before calling usb_wait_for() with appropriate handle). 82 * OUT transactions buffers can be freed immediately after call is dispatched 83 * (i.e. after return from wrapping function). 84 * 85 */ 46 86 47 typedef enum { 87 /** Get data from device. 88 * See explanation at usb_iface_funcs_t (IN transaction). 89 */ 90 IPC_M_USBHC_READ, 91 92 /** Send data to device. 93 * See explanation at usb_iface_funcs_t (OUT transaction). 94 */ 95 IPC_M_USBHC_WRITE, 48 IPC_M_USB_DEFAULT_ADDRESS_RESERVATION, 49 IPC_M_USB_DEVICE_ENUMERATE, 50 IPC_M_USB_DEVICE_REMOVE, 51 IPC_M_USB_REGISTER_ENDPOINT, 52 IPC_M_USB_UNREGISTER_ENDPOINT, 53 IPC_M_USB_TRANSFER, 96 54 } usbhc_iface_funcs_t; 97 55 98 errno_t usbhc_read(async_exch_t *exch, usb_address_t address, 99 usb_endpoint_t endpoint, uint64_t setup, void *data, size_t size, 100 size_t *rec_size) 101 { 102 if (!exch) 103 return EBADMEM; 104 105 if (size == 0 && setup == 0) 106 return EOK; 107 108 const usb_target_t target = 109 {{ .address = address, .endpoint = endpoint }}; 110 111 /* Make call identifying target USB device and type of transfer. */ 112 aid_t opening_request = async_send_4(exch, 113 DEV_IFACE_ID(USBHC_DEV_IFACE), 114 IPC_M_USBHC_READ, target.packed, 115 (setup & UINT32_MAX), (setup >> 32), NULL); 56 /** Reserve default USB address. 57 * @param[in] exch IPC communication exchange 58 * @return Error code. 59 */ 60 errno_t usbhc_reserve_default_address(async_exch_t *exch) 61 { 62 if (!exch) 63 return EBADMEM; 64 return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_DEFAULT_ADDRESS_RESERVATION, true); 65 } 66 67 /** Release default USB address. 68 * 69 * @param[in] exch IPC communication exchange 70 * 71 * @return Error code. 72 */ 73 errno_t usbhc_release_default_address(async_exch_t *exch) 74 { 75 if (!exch) 76 return EBADMEM; 77 return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_DEFAULT_ADDRESS_RESERVATION, false); 78 } 79 80 /** 81 * Trigger USB device enumeration 82 * 83 * @param[in] exch IPC communication exchange 84 * @param[in] port Port number at which the device is attached 85 * @param[in] speed Communication speed of the newly attached device 86 * 87 * @return Error code. 88 */ 89 errno_t usbhc_device_enumerate(async_exch_t *exch, unsigned port, usb_speed_t speed) 90 { 91 if (!exch) 92 return EBADMEM; 93 const errno_t ret = async_req_3_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), 94 IPC_M_USB_DEVICE_ENUMERATE, port, speed); 95 return ret; 96 } 97 98 /** Trigger USB device enumeration 99 * 100 * @param[in] exch IPC communication exchange 101 * @param[in] handle Identifier of the device 102 * 103 * @return Error code. 104 * 105 */ 106 errno_t usbhc_device_remove(async_exch_t *exch, unsigned port) 107 { 108 if (!exch) 109 return EBADMEM; 110 return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), 111 IPC_M_USB_DEVICE_REMOVE, port); 112 } 113 114 errno_t usbhc_register_endpoint(async_exch_t *exch, usb_pipe_desc_t *pipe_desc, 115 const usb_endpoint_descriptors_t *desc) 116 { 117 if (!exch) 118 return EBADMEM; 119 120 if (!desc) 121 return EINVAL; 122 123 aid_t opening_request = async_send_1(exch, 124 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_REGISTER_ENDPOINT, NULL); 116 125 117 126 if (opening_request == 0) { … … 119 128 } 120 129 121 /* Retrieve the data. */ 122 ipc_call_t data_request_call; 123 aid_t data_request = 124 async_data_read(exch, data, size, &data_request_call); 125 126 if (data_request == 0) { 127 // FIXME: How to let the other side know that we want to abort? 130 errno_t ret = async_data_write_start(exch, desc, sizeof(*desc)); 131 if (ret != EOK) { 128 132 async_forget(opening_request); 129 return ENOMEM;133 return ret; 130 134 } 131 135 132 136 /* Wait for the answer. */ 133 errno_t data_request_rc;134 137 errno_t opening_request_rc; 135 async_wait_for(data_request, &data_request_rc);136 138 async_wait_for(opening_request, &opening_request_rc); 137 139 138 if (data_request_rc != EOK) { 139 /* Prefer the return code of the opening request. */ 140 if (opening_request_rc != EOK) { 141 return (errno_t) opening_request_rc; 142 } else { 143 return (errno_t) data_request_rc; 144 } 145 } 146 if (opening_request_rc != EOK) { 140 if (opening_request_rc) 147 141 return (errno_t) opening_request_rc; 148 } 149 150 *rec_size = IPC_GET_ARG2(data_request_call); 142 143 usb_pipe_desc_t dest; 144 ret = async_data_read_start(exch, &dest, sizeof(dest)); 145 if (ret != EOK) { 146 return ret; 147 } 148 149 if (pipe_desc) 150 *pipe_desc = dest; 151 151 152 return EOK; 152 153 } 153 154 154 errno_t usbhc_write(async_exch_t *exch, usb_address_t address, 155 usb_endpoint_t endpoint, uint64_t setup, const void *data, size_t size) 156 { 157 if (!exch) 158 return EBADMEM; 159 160 if (size == 0 && setup == 0) 161 return EOK; 162 163 const usb_target_t target = 164 {{ .address = address, .endpoint = endpoint }}; 165 166 aid_t opening_request = async_send_5(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), 167 IPC_M_USBHC_WRITE, target.packed, size, 168 (setup & UINT32_MAX), (setup >> 32), NULL); 155 errno_t usbhc_unregister_endpoint(async_exch_t *exch, const usb_pipe_desc_t *pipe_desc) 156 { 157 if (!exch) 158 return EBADMEM; 159 160 aid_t opening_request = async_send_1(exch, 161 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_UNREGISTER_ENDPOINT, NULL); 169 162 170 163 if (opening_request == 0) { … … 172 165 } 173 166 174 /* Send the data if any. */ 175 if (size > 0) { 176 const errno_t ret = async_data_write_start(exch, data, size); 167 const errno_t ret = async_data_write_start(exch, pipe_desc, sizeof(*pipe_desc)); 168 if (ret != EOK) { 169 async_forget(opening_request); 170 return ret; 171 } 172 173 /* Wait for the answer. */ 174 errno_t opening_request_rc; 175 async_wait_for(opening_request, &opening_request_rc); 176 177 return (errno_t) opening_request_rc; 178 } 179 180 /** 181 * Issue a USB transfer with a data contained in memory area. That area is 182 * temporarily shared with the HC. 183 */ 184 errno_t usbhc_transfer(async_exch_t *exch, 185 const usbhc_iface_transfer_request_t *req, size_t *transferred) 186 { 187 if (transferred) 188 *transferred = 0; 189 190 if (!exch) 191 return EBADMEM; 192 193 ipc_call_t call; 194 195 aid_t opening_request = async_send_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), 196 IPC_M_USB_TRANSFER, &call); 197 198 if (opening_request == 0) 199 return ENOMEM; 200 201 const errno_t ret = async_data_write_start(exch, req, sizeof(*req)); 202 if (ret != EOK) { 203 async_forget(opening_request); 204 return ret; 205 } 206 207 /* Share the data, if any. */ 208 if (req->size > 0) { 209 unsigned flags = (req->dir == USB_DIRECTION_IN) 210 ? AS_AREA_WRITE : AS_AREA_READ; 211 212 const errno_t ret = async_share_out_start(exch, req->buffer.virt, flags); 177 213 if (ret != EOK) { 178 214 async_forget(opening_request); … … 185 221 async_wait_for(opening_request, &opening_request_rc); 186 222 223 if (transferred) 224 *transferred = IPC_GET_ARG1(call); 225 187 226 return (errno_t) opening_request_rc; 188 227 } 189 228 190 static void remote_usbhc_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 191 static void remote_usbhc_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 192 193 /** Remote USB host controller interface operations. */ 194 static const remote_iface_func_ptr_t remote_usbhc_iface_ops[] = { 195 [IPC_M_USBHC_READ] = remote_usbhc_read, 196 [IPC_M_USBHC_WRITE] = remote_usbhc_write, 229 static void remote_usbhc_default_address_reservation(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 230 static void remote_usbhc_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 231 static void remote_usbhc_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 232 static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 233 static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 234 static void remote_usbhc_transfer(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call); 235 236 /** Remote USB interface operations. */ 237 static const remote_iface_func_ptr_t remote_usbhc_iface_ops [] = { 238 [IPC_M_USB_DEFAULT_ADDRESS_RESERVATION] = remote_usbhc_default_address_reservation, 239 [IPC_M_USB_DEVICE_ENUMERATE] = remote_usbhc_device_enumerate, 240 [IPC_M_USB_DEVICE_REMOVE] = remote_usbhc_device_remove, 241 [IPC_M_USB_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint, 242 [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usbhc_unregister_endpoint, 243 [IPC_M_USB_TRANSFER] = remote_usbhc_transfer, 197 244 }; 198 245 199 /** Remote USB host controllerinterface structure.246 /** Remote USB interface structure. 200 247 */ 201 248 const remote_iface_t remote_usbhc_iface = { 202 249 .method_count = ARRAY_SIZE(remote_usbhc_iface_ops), 203 .methods = remote_usbhc_iface_ops 250 .methods = remote_usbhc_iface_ops, 204 251 }; 205 252 206 253 typedef struct { 207 254 ipc_callid_t caller; 208 ipc_callid_t data_caller; 209 void *buffer; 255 usbhc_iface_transfer_request_t request; 210 256 } async_transaction_t; 211 257 212 static void async_transaction_destroy(async_transaction_t *trans) 213 { 214 if (trans == NULL) 215 return; 216 217 if (trans->buffer != NULL) 218 free(trans->buffer); 219 220 free(trans); 221 } 222 223 static async_transaction_t *async_transaction_create(ipc_callid_t caller) 224 { 225 async_transaction_t *trans = malloc(sizeof(async_transaction_t)); 226 if (trans == NULL) { 227 return NULL; 228 } 229 230 trans->caller = caller; 231 trans->data_caller = 0; 232 trans->buffer = NULL; 233 234 return trans; 235 } 236 237 static void callback_out(errno_t outcome, void *arg) 238 { 239 async_transaction_t *trans = arg; 240 241 async_answer_0(trans->caller, outcome); 242 243 async_transaction_destroy(trans); 244 } 245 246 static void callback_in(errno_t outcome, size_t actual_size, void *arg) 247 { 248 async_transaction_t *trans = (async_transaction_t *)arg; 249 250 if (outcome != EOK) { 251 async_answer_0(trans->caller, outcome); 252 if (trans->data_caller) { 253 async_answer_0(trans->data_caller, EINTR); 254 } 255 async_transaction_destroy(trans); 256 return; 257 } 258 259 if (trans->data_caller) { 260 async_data_read_finalize(trans->data_caller, 261 trans->buffer, actual_size); 262 } 263 264 async_answer_0(trans->caller, EOK); 265 266 async_transaction_destroy(trans); 267 } 268 269 void remote_usbhc_read( 270 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) 258 void remote_usbhc_default_address_reservation(ddf_fun_t *fun, void *iface, 259 ipc_callid_t callid, ipc_call_t *call) 260 { 261 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface; 262 263 if (usbhc_iface->default_address_reservation == NULL) { 264 async_answer_0(callid, ENOTSUP); 265 return; 266 } 267 268 const bool reserve = IPC_GET_ARG2(*call); 269 const errno_t ret = usbhc_iface->default_address_reservation(fun, reserve); 270 async_answer_0(callid, ret); 271 } 272 273 274 static void remote_usbhc_device_enumerate(ddf_fun_t *fun, void *iface, 275 ipc_callid_t callid, ipc_call_t *call) 276 { 277 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface; 278 279 if (usbhc_iface->device_enumerate == NULL) { 280 async_answer_0(callid, ENOTSUP); 281 return; 282 } 283 284 const unsigned port = DEV_IPC_GET_ARG1(*call); 285 usb_speed_t speed = DEV_IPC_GET_ARG2(*call); 286 const errno_t ret = usbhc_iface->device_enumerate(fun, port, speed); 287 async_answer_0(callid, ret); 288 } 289 290 static void remote_usbhc_device_remove(ddf_fun_t *fun, void *iface, 291 ipc_callid_t callid, ipc_call_t *call) 292 { 293 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface; 294 295 if (usbhc_iface->device_remove == NULL) { 296 async_answer_0(callid, ENOTSUP); 297 return; 298 } 299 300 const unsigned port = DEV_IPC_GET_ARG1(*call); 301 const errno_t ret = usbhc_iface->device_remove(fun, port); 302 async_answer_0(callid, ret); 303 } 304 305 static void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface, 306 ipc_callid_t callid, ipc_call_t *call) 271 307 { 272 308 assert(fun); … … 274 310 assert(call); 275 311 276 const usbhc_iface_t * hc_iface = iface;277 278 if (! hc_iface->read) {312 const usbhc_iface_t *usbhc_iface = iface; 313 314 if (!usbhc_iface->register_endpoint) { 279 315 async_answer_0(callid, ENOTSUP); 280 316 return; 281 317 } 282 318 283 const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) }; 284 const uint64_t setup = 285 ((uint64_t)DEV_IPC_GET_ARG2(*call)) | 286 (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32); 319 usb_endpoint_descriptors_t ep_desc; 320 ipc_callid_t data_callid; 321 size_t len; 322 323 if (!async_data_write_receive(&data_callid, &len) 324 || len != sizeof(ep_desc)) { 325 async_answer_0(callid, EINVAL); 326 return; 327 } 328 async_data_write_finalize(data_callid, &ep_desc, sizeof(ep_desc)); 329 330 usb_pipe_desc_t pipe_desc; 331 332 const errno_t rc = usbhc_iface->register_endpoint(fun, &pipe_desc, &ep_desc); 333 async_answer_0(callid, rc); 334 335 if (!async_data_read_receive(&data_callid, &len) 336 || len != sizeof(pipe_desc)) { 337 return; 338 } 339 async_data_read_finalize(data_callid, &pipe_desc, sizeof(pipe_desc)); 340 } 341 342 static void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface, 343 ipc_callid_t callid, ipc_call_t *call) 344 { 345 assert(fun); 346 assert(iface); 347 assert(call); 348 349 const usbhc_iface_t *usbhc_iface = iface; 350 351 if (!usbhc_iface->unregister_endpoint) { 352 async_answer_0(callid, ENOTSUP); 353 return; 354 } 355 356 usb_pipe_desc_t pipe_desc; 357 ipc_callid_t data_callid; 358 size_t len; 359 360 if (!async_data_write_receive(&data_callid, &len) 361 || len != sizeof(pipe_desc)) { 362 async_answer_0(callid, EINVAL); 363 return; 364 } 365 async_data_write_finalize(data_callid, &pipe_desc, sizeof(pipe_desc)); 366 367 const errno_t rc = usbhc_iface->unregister_endpoint(fun, &pipe_desc); 368 async_answer_0(callid, rc); 369 } 370 371 static void async_transaction_destroy(async_transaction_t *trans) 372 { 373 if (trans == NULL) { 374 return; 375 } 376 if (trans->request.buffer.virt != NULL) { 377 as_area_destroy(trans->request.buffer.virt); 378 } 379 380 free(trans); 381 } 382 383 static async_transaction_t *async_transaction_create(ipc_callid_t caller) 384 { 385 async_transaction_t *trans = calloc(1, sizeof(async_transaction_t)); 386 387 if (trans != NULL) 388 trans->caller = caller; 389 390 return trans; 391 } 392 393 static errno_t transfer_finished(void *arg, errno_t error, size_t transferred_size) 394 { 395 async_transaction_t *trans = arg; 396 const errno_t err = async_answer_1(trans->caller, error, transferred_size); 397 async_transaction_destroy(trans); 398 return err; 399 } 400 401 static errno_t receive_memory_buffer(async_transaction_t *trans) 402 { 403 assert(trans); 404 assert(trans->request.size > 0); 405 406 const size_t required_size = trans->request.offset + trans->request.size; 407 const unsigned required_flags = 408 (trans->request.dir == USB_DIRECTION_IN) 409 ? AS_AREA_WRITE : AS_AREA_READ; 410 411 errno_t err; 412 ipc_callid_t data_callid; 413 size_t size; 414 unsigned flags; 415 416 if (!async_share_out_receive(&data_callid, &size, &flags)) 417 return EPARTY; 418 419 if (size < required_size || (flags & required_flags) != required_flags) { 420 async_answer_0(data_callid, EINVAL); 421 return EINVAL; 422 } 423 424 if ((err = async_share_out_finalize(data_callid, &trans->request.buffer.virt))) 425 return err; 426 427 /* 428 * As we're going to get physical addresses of the mapping, we must make 429 * sure the memory is actually mapped. We must do it right now, because 430 * the area might be read-only or write-only, and we may be unsure 431 * later. 432 */ 433 if (flags & AS_AREA_READ) { 434 char foo = 0; 435 volatile const char *buf = trans->request.buffer.virt + trans->request.offset; 436 for (size_t i = 0; i < size; i += PAGE_SIZE) 437 foo += buf[i]; 438 } else { 439 volatile char *buf = trans->request.buffer.virt + trans->request.offset; 440 for (size_t i = 0; i < size; i += PAGE_SIZE) 441 buf[i] = 0xff; 442 } 443 444 return EOK; 445 } 446 447 void remote_usbhc_transfer(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) 448 { 449 assert(fun); 450 assert(iface); 451 assert(call); 452 453 const usbhc_iface_t *usbhc_iface = iface; 454 455 if (!usbhc_iface->transfer) { 456 async_answer_0(callid, ENOTSUP); 457 return; 458 } 287 459 288 460 async_transaction_t *trans = async_transaction_create(callid); … … 292 464 } 293 465 294 size_t size = 0; 295 if (!async_data_read_receive(&trans->data_caller, &size)) { 296 async_answer_0(callid, EPARTY); 297 return; 298 } 299 300 trans->buffer = malloc(size); 301 if (trans->buffer == NULL) { 302 async_answer_0(trans->data_caller, ENOMEM); 303 async_answer_0(callid, ENOMEM); 304 async_transaction_destroy(trans); 305 return; 306 } 307 308 const errno_t rc = hc_iface->read( 309 fun, target, setup, trans->buffer, size, callback_in, trans); 310 311 if (rc != EOK) { 312 async_answer_0(trans->data_caller, rc); 313 async_answer_0(callid, rc); 314 async_transaction_destroy(trans); 315 } 316 } 317 318 void remote_usbhc_write( 319 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) 320 { 321 assert(fun); 322 assert(iface); 323 assert(call); 324 325 const usbhc_iface_t *hc_iface = iface; 326 327 if (!hc_iface->write) { 328 async_answer_0(callid, ENOTSUP); 329 return; 330 } 331 332 const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) }; 333 const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call); 334 const uint64_t setup = 335 ((uint64_t)DEV_IPC_GET_ARG3(*call)) | 336 (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32); 337 338 async_transaction_t *trans = async_transaction_create(callid); 339 if (trans == NULL) { 340 async_answer_0(callid, ENOMEM); 341 return; 342 } 343 344 size_t size = 0; 345 if (data_buffer_len > 0) { 346 const errno_t rc = async_data_write_accept(&trans->buffer, false, 347 1, USB_MAX_PAYLOAD_SIZE, 348 0, &size); 349 350 if (rc != EOK) { 351 async_answer_0(callid, rc); 352 async_transaction_destroy(trans); 353 return; 354 } 355 } 356 357 const errno_t rc = hc_iface->write( 358 fun, target, setup, trans->buffer, size, callback_out, trans); 359 360 if (rc != EOK) { 361 async_answer_0(callid, rc); 362 async_transaction_destroy(trans); 363 } 364 } 466 errno_t err = EPARTY; 467 468 ipc_callid_t data_callid; 469 size_t len; 470 if (!async_data_write_receive(&data_callid, &len) 471 || len != sizeof(trans->request)) { 472 async_answer_0(data_callid, EINVAL); 473 goto err; 474 } 475 476 if ((err = async_data_write_finalize(data_callid, 477 &trans->request, sizeof(trans->request)))) 478 goto err; 479 480 if (trans->request.size > 0) { 481 if ((err = receive_memory_buffer(trans))) 482 goto err; 483 } else { 484 /* The value was valid on the other side, for us, its garbage. */ 485 trans->request.buffer.virt = NULL; 486 } 487 488 if ((err = usbhc_iface->transfer(fun, &trans->request, 489 &transfer_finished, trans))) 490 goto err; 491 492 /* The call will be answered asynchronously by the callback. */ 493 return; 494 495 err: 496 async_answer_0(callid, err); 497 async_transaction_destroy(trans); 498 } 499 365 500 /** 366 501 * @} -
uspace/lib/drv/include/usb_iface.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2010 Vojtech Horky 3 * Copyright (c) 2018 Ondrej Hlavaty, Michal Staruch 3 4 * All rights reserved. 4 5 * … … 32 33 */ 33 34 /** @file 34 * @brief USB interface definition.35 * @brief USB device interface definition. 35 36 */ 36 37 … … 40 41 #include "ddf/driver.h" 41 42 #include <async.h> 43 #include <usbhc_iface.h> 42 44 43 45 typedef async_sess_t usb_dev_session_t; 44 46 45 /** USB speeds. */ 46 typedef enum { 47 /** USB 1.1 low speed (1.5Mbits/s). */ 48 USB_SPEED_LOW, 49 /** USB 1.1 full speed (12Mbits/s). */ 50 USB_SPEED_FULL, 51 /** USB 2.0 high speed (480Mbits/s). */ 52 USB_SPEED_HIGH, 53 /** Psuedo-speed serving as a boundary. */ 54 USB_SPEED_MAX 55 } usb_speed_t; 56 57 /** USB endpoint number type. 58 * Negative values could be used to indicate error. 59 */ 60 typedef int16_t usb_endpoint_t; 61 62 /** USB address type. 63 * Negative values could be used to indicate error. 64 */ 65 typedef int16_t usb_address_t; 66 67 /** USB transfer type. */ 68 typedef enum { 69 USB_TRANSFER_CONTROL = 0, 70 USB_TRANSFER_ISOCHRONOUS = 1, 71 USB_TRANSFER_BULK = 2, 72 USB_TRANSFER_INTERRUPT = 3 73 } usb_transfer_type_t; 74 75 /** USB data transfer direction. */ 76 typedef enum { 77 USB_DIRECTION_IN, 78 USB_DIRECTION_OUT, 79 USB_DIRECTION_BOTH 80 } usb_direction_t; 81 82 /** USB complete address type. 83 * Pair address + endpoint is identification of transaction recipient. 84 */ 85 typedef union { 86 struct { 87 usb_address_t address; 88 usb_endpoint_t endpoint; 89 } __attribute__((packed)); 90 uint32_t packed; 91 } usb_target_t; 47 typedef struct { 48 usb_address_t address; /**< Current USB address */ 49 uint8_t depth; /**< Depth in the hub hiearchy */ 50 usb_speed_t speed; /**< Speed of the device */ 51 devman_handle_t handle; /**< Handle to DDF function of the HC driver */ 52 /** Interface set by multi interface driver, -1 if none */ 53 int iface; 54 } usb_device_desc_t; 92 55 93 56 extern usb_dev_session_t *usb_dev_connect(devman_handle_t); … … 95 58 extern void usb_dev_disconnect(usb_dev_session_t *); 96 59 97 extern errno_t usb_get_my_interface(async_exch_t *, int *); 98 extern errno_t usb_get_my_device_handle(async_exch_t *, devman_handle_t *); 99 100 extern errno_t usb_reserve_default_address(async_exch_t *, usb_speed_t); 101 extern errno_t usb_release_default_address(async_exch_t *); 102 103 extern errno_t usb_device_enumerate(async_exch_t *, unsigned port); 104 extern errno_t usb_device_remove(async_exch_t *, unsigned port); 105 106 extern errno_t usb_register_endpoint(async_exch_t *, usb_endpoint_t, 107 usb_transfer_type_t, usb_direction_t, size_t, unsigned, unsigned); 108 extern errno_t usb_unregister_endpoint(async_exch_t *, usb_endpoint_t, 109 usb_direction_t); 110 extern errno_t usb_read(async_exch_t *, usb_endpoint_t, uint64_t, void *, size_t, 111 size_t *); 112 extern errno_t usb_write(async_exch_t *, usb_endpoint_t, uint64_t, const void *, 113 size_t); 114 115 /** Callback for outgoing transfer. */ 116 typedef void (*usb_iface_transfer_out_callback_t)(errno_t, void *); 117 118 /** Callback for incoming transfer. */ 119 typedef void (*usb_iface_transfer_in_callback_t)(errno_t, size_t, void *); 60 extern errno_t usb_get_my_description(async_exch_t *, usb_device_desc_t *); 120 61 121 62 /** USB device communication interface. */ 122 63 typedef struct { 123 errno_t (*get_my_interface)(ddf_fun_t *, int *); 124 errno_t (*get_my_device_handle)(ddf_fun_t *, devman_handle_t *); 125 126 errno_t (*reserve_default_address)(ddf_fun_t *, usb_speed_t); 127 errno_t (*release_default_address)(ddf_fun_t *); 128 129 errno_t (*device_enumerate)(ddf_fun_t *, unsigned); 130 errno_t (*device_remove)(ddf_fun_t *, unsigned); 131 132 errno_t (*register_endpoint)(ddf_fun_t *, usb_endpoint_t, 133 usb_transfer_type_t, usb_direction_t, size_t, unsigned, unsigned); 134 errno_t (*unregister_endpoint)(ddf_fun_t *, usb_endpoint_t, 135 usb_direction_t); 136 137 errno_t (*read)(ddf_fun_t *, usb_endpoint_t, uint64_t, uint8_t *, size_t, 138 usb_iface_transfer_in_callback_t, void *); 139 errno_t (*write)(ddf_fun_t *, usb_endpoint_t, uint64_t, const uint8_t *, 140 size_t, usb_iface_transfer_out_callback_t, void *); 64 errno_t (*get_my_description)(ddf_fun_t *, usb_device_desc_t *); 141 65 } usb_iface_t; 142 66 -
uspace/lib/drv/include/usbhc_iface.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2010 Vojtech Horky 3 * Copyright (c) 201 1 Jan Vesely3 * Copyright (c) 2017 Ondrej Hlavaty 4 4 * All rights reserved. 5 5 * … … 32 32 * @{ 33 33 */ 34 35 34 /** @file 36 * @brief USB host controller interface definition. 35 * @brief USB host controler interface definition. This is the interface of 36 * USB host controller function, which can be used by usb device drivers. 37 37 */ 38 38 … … 41 41 42 42 #include "ddf/driver.h" 43 #include <usb_iface.h> 44 #include <stdbool.h> 45 46 extern errno_t usbhc_read(async_exch_t *, usb_address_t, usb_endpoint_t, 47 uint64_t, void *, size_t, size_t *); 48 extern errno_t usbhc_write(async_exch_t *, usb_address_t, usb_endpoint_t, 49 uint64_t, const void *, size_t); 50 51 /** Callback for outgoing transfer. */ 52 typedef void (*usbhc_iface_transfer_out_callback_t)(errno_t, void *); 53 54 /** Callback for incoming transfer. */ 55 typedef void (*usbhc_iface_transfer_in_callback_t)(errno_t, size_t, void *); 56 57 /** USB host controller communication interface. */ 43 #include <async.h> 44 45 /** USB speeds. */ 46 typedef enum { 47 /** USB 1.1 low speed (1.5Mbits/s). */ 48 USB_SPEED_LOW, 49 /** USB 1.1 full speed (12Mbits/s). */ 50 USB_SPEED_FULL, 51 /** USB 2.0 high speed (480Mbits/s). */ 52 USB_SPEED_HIGH, 53 /** USB 3.0 super speed (5Gbits/s). */ 54 USB_SPEED_SUPER, 55 /** Psuedo-speed serving as a boundary. */ 56 USB_SPEED_MAX 57 } usb_speed_t; 58 59 /** USB endpoint number type. 60 * Negative values could be used to indicate error. 61 */ 62 typedef uint16_t usb_endpoint_t; 63 64 /** USB address type. 65 * Negative values could be used to indicate error. 66 */ 67 typedef uint16_t usb_address_t; 68 69 /** 70 * USB Stream ID type. 71 */ 72 typedef uint16_t usb_stream_t; 73 74 /** USB transfer type. */ 75 typedef enum { 76 USB_TRANSFER_CONTROL = 0, 77 USB_TRANSFER_ISOCHRONOUS = 1, 78 USB_TRANSFER_BULK = 2, 79 USB_TRANSFER_INTERRUPT = 3, 80 } usb_transfer_type_t; 81 82 #define USB_TRANSFER_COUNT (USB_TRANSFER_INTERRUPT + 1) 83 84 /** USB data transfer direction. */ 85 typedef enum { 86 USB_DIRECTION_IN, 87 USB_DIRECTION_OUT, 88 USB_DIRECTION_BOTH, 89 } usb_direction_t; 90 91 #define USB_DIRECTION_COUNT (USB_DIRECTION_BOTH + 1) 92 93 /** USB complete address type. 94 * Pair address + endpoint is identification of transaction recipient. 95 */ 96 typedef union { 97 struct { 98 usb_address_t address; 99 usb_endpoint_t endpoint; 100 usb_stream_t stream; 101 } __attribute__((packed)); 102 uint64_t packed; 103 } usb_target_t; 104 105 // FIXME: DMA buffers shall be part of libdrv anyway. 106 typedef uintptr_t dma_policy_t; 107 108 typedef struct dma_buffer { 109 void *virt; 110 dma_policy_t policy; 111 } dma_buffer_t; 112 113 typedef struct usb_pipe_desc { 114 /** Endpoint number. */ 115 usb_endpoint_t endpoint_no; 116 117 /** Endpoint transfer type. */ 118 usb_transfer_type_t transfer_type; 119 120 /** Endpoint direction. */ 121 usb_direction_t direction; 122 123 /** 124 * Maximum size of one transfer. Non-periodic endpoints may handle 125 * bigger transfers, but those can be split into multiple USB transfers. 126 */ 127 size_t max_transfer_size; 128 129 /** Constraints on buffers to be transferred without copying */ 130 dma_policy_t transfer_buffer_policy; 131 } usb_pipe_desc_t; 132 133 typedef struct usb_pipe_transfer_request { 134 usb_direction_t dir; 135 usb_endpoint_t endpoint; 136 usb_stream_t stream; 137 138 uint64_t setup; /**< Valid iff the transfer is of control type */ 139 140 /** 141 * The DMA buffer to share. Must be at least offset + size large. Is 142 * patched after being transmitted over IPC, so the pointer is still 143 * valid. 144 */ 145 dma_buffer_t buffer; 146 size_t offset; /**< Offset to the buffer */ 147 size_t size; /**< Requested size. */ 148 } usbhc_iface_transfer_request_t; 149 150 /** This structure follows standard endpoint descriptor + superspeed companion 151 * descriptor, and exists to avoid dependency of libdrv on libusb. Keep the 152 * internal fields named exactly like their source (because we want to use the 153 * same macros to access them). 154 * Callers shall fill it with bare contents of respective descriptors (in usb endianity). 155 */ 156 typedef struct usb_endpoint_descriptors { 157 struct { 158 uint8_t endpoint_address; 159 uint8_t attributes; 160 uint16_t max_packet_size; 161 uint8_t poll_interval; 162 } endpoint; 163 164 /* Superspeed companion descriptor */ 165 struct companion_desc_t { 166 uint8_t max_burst; 167 uint8_t attributes; 168 uint16_t bytes_per_interval; 169 } companion; 170 } usb_endpoint_descriptors_t; 171 172 extern errno_t usbhc_reserve_default_address(async_exch_t *); 173 extern errno_t usbhc_release_default_address(async_exch_t *); 174 175 extern errno_t usbhc_device_enumerate(async_exch_t *, unsigned, usb_speed_t); 176 extern errno_t usbhc_device_remove(async_exch_t *, unsigned); 177 178 extern errno_t usbhc_register_endpoint(async_exch_t *, usb_pipe_desc_t *, const usb_endpoint_descriptors_t *); 179 extern errno_t usbhc_unregister_endpoint(async_exch_t *, const usb_pipe_desc_t *); 180 181 extern errno_t usbhc_transfer(async_exch_t *, const usbhc_iface_transfer_request_t *, size_t *); 182 183 /** Callback for outgoing transfer */ 184 typedef errno_t (*usbhc_iface_transfer_callback_t)(void *, int, size_t); 185 186 /** USB device communication interface. */ 58 187 typedef struct { 59 errno_t (*read)(ddf_fun_t *, usb_target_t, uint64_t, uint8_t *, size_t, 60 usbhc_iface_transfer_in_callback_t, void *); 61 errno_t (*write)(ddf_fun_t *, usb_target_t, uint64_t, const uint8_t *, 62 size_t, usbhc_iface_transfer_out_callback_t, void *); 188 errno_t (*default_address_reservation)(ddf_fun_t *, bool); 189 190 errno_t (*device_enumerate)(ddf_fun_t *, unsigned, usb_speed_t); 191 errno_t (*device_remove)(ddf_fun_t *, unsigned); 192 193 errno_t (*register_endpoint)(ddf_fun_t *, usb_pipe_desc_t *, const usb_endpoint_descriptors_t *); 194 errno_t (*unregister_endpoint)(ddf_fun_t *, const usb_pipe_desc_t *); 195 196 errno_t (*transfer)(ddf_fun_t *, const usbhc_iface_transfer_request_t *, 197 usbhc_iface_transfer_callback_t, void *); 63 198 } usbhc_iface_t; 64 65 199 66 200 #endif -
uspace/lib/pcm/src/format.c
rf5e5f73 rdf6ded8 41 41 42 42 #include "format.h" 43 44 #define uint8_t_le2host(x) (x)45 #define host2uint8_t_le(x) (x)46 #define uint8_t_be2host(x) (x)47 #define host2uint8_t_be(x) (x)48 49 #define int8_t_le2host(x) (x)50 #define host2int8_t_le(x) (x)51 52 #define int16_t_le2host(x) uint16_t_le2host(x)53 #define host2int16_t_le(x) host2uint16_t_le(x)54 55 #define int32_t_le2host(x) uint32_t_le2host(x)56 #define host2int32_t_le(x) host2uint32_t_le(x)57 58 #define int8_t_be2host(x) (x)59 #define host2int8_t_be(x) (x)60 61 #define int16_t_be2host(x) uint16_t_be2host(x)62 #define host2int16_t_be(x) host2uint16_t_be(x)63 64 #define int32_t_be2host(x) uint32_t_be2host(x)65 #define host2int32_t_be(x) host2uint32_t_be(x)66 43 67 44 // TODO float endian? -
uspace/lib/usb/Makefile
rf5e5f73 rdf6ded8 35 35 src/dev.c \ 36 36 src/debug.c \ 37 src/dma_buffer.c \ 37 38 src/dump.c \ 39 src/port.c \ 38 40 src/usb.c 39 41 -
uspace/lib/usb/include/usb/classes/hub.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2010 Matus Dekanek 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 48 49 USB_HUB_FEATURE_HUB_OVER_CURRENT = 1, 49 50 USB_HUB_FEATURE_PORT_CONNECTION = 0, 50 USB _HUB_FEATURE_PORT_ENABLE = 1,51 USB _HUB_FEATURE_PORT_SUSPEND = 2,51 USB2_HUB_FEATURE_PORT_ENABLE = 1, 52 USB2_HUB_FEATURE_PORT_SUSPEND = 2, 52 53 USB_HUB_FEATURE_PORT_OVER_CURRENT = 3, 53 54 USB_HUB_FEATURE_PORT_RESET = 4, 55 USB3_HUB_FEATURE_PORT_LINK_STATE = 5, 54 56 USB_HUB_FEATURE_PORT_POWER = 8, 55 USB_HUB_FEATURE_PORT_LOW_SPEED = 9, 56 USB_HUB_FEATURE_PORT_HIGH_SPEED = 10, 57 USB2_HUB_FEATURE_PORT_LOW_SPEED = 9, 57 58 USB_HUB_FEATURE_C_PORT_CONNECTION = 16, 58 USB _HUB_FEATURE_C_PORT_ENABLE = 17,59 USB _HUB_FEATURE_C_PORT_SUSPEND = 18,59 USB2_HUB_FEATURE_C_PORT_ENABLE = 17, 60 USB2_HUB_FEATURE_C_PORT_SUSPEND = 18, 60 61 USB_HUB_FEATURE_C_PORT_OVER_CURRENT = 19, 61 62 USB_HUB_FEATURE_C_PORT_RESET = 20, 62 USB_HUB_FEATURE_PORT_TEST = 21, 63 USB_HUB_FEATURE_PORT_INDICATOR = 22 63 USB2_HUB_FEATURE_PORT_TEST = 21, 64 USB2_HUB_FEATURE_PORT_INDICATOR = 22, 65 USB3_HUB_FEATURE_C_PORT_LINK_STATE = 25, 66 USB3_HUB_FEATURE_BH_PORT_RESET = 28, 67 USB3_HUB_FEATURE_C_BH_PORT_RESET = 29, 64 68 /* USB_HUB_FEATURE_ = , */ 65 69 } usb_hub_class_feature_t; 66 70 71 /** 72 * Dword holding port status and changes flags. 73 * 74 * For more information refer to tables 11-15 and 11-16 in 75 * "Universal Serial Bus Specification Revision 1.1" pages 274 and 277 76 * (290 and 293 in pdf) 77 * 78 * Beware that definition of bits changed between USB 2 and 3, 79 * so some fields are prefixed with USB2 or USB3 instead. 80 */ 81 typedef uint32_t usb_port_status_t; 82 83 #define USB_HUB_PORT_STATUS_BIT(bit) (uint32_usb2host(1 << (bit))) 84 #define USB_HUB_PORT_STATUS_CONNECTION USB_HUB_PORT_STATUS_BIT(0) 85 #define USB_HUB_PORT_STATUS_ENABLE USB_HUB_PORT_STATUS_BIT(1) 86 #define USB2_HUB_PORT_STATUS_SUSPEND USB_HUB_PORT_STATUS_BIT(2) 87 #define USB_HUB_PORT_STATUS_OC USB_HUB_PORT_STATUS_BIT(3) 88 #define USB_HUB_PORT_STATUS_RESET USB_HUB_PORT_STATUS_BIT(4) 89 90 #define USB2_HUB_PORT_STATUS_POWER USB_HUB_PORT_STATUS_BIT(8) 91 #define USB2_HUB_PORT_STATUS_LOW_SPEED USB_HUB_PORT_STATUS_BIT(9) 92 #define USB3_HUB_PORT_STATUS_POWER USB_HUB_PORT_STATUS_BIT(9) 93 #define USB2_HUB_PORT_STATUS_HIGH_SPEED USB_HUB_PORT_STATUS_BIT(10) 94 #define USB2_HUB_PORT_STATUS_TEST USB_HUB_PORT_STATUS_BIT(11) 95 #define USB2_HUB_PORT_STATUS_INDICATOR USB_HUB_PORT_STATUS_BIT(12) 96 97 #define USB_HUB_PORT_STATUS_C_CONNECTION USB_HUB_PORT_STATUS_BIT(16) 98 #define USB2_HUB_PORT_STATUS_C_ENABLE USB_HUB_PORT_STATUS_BIT(17) 99 #define USB2_HUB_PORT_STATUS_C_SUSPEND USB_HUB_PORT_STATUS_BIT(18) 100 #define USB_HUB_PORT_STATUS_C_OC USB_HUB_PORT_STATUS_BIT(19) 101 #define USB_HUB_PORT_STATUS_C_RESET USB_HUB_PORT_STATUS_BIT(20) 102 #define USB3_HUB_PORT_STATUS_C_BH_RESET USB_HUB_PORT_STATUS_BIT(21) 103 #define USB3_HUB_PORT_STATUS_C_LINK_STATE USB_HUB_PORT_STATUS_BIT(22) 104 #define USB3_HUB_PORT_STATUS_C_CONFIG_ERROR USB_HUB_PORT_STATUS_BIT(23) 67 105 68 106 /** Header of standard hub descriptor without the "variadic" part. */ … … 71 109 uint8_t length; 72 110 73 /** Descriptor type (0x29 ). */111 /** Descriptor type (0x29 or 0x2a for superspeed hub). */ 74 112 uint8_t descriptor_type; 75 113 … … 116 154 #define HUB_CHAR_OC_PER_PORT_FLAG (1 << 3) 117 155 #define HUB_CHAR_NO_OC_FLAG (1 << 4) 156 157 /* These are invalid for superspeed hub */ 118 158 #define HUB_CHAR_TT_THINK_16 (1 << 5) 119 159 #define HUB_CHAR_TT_THINK_8 (1 << 6) … … 138 178 */ 139 179 uint8_t max_current; 140 } __attribute__ ((packed)) usb_hub_descriptor_header_t;180 } __attribute__((packed)) usb_hub_descriptor_header_t; 141 181 142 182 /** One bit for the device and one bit for every port */ 143 183 #define STATUS_BYTES(ports) ((1 + ports + 7) / 8) 144 184 145 /** @brief usb hub specific request types. 146 * 147 * For more information see Universal Serial Bus Specification Revision 1.1 chapter 11.16.2 185 /** 186 * @brief usb hub specific request types. 148 187 */ 149 188 typedef enum { 150 /** This request resets a value reported in the hub status. */ 151 USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE = 0x20, 152 /** This request resets a value reported in the port status. */ 153 USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE = 0x23, 154 /** This is an optional per-port diagnostic request that returns the bus state value, as sampled at the last EOF2 point. */ 155 USB_HUB_REQ_TYPE_GET_STATE = 0xA3, 156 /** This request returns the hub descriptor. */ 157 USB_HUB_REQ_TYPE_GET_DESCRIPTOR = 0xA0, 158 /** This request returns the current hub status and the states that have changed since the previous acknowledgment. */ 159 USB_HUB_REQ_TYPE_GET_HUB_STATUS = 0xA0, 160 /** This request returns the current port status and the current value of the port status change bits. */ 161 USB_HUB_REQ_TYPE_GET_PORT_STATUS = 0xA3, 162 /** This request overwrites the hub descriptor. */ 163 USB_HUB_REQ_TYPE_SET_DESCRIPTOR = 0x20, 164 /** This request sets a value reported in the hub status. */ 165 USB_HUB_REQ_TYPE_SET_HUB_FEATURE = 0x20, 166 /** This request sets a value reported in the port status. */ 167 USB_HUB_REQ_TYPE_SET_PORT_FEATURE = 0x23 189 /** This request resets a value reported in the hub status. */ 190 USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE = 0x20, 191 /** This request resets a value reported in the port status. */ 192 USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE = 0x23, 193 /** 194 * This is an optional per-port diagnostic request that returns the bus 195 * state value, as sampled at the last EOF2 point. 196 */ 197 USB_HUB_REQ_TYPE_GET_STATE = 0xA3, 198 /** This request returns the hub descriptor. */ 199 USB_HUB_REQ_TYPE_GET_DESCRIPTOR = 0xA0, 200 /** 201 * This request returns the current hub status and the states that have 202 * changed since the previous acknowledgment. 203 */ 204 USB_HUB_REQ_TYPE_GET_HUB_STATUS = 0xA0, 205 /** 206 * This request returns the current port status and the current value of the 207 * port status change bits. 208 */ 209 USB_HUB_REQ_TYPE_GET_PORT_STATUS = 0xA3, 210 /** This request overwrites the hub descriptor. */ 211 USB_HUB_REQ_TYPE_SET_DESCRIPTOR = 0x20, 212 /** This request sets a value reported in the hub status. */ 213 USB_HUB_REQ_TYPE_SET_HUB_FEATURE = 0x20, 214 /** 215 * This request sets the value that the hub uses to determine the index 216 * into the Route String Index for the hub. 217 */ 218 USB_HUB_REQ_TYPE_SET_HUB_DEPTH = 0x20, 219 /** This request sets a value reported in the port status. */ 220 USB_HUB_REQ_TYPE_SET_PORT_FEATURE = 0x23, 168 221 } usb_hub_bm_request_type_t; 169 222 170 /** @brief hub class request codes*/ 171 /// \TODO these are duplicit to standart descriptors 223 /** 224 * @brief hub class request codes 225 */ 172 226 typedef enum { 173 /** */ 174 USB_HUB_REQUEST_GET_STATUS = 0, 175 /** */ 176 USB_HUB_REQUEST_CLEAR_FEATURE = 1, 177 /** USB 1.0 only */ 178 USB_HUB_REQUEST_GET_STATE = 2, 179 /** */ 180 USB_HUB_REQUEST_SET_FEATURE = 3, 181 /** */ 182 USB_HUB_REQUEST_GET_DESCRIPTOR = 6, 183 /** */ 184 USB_HUB_REQUEST_SET_DESCRIPTOR = 7, 185 /** */ 186 USB_HUB_REQUEST_CLEAR_TT_BUFFER = 8, 187 /** */ 188 USB_HUB_REQUEST_RESET_TT = 9, 189 /** */ 190 USB_HUB_GET_TT_STATE = 10, 191 /** */ 192 USB_HUB_STOP_TT = 11, 227 USB_HUB_REQUEST_GET_STATUS = 0, 228 USB_HUB_REQUEST_CLEAR_FEATURE = 1, 229 /** USB 1.0 only */ 230 USB_HUB_REQUEST_GET_STATE = 2, 231 USB_HUB_REQUEST_SET_FEATURE = 3, 232 USB_HUB_REQUEST_GET_DESCRIPTOR = 6, 233 USB_HUB_REQUEST_SET_DESCRIPTOR = 7, 234 USB_HUB_REQUEST_CLEAR_TT_BUFFER = 8, 235 USB_HUB_REQUEST_RESET_TT = 9, 236 USB_HUB_GET_TT_STATE = 10, 237 USB_HUB_STOP_TT = 11, 238 /** USB 3+ only */ 239 USB_HUB_REQUEST_SET_HUB_DEPTH = 12, 193 240 } usb_hub_request_t; 194 241 195 242 /** 196 * Maximum size of usb hub descriptor in bytes243 * Maximum size of usb hub descriptor in bytes 197 244 */ 198 245 /* 7 (basic size) + 2*32 (port bitmasks) */ -
uspace/lib/usb/include/usb/descriptor.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2010 Vojtech Horky 3 * Copyright (c) 2018 Michal Staruch, Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 49 50 USB_DESCTYPE_OTHER_SPEED_CONFIGURATION = 7, 50 51 USB_DESCTYPE_INTERFACE_POWER = 8, 52 /* USB 3.0 types */ 53 USB_DESCTYPE_OTG = 9, 54 USB_DESCTYPE_DEBUG = 0xa, 55 USB_DESCTYPE_IFACE_ASSOC = 0xb, 56 USB_DESCTYPE_BOS = 0xf, 57 USB_DESCTYPE_DEVICE_CAP = 0x10, 51 58 /* Class specific */ 52 59 USB_DESCTYPE_HID = 0x21, … … 54 61 USB_DESCTYPE_HID_PHYSICAL = 0x23, 55 62 USB_DESCTYPE_HUB = 0x29, 63 USB_DESCTYPE_SSPEED_HUB = 0x2a, 64 USB_DESCTYPE_SSPEED_EP_COMPANION = 0x30 56 65 /* USB_DESCTYPE_ = */ 57 66 } usb_descriptor_type_t; … … 92 101 /** Number of possible configurations. */ 93 102 uint8_t configuration_count; 94 } __attribute__ ((packed)) usb_standard_device_descriptor_t;103 } __attribute__((packed)) usb_standard_device_descriptor_t; 95 104 96 105 /** USB device qualifier decriptor is basically a cut down version of the device … … 120 129 uint8_t configuration_count; 121 130 uint8_t reserved; 122 } __attribute__ ((packed)) usb_standard_device_qualifier_descriptor_t;131 } __attribute__((packed)) usb_standard_device_qualifier_descriptor_t; 123 132 124 133 /** Standard USB configuration descriptor. … … 147 156 */ 148 157 uint8_t max_power; 149 } __attribute__ ((packed)) usb_standard_configuration_descriptor_t;158 } __attribute__((packed)) usb_standard_configuration_descriptor_t; 150 159 151 160 /** USB Other Speed Configuration descriptor shows values that would change … … 182 191 /** String descriptor describing this interface. */ 183 192 uint8_t str_interface; 184 } __attribute__ ((packed)) usb_standard_interface_descriptor_t;193 } __attribute__((packed)) usb_standard_interface_descriptor_t; 185 194 186 195 /** Standard USB endpoint descriptor. … … 193 202 /** Endpoint address together with data flow direction. */ 194 203 uint8_t endpoint_address; 204 #define USB_ED_GET_EP(ed) ((ed).endpoint_address & 0xf) 205 #define USB_ED_GET_DIR(ed) (!(((ed).endpoint_address >> 7) & 0x1)) 206 195 207 /** Endpoint attributes. 196 208 * Includes transfer type (usb_transfer_type_t). 197 209 */ 198 210 uint8_t attributes; 211 #define USB_ED_GET_TRANSFER_TYPE(ed) ((ed).attributes & 0x3) 199 212 /** Maximum packet size. 200 213 * Lower 10 bits represent the actuall size … … 202 215 * HS INT and ISO transfers. */ 203 216 uint16_t max_packet_size; 204 205 #define ED_MPS_PACKET_SIZE_MASK 0x3ff 206 #define ED_MPS_PACKET_SIZE_GET(value) \ 207 ((value) & ED_MPS_PACKET_SIZE_MASK) 208 #define ED_MPS_TRANS_OPPORTUNITIES_GET(value) \ 209 ((((value) >> 10) & 0x3) + 1) 210 211 /** Polling interval in milliseconds. 212 * Ignored for bulk and control endpoints. 213 * Isochronous endpoints must use value 1. 214 * Interrupt endpoints any value from 1 to 255. 217 #define USB_ED_GET_MPS(ed) \ 218 (uint16_usb2host((ed).max_packet_size) & 0x7ff) 219 #define USB_ED_GET_ADD_OPPS(ed) \ 220 ((uint16_usb2host((ed).max_packet_size) >> 11) & 0x3) 221 /** Polling interval. Different semantics for various (speed, type) 222 * pairs. 215 223 */ 216 224 uint8_t poll_interval; 217 } __attribute__ ((packed)) usb_standard_endpoint_descriptor_t; 225 } __attribute__((packed)) usb_standard_endpoint_descriptor_t; 226 227 /** Superspeed USB endpoint companion descriptor. 228 * See USB 3 specification, section 9.6.7. 229 */ 230 typedef struct { 231 /** Size of this descriptor in bytes */ 232 uint8_t length; 233 /** Descriptor type (USB_DESCTYPE_SSPEED_EP_COMPANION). */ 234 uint8_t descriptor_type; 235 /** The maximum number of packets the endpoint can send 236 * or receive as part of a burst. Valid values are from 0 to 15. 237 * The endpoint can only burst max_burst + 1 packets at a time. 238 */ 239 uint8_t max_burst; 240 /** Valid only for bulk and isochronous endpoints. 241 * For bulk endpoints, this field contains the amount of streams 242 * supported by the endpoint. 243 * For isochronous endpoints, this field contains maximum 244 * number of packets supported within a service interval. 245 * Warning: the values returned by macros may not make any sense 246 * for specific endpoint types. 247 */ 248 uint8_t attributes; 249 #define USB_SSC_MAX_STREAMS(sscd) ((sscd).attributes & 0x1f) 250 #define USB_SSC_MULT(sscd) ((sscd).attributes & 0x3) 251 /** The total number of bytes this endpoint will transfer 252 * every service interval (SI). 253 * This field is only valid for periodic endpoints. 254 */ 255 uint16_t bytes_per_interval; 256 } __attribute__((packed)) usb_superspeed_endpoint_companion_descriptor_t; 218 257 219 258 /** Part of standard USB HID descriptor specifying one class descriptor. … … 226 265 /** Length of class-specific descriptor in bytes. */ 227 266 uint16_t length; 228 } __attribute__ ((packed)) usb_standard_hid_class_descriptor_info_t;267 } __attribute__((packed)) usb_standard_hid_class_descriptor_info_t; 229 268 230 269 /** Standard USB HID descriptor. … … 257 296 /** First mandatory class descriptor (Report) info. */ 258 297 usb_standard_hid_class_descriptor_info_t report_desc_info; 259 } __attribute__ ((packed)) usb_standard_hid_descriptor_t;298 } __attribute__((packed)) usb_standard_hid_descriptor_t; 260 299 261 300 #endif -
uspace/lib/usb/include/usb/request.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2012 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 71 72 #define USB_ENDPOINT_STATUS_HALTED ((uint16_t)(1 << 0)) 72 73 74 /** Size of the USB setup packet */ 75 #define USB_SETUP_PACKET_SIZE 8 76 73 77 /** Device request setup packet. 74 78 * The setup packet describes the request. … … 82 86 #define SETUP_REQUEST_TYPE_DEVICE_TO_HOST (1 << 7) 83 87 #define SETUP_REQUEST_TYPE_HOST_TO_DEVICE (0 << 7) 88 #define SETUP_REQUEST_TYPE_IS_DEVICE_TO_HOST(rt) ((rt) & (1 << 7)) 84 89 #define SETUP_REQUEST_TYPE_GET_TYPE(rt) ((rt >> 5) & 0x3) 85 90 #define SETUP_REQUEST_TYPE_GET_RECIPIENT(rec) (rec & 0x1f) … … 108 113 } __attribute__ ((packed)) usb_device_request_setup_packet_t; 109 114 110 static_assert(sizeof(usb_device_request_setup_packet_t) == 8);115 static_assert(sizeof(usb_device_request_setup_packet_t) == USB_SETUP_PACKET_SIZE); 111 116 112 int usb_request_needs_toggle_reset( 113 const usb_device_request_setup_packet_t *request); 117 #define GET_DEVICE_DESC(size) \ 118 { \ 119 .request_type = SETUP_REQUEST_TYPE_DEVICE_TO_HOST \ 120 | (USB_REQUEST_TYPE_STANDARD << 5) \ 121 | USB_REQUEST_RECIPIENT_DEVICE, \ 122 .request = USB_DEVREQ_GET_DESCRIPTOR, \ 123 .value = uint16_host2usb(USB_DESCTYPE_DEVICE << 8), \ 124 .index = uint16_host2usb(0), \ 125 .length = uint16_host2usb(size), \ 126 }; 127 128 #define SET_ADDRESS(address) \ 129 { \ 130 .request_type = SETUP_REQUEST_TYPE_HOST_TO_DEVICE \ 131 | (USB_REQUEST_TYPE_STANDARD << 5) \ 132 | USB_REQUEST_RECIPIENT_DEVICE, \ 133 .request = USB_DEVREQ_SET_ADDRESS, \ 134 .value = uint16_host2usb(address), \ 135 .index = uint16_host2usb(0), \ 136 .length = uint16_host2usb(0), \ 137 }; 138 139 #define CTRL_PIPE_MIN_PACKET_SIZE 8 114 140 115 141 #endif -
uspace/lib/usb/include/usb/usb.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2010 Vojtech Horky 3 * Copyright (c) 2018 Ondrej Hlavaty, Michal Staruch 3 4 * All rights reserved. 4 5 * … … 39 40 #include <stdint.h> 40 41 #include <types/common.h> 41 #include <usb _iface.h>42 #include <usbhc_iface.h> 42 43 43 44 /** Convert 16bit value from native (host) endianness to USB endianness. */ … … 53 54 #define uint32_usb2host(n) uint32_t_le2host((n)) 54 55 55 const char * usb_str_transfer_type(usb_transfer_type_tt);56 const char * usb_str_transfer_type_short(usb_transfer_type_tt);56 const char *usb_str_transfer_type(usb_transfer_type_t); 57 const char *usb_str_transfer_type_short(usb_transfer_type_t); 57 58 58 59 const char *usb_str_direction(usb_direction_t); … … 61 62 { 62 63 return (s == USB_SPEED_FULL) || (s == USB_SPEED_LOW); 64 } 65 66 static inline bool usb_speed_is_valid(const usb_speed_t s) 67 { 68 return (s >= USB_SPEED_LOW) && (s < USB_SPEED_MAX); 63 69 } 64 70 … … 97 103 static inline bool usb_address_is_valid(usb_address_t a) 98 104 { 99 return (a >= USB_ADDRESS_DEFAULT) && (a <= USB11_ADDRESS_MAX);105 return a <= USB11_ADDRESS_MAX; 100 106 } 101 107 … … 103 109 #define USB_ENDPOINT_DEFAULT_CONTROL 0 104 110 105 /** Maximum endpoint number in USB 1.1. */ 106 #define USB11_ENDPOINT_MAX 16 111 /** Maximum endpoint number in USB */ 112 #define USB_ENDPOINT_MAX 16 113 114 /** There might be two directions for every endpoint number (except 0) */ 115 #define USB_ENDPOINT_COUNT (2 * USB_ENDPOINT_MAX) 107 116 108 117 /** Check USB endpoint for allowed values. … … 115 124 static inline bool usb_endpoint_is_valid(usb_endpoint_t ep) 116 125 { 117 return (ep >= USB_ENDPOINT_DEFAULT_CONTROL) && 118 (ep < USB11_ENDPOINT_MAX); 126 return ep < USB_ENDPOINT_MAX; 119 127 } 120 128 121 /** Check USB target for allowed values (address and endpoint). 129 /** 130 * Check USB target for allowed values (address, endpoint, stream). 122 131 * 123 132 * @param target. 124 133 * @return True, if values are wihtin limits, false otherwise. 125 134 */ 126 static inline bool usb_target_is_valid( usb_target_ttarget)135 static inline bool usb_target_is_valid(const usb_target_t *target) 127 136 { 128 return usb_address_is_valid(target.address) && 129 usb_endpoint_is_valid(target.endpoint); 137 return usb_address_is_valid(target->address) && 138 usb_endpoint_is_valid(target->endpoint); 139 140 // A 16-bit Stream ID is always valid. 130 141 } 131 142 … … 136 147 * @return Whether @p a and @p b points to the same pipe on the same device. 137 148 */ 138 static inline intusb_target_same(usb_target_t a, usb_target_t b)149 static inline bool usb_target_same(usb_target_t a, usb_target_t b) 139 150 { 140 return (a.address == b.address) 141 && (a.endpoint == b.endpoint); 151 return (a.address == b.address) && (a.endpoint == b.endpoint); 142 152 } 143 144 /** General handle type.145 * Used by various USB functions as opaque handle.146 */147 typedef sysarg_t usb_handle_t;148 153 149 154 /** USB packet identifier. */ … … 161 166 USB_PID_SETUP = _MAKE_PID(3, 1), 162 167 163 USB_PID_DATA0 = _MAKE_PID(0 ,3),164 USB_PID_DATA1 = _MAKE_PID(2 ,3),168 USB_PID_DATA0 = _MAKE_PID(0, 3), 169 USB_PID_DATA1 = _MAKE_PID(2, 3), 165 170 166 USB_PID_ACK = _MAKE_PID(0 ,2),167 USB_PID_NAK = _MAKE_PID(2 ,2),168 USB_PID_STALL = _MAKE_PID(3 ,2),171 USB_PID_ACK = _MAKE_PID(0, 2), 172 USB_PID_NAK = _MAKE_PID(2, 2), 173 USB_PID_STALL = _MAKE_PID(3, 2), 169 174 170 USB_PID_PRE = _MAKE_PID(3 ,0),175 USB_PID_PRE = _MAKE_PID(3, 0), 171 176 /* USB_PID_ = _MAKE_PID( ,), */ 172 177 #undef _MAKE_PID -
uspace/lib/usb/src/dump.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Vojtech Horky 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 61 62 static void usb_dump_descriptor_endpoint(FILE *, const char *, const char *, 62 63 const uint8_t *, size_t); 64 static void usb_dump_descriptor_superspeed_endpoint_companion(FILE *, const char *, const char *, 65 const uint8_t *, size_t); 63 66 static void usb_dump_descriptor_hid(FILE *, const char *, const char *, 64 67 const uint8_t *, size_t); … … 75 78 { USB_DESCTYPE_INTERFACE, usb_dump_descriptor_interface }, 76 79 { USB_DESCTYPE_ENDPOINT, usb_dump_descriptor_endpoint }, 80 { USB_DESCTYPE_SSPEED_EP_COMPANION, usb_dump_descriptor_superspeed_endpoint_companion }, 77 81 { USB_DESCTYPE_HID, usb_dump_descriptor_hid }, 78 82 { USB_DESCTYPE_HUB, usb_dump_descriptor_hub }, … … 238 242 PRINTLINE("wMaxPacketSize = %d", d->max_packet_size); 239 243 PRINTLINE("bInterval = %dms", d->poll_interval); 244 } 245 246 static void usb_dump_descriptor_superspeed_endpoint_companion(FILE *output, 247 const char *line_prefix, const char *line_suffix, 248 const uint8_t *descriptor, size_t descriptor_length) 249 { 250 usb_superspeed_endpoint_companion_descriptor_t *d 251 = (usb_superspeed_endpoint_companion_descriptor_t *) descriptor; 252 if (descriptor_length < sizeof(*d)) { 253 return; 254 } 255 256 PRINTLINE("bLength = %u", d->length); 257 PRINTLINE("bDescriptorType = 0x%02X", d->descriptor_type); 258 PRINTLINE("bMaxBurst = %u", d->max_burst); 259 PRINTLINE("bmAttributes = %d", d->attributes); 260 PRINTLINE("wBytesPerInterval = %u", d->bytes_per_interval); 240 261 } 241 262 -
uspace/lib/usb/src/usb.c
rf5e5f73 rdf6ded8 44 44 [USB_SPEED_FULL] = "full", 45 45 [USB_SPEED_HIGH] = "high", 46 [USB_SPEED_SUPER] = "super", 46 47 }; 47 48 … … 118 119 } 119 120 120 /** Check setup packet data for signs of toggle reset.121 *122 * @param[in] requst Setup requst data.123 *124 * @retval -1 No endpoints need reset.125 * @retval 0 All endpoints need reset.126 * @retval >0 Specified endpoint needs reset.127 *128 */129 int usb_request_needs_toggle_reset(130 const usb_device_request_setup_packet_t *request)131 {132 assert(request);133 switch (request->request)134 {135 /* Clear Feature ENPOINT_STALL */136 case USB_DEVREQ_CLEAR_FEATURE: /*resets only cleared ep */137 /* 0x2 ( HOST to device | STANDART | TO ENPOINT) */138 if ((request->request_type == 0x2) &&139 (request->value == USB_FEATURE_ENDPOINT_HALT))140 return uint16_usb2host(request->index);141 break;142 case USB_DEVREQ_SET_CONFIGURATION:143 case USB_DEVREQ_SET_INTERFACE:144 /* Recipient must be device, this resets all endpoints,145 * In fact there should be no endpoints but EP 0 registered146 * as different interfaces use different endpoints,147 * unless you're changing configuration or alternative148 * interface of an already setup device. */149 if (!(request->request_type & SETUP_REQUEST_TYPE_DEVICE_TO_HOST))150 return 0;151 break;152 default:153 break;154 }155 return -1;156 }157 158 121 /** 159 122 * @} -
uspace/lib/usbdev/include/usb/dev/device.h
rf5e5f73 rdf6ded8 42 42 #include <usb/dev/alternate_ifaces.h> 43 43 #include <usb/dev/pipes.h> 44 #include <usbhc_iface.h> 44 45 45 46 #include <assert.h> … … 58 59 59 60 /* DDF parts */ 60 errno_t usb_device_create_ddf(ddf_dev_t *, const usb_endpoint_description_t **, const char **); 61 errno_t usb_device_create_ddf(ddf_dev_t *, 62 const usb_endpoint_description_t **, const char **); 61 63 void usb_device_destroy_ddf(ddf_dev_t *); 62 64 … … 67 69 } 68 70 69 usb_device_t * usb_device_create(devman_handle_t);71 usb_device_t *usb_device_create(devman_handle_t); 70 72 void usb_device_destroy(usb_device_t *); 71 73 72 const char * usb_device_get_name(usb_device_t *);74 const char *usb_device_get_name(usb_device_t *); 73 75 ddf_fun_t *usb_device_ddf_fun_create(usb_device_t *, fun_type_t, const char *); 74 76 75 async_exch_t * usb_device_bus_exchange_begin(usb_device_t *);77 async_exch_t *usb_device_bus_exchange_begin(usb_device_t *); 76 78 void usb_device_bus_exchange_end(async_exch_t *); 77 79 … … 86 88 usb_endpoint_mapping_t * usb_device_get_mapped_ep_desc(usb_device_t *, 87 89 const usb_endpoint_description_t *); 88 usb_endpoint_mapping_t * usb_device_get_mapped_ep(usb_device_t *, 89 usb_endpoint_t); 90 int usb_device_unmap_ep(usb_endpoint_mapping_t *); 90 91 91 int usb_device_get_iface_number(usb_device_t *); 92 devman_handle_t usb_device_get_devman_handle(usb_device_t *); 92 usb_address_t usb_device_get_address(const usb_device_t *); 93 usb_speed_t usb_device_get_depth(const usb_device_t *); 94 usb_speed_t usb_device_get_speed(const usb_device_t *); 95 int usb_device_get_iface_number(const usb_device_t *); 96 devman_handle_t usb_device_get_devman_handle(const usb_device_t *); 93 97 94 const usb_device_descriptors_t * usb_device_descriptors(usb_device_t *);98 const usb_device_descriptors_t *usb_device_descriptors(usb_device_t *); 95 99 96 const usb_alternate_interfaces_t * usb_device_get_alternative_ifaces(100 const usb_alternate_interfaces_t *usb_device_get_alternative_ifaces( 97 101 usb_device_t *); 98 102 99 void * usb_device_data_alloc(usb_device_t *, size_t);100 void * usb_device_data_get(usb_device_t *);103 void *usb_device_data_alloc(usb_device_t *, size_t); 104 void *usb_device_data_get(usb_device_t *); 101 105 102 106 #endif -
uspace/lib/usbdev/include/usb/dev/driver.h
rf5e5f73 rdf6ded8 45 45 errno_t (*device_add)(usb_device_t *); 46 46 /** Callback when a device is about to be removed from the system. */ 47 errno_t (*device_rem )(usb_device_t *);47 errno_t (*device_remove)(usb_device_t *); 48 48 /** Callback when a device was removed from the system. */ 49 49 errno_t (*device_gone)(usb_device_t *); 50 /** Callback asking the driver to online a specific function. */ 51 errno_t (*function_online)(ddf_fun_t *); 52 /** Callback asking the driver to offline a specific function. */ 53 errno_t (*function_offline)(ddf_fun_t *); 50 54 } usb_driver_ops_t; 51 55 -
uspace/lib/usbdev/include/usb/dev/pipes.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Vojtech Horky 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 44 45 45 46 #define CTRL_PIPE_MIN_PACKET_SIZE 8 47 46 48 /** Abstraction of a logical connection to USB device endpoint. 47 * It encapsulates endpoint attributes (transfer type etc.).49 * It contains some vital information about the pipe. 48 50 * This endpoint must be bound with existing usb_device_connection_t 49 51 * (i.e. the wire to send data over). 50 52 */ 51 53 typedef struct { 52 /** Endpoint number. */ 53 usb_endpoint_t endpoint_no; 54 55 /** Endpoint transfer type. */ 56 usb_transfer_type_t transfer_type; 57 58 /** Endpoint direction. */ 59 usb_direction_t direction; 60 61 /** Maximum packet size for the endpoint. */ 62 size_t max_packet_size; 63 64 /** Number of packets per frame/uframe. 65 * Only valid for HS INT and ISO transfers. All others should set to 1*/ 66 unsigned packets; 54 /** Pipe description received from HC */ 55 usb_pipe_desc_t desc; 67 56 68 57 /** Whether to automatically reset halt on the endpoint. … … 70 59 */ 71 60 bool auto_reset_halt; 72 73 61 /** The connection used for sending the data. */ 74 62 usb_dev_session_t *bus_session; … … 103 91 /** Found descriptor fitting the description. */ 104 92 const usb_standard_endpoint_descriptor_t *descriptor; 93 /** Relevant superspeed companion descriptor. */ 94 const usb_superspeed_endpoint_companion_descriptor_t 95 *companion_descriptor; 105 96 /** Interface descriptor the endpoint belongs to. */ 106 97 const usb_standard_interface_descriptor_t *interface; … … 109 100 } usb_endpoint_mapping_t; 110 101 111 errno_t usb_pipe_initialize(usb_pipe_t *, usb_endpoint_t, usb_transfer_type_t, 112 size_t, usb_direction_t, unsigned, usb_dev_session_t *); 102 errno_t usb_pipe_initialize(usb_pipe_t *, usb_dev_session_t *); 113 103 errno_t usb_pipe_initialize_default_control(usb_pipe_t *, usb_dev_session_t *); 114 104 115 errno_t usb_pipe_probe_default_control(usb_pipe_t *);116 105 errno_t usb_pipe_initialize_from_configuration(usb_endpoint_mapping_t *, 117 106 size_t, const uint8_t *, size_t, usb_dev_session_t *); 118 107 119 errno_t usb_pipe_register(usb_pipe_t *, unsigned); 108 errno_t usb_pipe_register(usb_pipe_t *, 109 const usb_standard_endpoint_descriptor_t *, 110 const usb_superspeed_endpoint_companion_descriptor_t *); 120 111 errno_t usb_pipe_unregister(usb_pipe_t *); 121 112 122 113 errno_t usb_pipe_read(usb_pipe_t *, void *, size_t, size_t *); 123 114 errno_t usb_pipe_write(usb_pipe_t *, const void *, size_t); 115 116 errno_t usb_pipe_read_dma(usb_pipe_t *, void *, void *, size_t, size_t *); 117 errno_t usb_pipe_write_dma(usb_pipe_t *, void *, void *, size_t); 124 118 125 119 errno_t usb_pipe_control_read(usb_pipe_t *, const void *, size_t, … … 128 122 const void *, size_t); 129 123 124 void *usb_pipe_alloc_buffer(usb_pipe_t *, size_t); 125 void usb_pipe_free_buffer(usb_pipe_t *, void *); 130 126 #endif 131 127 /** -
uspace/lib/usbdev/include/usb/dev/poll.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Vojtech Horky 3 * Copyright (c) 2017 Petr Manek 3 4 * All rights reserved. 4 5 * … … 43 44 #include <stddef.h> 44 45 #include <stdint.h> 46 #include <fibril_synch.h> 45 47 46 /** Parameters and callbacks for automated polling. */ 47 typedef struct { 48 /** Level of debugging messages from auto polling. 49 * 0 - nothing 50 * 1 - inform about errors and polling start/end 51 * 2 - also dump every retrieved buffer 48 49 /** USB automated polling. */ 50 typedef struct usb_polling { 51 /** Mandatory parameters - user is expected to configure these. */ 52 53 /** USB device to poll. */ 54 usb_device_t *device; 55 56 /** Device enpoint mapping to use for polling. */ 57 usb_endpoint_mapping_t *ep_mapping; 58 59 /** Size of the recieved data. */ 60 size_t request_size; 61 62 /** 63 * Data buffer of at least `request_size`. User is responsible for its 64 * allocation. 52 65 */ 53 int debug; 54 /** Maximum number of consecutive errors before polling termination. */ 55 size_t max_failures; 56 /** Delay between poll requests in milliseconds. 57 * Set to negative value to use value from endpoint descriptor. 58 */ 59 int delay; 60 /** Whether to automatically try to clear the HALT feature after 61 * the endpoint stalls. 62 */ 63 bool auto_clear_halt; 66 uint8_t *buffer; 67 64 68 /** Callback when data arrives. 65 69 * … … 72 76 bool (*on_data)(usb_device_t *dev, uint8_t *data, size_t data_size, 73 77 void *arg); 78 79 80 /** 81 * Optional parameters - user can customize them, but they are 82 * defaulted to some reasonable values. 83 */ 84 85 /** Level of debugging messages from auto polling. 86 * 0 - nothing (default) 87 * 1 - inform about errors and polling start/end 88 * 2 - also dump every retrieved buffer 89 */ 90 int debug; 91 92 /** 93 * Maximum number of consecutive errors before polling termination 94 * (default 3). 95 */ 96 size_t max_failures; 97 98 /** Delay between poll requests in milliseconds. 99 * By default, value from endpoint descriptor used. 100 */ 101 int delay; 102 103 /** Whether to automatically try to clear the HALT feature after 104 * the endpoint stalls (true by default). 105 */ 106 bool auto_clear_halt; 107 108 /** Argument to pass to callbacks (default NULL). */ 109 void *arg; 110 74 111 /** Callback when polling is terminated. 75 112 * … … 80 117 void (*on_polling_end)(usb_device_t *dev, bool due_to_errors, 81 118 void *arg); 119 82 120 /** Callback when error occurs. 83 121 * … … 88 126 */ 89 127 bool (*on_error)(usb_device_t *dev, errno_t err_code, void *arg); 90 /** Argument to pass to callbacks. */91 void *arg;92 } usb_device_auto_polling_t;93 128 94 typedef bool (*usb_polling_callback_t)(usb_device_t *, uint8_t *, size_t, void *);95 typedef void (*usb_polling_terminted_callback_t)(usb_device_t *, bool, void *);96 129 97 extern errno_t usb_device_auto_polling(usb_device_t *, usb_endpoint_t, 98 const usb_device_auto_polling_t *, size_t); 130 /** 131 * Internal parameters - user is not expected to set them. Messing with 132 * them can result in unexpected behavior if you do not know what you 133 * are doing. 134 */ 99 135 100 extern errno_t usb_device_auto_poll(usb_device_t *, usb_endpoint_t, 101 usb_polling_callback_t, size_t, int, usb_polling_terminted_callback_t, void *);136 /** Fibril used for polling. */ 137 fid_t fibril; 102 138 103 extern errno_t usb_device_auto_polling_desc(usb_device_t *, 104 const usb_endpoint_description_t *, const usb_device_auto_polling_t *, 105 size_t); 139 /** True if polling is currently in operation. */ 140 volatile bool running; 106 141 107 extern errno_t usb_device_auto_poll_desc(usb_device_t *, 108 const usb_endpoint_description_t *, usb_polling_callback_t, size_t, int, 109 usb_polling_terminted_callback_t, void *); 142 /** True if polling should terminate as soon as possible. */ 143 volatile bool joining; 144 145 /** Synchronization primitives for joining polling end. */ 146 fibril_mutex_t guard; 147 fibril_condvar_t cv; 148 } usb_polling_t; 149 150 errno_t usb_polling_init(usb_polling_t *); 151 void usb_polling_fini(usb_polling_t *); 152 153 errno_t usb_polling_start(usb_polling_t *); 154 errno_t usb_polling_join(usb_polling_t *); 110 155 111 156 #endif -
uspace/lib/usbdev/include/usb/dev/request.h
rf5e5f73 rdf6ded8 85 85 char **); 86 86 87 errno_t usb_request_clear_endpoint_halt(usb_pipe_t *, uint16_t);88 87 errno_t usb_pipe_clear_halt(usb_pipe_t *, usb_pipe_t *); 89 88 errno_t usb_request_get_endpoint_status(usb_pipe_t *, usb_pipe_t *, uint16_t *); -
uspace/lib/usbdev/src/devdrv.c
rf5e5f73 rdf6ded8 2 2 * Copyright (c) 2011 Vojtech Horky 3 3 * Copyright (c) 2011 Jan Vesely 4 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek, Michal Staruch 4 5 * All rights reserved. 5 6 * … … 48 49 #include <devman.h> 49 50 #include <errno.h> 51 #include <str_error.h> 50 52 #include <stdlib.h> 51 53 … … 56 58 /** Connection to device on USB bus */ 57 59 usb_dev_session_t *bus_session; 58 60 59 61 /** devman handle */ 60 62 devman_handle_t handle; 61 63 62 64 /** The default control pipe. */ 63 65 usb_pipe_t ctrl_pipe; 64 66 65 67 /** Other endpoint pipes. 66 68 * … … 69 71 */ 70 72 usb_endpoint_mapping_t *pipes; 71 73 72 74 /** Number of other endpoint pipes. */ 73 75 size_t pipes_count; 74 76 77 /** USB address of this device */ 78 usb_address_t address; 79 80 /** Depth in the USB hub hiearchy */ 81 unsigned depth; 82 83 /** USB speed of this device */ 84 usb_speed_t speed; 85 75 86 /** Current interface. 76 87 * … … 79 90 */ 80 91 int interface_no; 81 92 82 93 /** Alternative interfaces. */ 83 94 usb_alternate_interfaces_t alternate_interfaces; 84 95 85 96 /** Some useful descriptors for USB device. */ 86 97 usb_device_descriptors_t descriptors; 87 98 88 99 /** Generic DDF device backing this one. DO NOT TOUCH! */ 89 100 ddf_dev_t *ddf_dev; 90 101 91 102 /** Custom driver data. 92 103 * … … 146 157 return rc; 147 158 } 148 159 149 160 /* Change current alternative */ 150 161 usb_dev->alternate_interfaces.current = alternate_setting; … … 255 266 256 267 /* Register created pipes. */ 268 unsigned pipes_registered = 0; 257 269 for (size_t i = 0; i < pipe_count; i++) { 258 270 if (pipes[i].present) { 259 rc = usb_pipe_register(&pipes[i].pipe, 260 pipes[i].descriptor->poll_interval); 271 rc = usb_pipe_register(&pipes[i].pipe, pipes[i].descriptor, pipes[i].companion_descriptor); 261 272 if (rc != EOK) { 262 273 goto rollback_unregister_endpoints; 263 274 } 264 275 } 276 pipes_registered++; 265 277 } 266 278 … … 277 289 */ 278 290 rollback_unregister_endpoints: 279 for (size_t i = 0; i < pipe _count; i++) {291 for (size_t i = 0; i < pipes_registered; i++) { 280 292 if (pipes[i].present) { 281 293 usb_pipe_unregister(&pipes[i].pipe); … … 296 308 assert(usb_dev); 297 309 assert(usb_dev->pipes || usb_dev->pipes_count == 0); 298 310 299 311 /* Destroy the pipes. */ 312 int rc; 300 313 for (size_t i = 0; i < usb_dev->pipes_count; ++i) { 301 usb_log_debug2("Unregistering pipe %zu: %spresent. \n",314 usb_log_debug2("Unregistering pipe %zu: %spresent.", 302 315 i, usb_dev->pipes[i].present ? "" : "not "); 303 if (usb_dev->pipes[i].present) 304 usb_pipe_unregister(&usb_dev->pipes[i].pipe); 305 } 306 316 317 rc = usb_device_unmap_ep(usb_dev->pipes + i); 318 if (rc != EOK && rc != ENOENT) 319 usb_log_warning("Unregistering pipe %zu failed: %s", i, str_error(rc)); 320 } 321 307 322 free(usb_dev->pipes); 308 323 usb_dev->pipes = NULL; … … 327 342 } 328 343 329 usb_endpoint_mapping_t * usb_device_get_mapped_ep( 330 usb_device_t *usb_dev, usb_endpoint_t ep) 331 { 332 assert(usb_dev); 333 for (unsigned i = 0; i < usb_dev->pipes_count; ++i) { 334 if (usb_dev->pipes[i].pipe.endpoint_no == ep) 335 return &usb_dev->pipes[i]; 336 } 337 return NULL; 338 } 339 340 int usb_device_get_iface_number(usb_device_t *usb_dev) 344 int usb_device_unmap_ep(usb_endpoint_mapping_t *epm) 345 { 346 assert(epm); 347 348 if (!epm->present) 349 return ENOENT; 350 351 const int rc = usb_pipe_unregister(&epm->pipe); 352 if (rc != EOK) 353 return rc; 354 355 epm->present = false; 356 return EOK; 357 } 358 359 usb_address_t usb_device_get_address(const usb_device_t *usb_dev) 360 { 361 assert(usb_dev); 362 return usb_dev->depth; 363 } 364 365 unsigned usb_device_get_depth(const usb_device_t *usb_dev) 366 { 367 assert(usb_dev); 368 return usb_dev->depth; 369 } 370 371 usb_speed_t usb_device_get_speed(const usb_device_t *usb_dev) 372 { 373 assert(usb_dev); 374 return usb_dev->speed; 375 } 376 377 int usb_device_get_iface_number(const usb_device_t *usb_dev) 341 378 { 342 379 assert(usb_dev); … … 344 381 } 345 382 346 devman_handle_t usb_device_get_devman_handle( usb_device_t *usb_dev)383 devman_handle_t usb_device_get_devman_handle(const usb_device_t *usb_dev) 347 384 { 348 385 assert(usb_dev); … … 394 431 */ 395 432 static errno_t usb_device_init(usb_device_t *usb_dev, ddf_dev_t *ddf_dev, 396 const usb_endpoint_description_t **endpoints, const char **errstr_ptr, 397 devman_handle_t handle, int interface_no) 433 const usb_endpoint_description_t **endpoints, const char **errstr_ptr) 398 434 { 399 435 assert(usb_dev != NULL); … … 403 439 404 440 usb_dev->ddf_dev = ddf_dev; 405 usb_dev->handle = handle;406 usb_dev->interface_no = interface_no;407 441 usb_dev->driver_data = NULL; 408 442 usb_dev->descriptors.full_config = NULL; … … 411 445 usb_dev->pipes = NULL; 412 446 413 usb_dev->bus_session = usb_dev_connect( handle);447 usb_dev->bus_session = usb_dev_connect(usb_dev->handle); 414 448 415 449 if (!usb_dev->bus_session) { … … 420 454 /* This pipe was registered by the hub driver, 421 455 * during device initialization. */ 422 errno_t rc = usb_pipe_initialize_default_control( 423 &usb_dev->ctrl_pipe, usb_dev->bus_session); 456 errno_t rc = usb_pipe_initialize_default_control(&usb_dev->ctrl_pipe, usb_dev->bus_session); 424 457 if (rc != EOK) { 425 458 usb_dev_disconnect(usb_dev->bus_session); … … 440 473 * it makes no sense to speak about alternate interfaces when 441 474 * controlling a device. */ 442 rc =usb_alternate_interfaces_init(&usb_dev->alternate_interfaces,475 usb_alternate_interfaces_init(&usb_dev->alternate_interfaces, 443 476 usb_dev->descriptors.full_config, 444 477 usb_dev->descriptors.full_config_size, usb_dev->interface_no); … … 457 490 } 458 491 459 static errno_t usb_device_get_info(async_sess_t *sess, devman_handle_t *handle, 460 int *iface_no) 461 { 462 assert(handle); 463 assert(iface_no); 464 492 static errno_t usb_device_get_info(async_sess_t *sess, usb_device_t *dev) 493 { 494 assert(dev); 495 465 496 async_exch_t *exch = async_exchange_begin(sess); 466 497 if (!exch) 467 498 return EPARTY; 468 469 errno_t ret = usb_get_my_device_handle(exch, handle); 499 500 usb_device_desc_t dev_desc; 501 const errno_t ret = usb_get_my_description(exch, &dev_desc); 502 470 503 if (ret == EOK) { 471 ret = usb_get_my_interface(exch, iface_no);472 if (ret == ENOTSUP) {473 *iface_no = -1;474 ret = EOK;475 }476 } 477 504 dev->address = dev_desc.address; 505 dev->depth = dev_desc.depth; 506 dev->speed = dev_desc.speed; 507 dev->handle = dev_desc.handle; 508 dev->interface_no = dev_desc.iface; 509 } 510 478 511 async_exchange_end(exch); 479 512 return ret; … … 485 518 assert(ddf_dev); 486 519 assert(err); 487 488 devman_handle_t h = 0;489 int iface_no = -1;490 520 491 521 async_sess_t *sess = ddf_dev_parent_sess_get(ddf_dev); 492 522 if (sess == NULL) 493 523 return ENOMEM; 494 const errno_t ret = usb_device_get_info(sess, &h, &iface_no);495 if (ret != EOK)496 return ret;497 524 498 525 usb_device_t *usb_dev = … … 502 529 return ENOMEM; 503 530 } 504 505 return usb_device_init(usb_dev, ddf_dev, desc, err, h, iface_no); 531 532 const errno_t ret = usb_device_get_info(sess, usb_dev); 533 if (ret != EOK) 534 return ret; 535 536 return usb_device_init(usb_dev, ddf_dev, desc, err); 506 537 } 507 538 … … 517 548 usb_device_t * usb_device_create(devman_handle_t handle) 518 549 { 519 devman_handle_t h = 0;520 int iface_no = -1;521 522 async_sess_t *sess = devman_device_connect(handle, IPC_FLAG_BLOCKING);523 errno_t ret = usb_device_get_info(sess, &h, &iface_no);524 if (sess)525 async_hangup(sess);526 if (ret != EOK)527 return NULL;528 529 550 usb_device_t *usb_dev = malloc(sizeof(usb_device_t)); 530 551 if (!usb_dev) 531 552 return NULL; 532 553 554 async_sess_t *sess = devman_device_connect(handle, IPC_FLAG_BLOCKING); 555 errno_t ret = usb_device_get_info(sess, usb_dev); 556 if (sess) 557 async_hangup(sess); 558 if (ret != EOK) { 559 free(usb_dev); 560 return NULL; 561 } 562 533 563 const char* dummy = NULL; 534 ret = usb_device_init(usb_dev, NULL, NULL, &dummy , handle, iface_no);564 ret = usb_device_init(usb_dev, NULL, NULL, &dummy); 535 565 if (ret != EOK) { 536 566 free(usb_dev); -
uspace/lib/usbdev/src/devpoll.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Vojtech Horky 3 * Copyright (c) 2017 Petr Manek 3 4 * All rights reserved. 4 5 * … … 47 48 #include <errno.h> 48 49 #include <fibril.h> 50 #include <fibril_synch.h> 49 51 #include <stdbool.h> 50 52 #include <stdlib.h> … … 53 55 #include <stdint.h> 54 56 55 /** Maximum number of failed consecutive requests before announcing failure. */ 56 #define MAX_FAILED_ATTEMPTS 3 57 58 /** Data needed for polling. */ 59 typedef struct { 60 /** Parameters for automated polling. */ 61 usb_device_auto_polling_t auto_polling; 62 63 /** USB device to poll. */ 64 usb_device_t *dev; 65 /** Device enpoint mapping to use for polling. */ 66 usb_endpoint_mapping_t *polling_mapping; 67 /** Size of the recieved data. */ 68 size_t request_size; 69 /** Data buffer. */ 70 uint8_t *buffer; 71 } polling_data_t; 57 58 /** Initialize the polling data structure, its internals and configuration 59 * with default values. 60 * 61 * @param polling Valid polling data structure. 62 * @return Error code. 63 * @retval EOK Polling data structure is ready to be used. 64 */ 65 int usb_polling_init(usb_polling_t *polling) 66 { 67 if (!polling) 68 return EBADMEM; 69 70 /* Zero out everything */ 71 memset(polling, 0, sizeof(usb_polling_t)); 72 73 /* Internal initializers. */ 74 fibril_mutex_initialize(&polling->guard); 75 fibril_condvar_initialize(&polling->cv); 76 77 /* Default configuration. */ 78 polling->auto_clear_halt = true; 79 polling->delay = -1; 80 polling->max_failures = 3; 81 82 return EOK; 83 } 84 85 86 /** Destroy the polling data structure. 87 * This function does nothing but a safety check whether the polling 88 * was joined successfully. 89 * 90 * @param polling Polling data structure. 91 */ 92 void usb_polling_fini(usb_polling_t *polling) 93 { 94 /* Nothing done at the moment. */ 95 assert(polling); 96 assert(!polling->running); 97 } 72 98 73 99 74 100 /** Polling fibril. 75 101 * 76 * @param arg Pointer to polling_data_t.102 * @param arg Pointer to usb_polling_t. 77 103 * @return Always EOK. 78 104 */ … … 80 106 { 81 107 assert(arg); 82 polling_data_t *data = arg; 83 /* Helper to reduce typing. */ 84 const usb_device_auto_polling_t *params = &data->auto_polling; 85 86 usb_pipe_t *pipe = &data->polling_mapping->pipe; 87 88 if (params->debug > 0) { 108 usb_polling_t *polling = arg; 109 110 fibril_mutex_lock(&polling->guard); 111 polling->running = true; 112 fibril_mutex_unlock(&polling->guard); 113 114 usb_pipe_t *pipe = &polling->ep_mapping->pipe; 115 116 if (polling->debug > 0) { 89 117 const usb_endpoint_mapping_t *mapping = 90 data->polling_mapping;118 polling->ep_mapping; 91 119 usb_log_debug("Poll (%p): started polling of `%s' - " \ 92 120 "interface %d (%s,%d,%d), %zuB/%zu.\n", 93 data, usb_device_get_name(data->dev),121 polling, usb_device_get_name(polling->device), 94 122 (int) mapping->interface->interface_number, 95 123 usb_str_class(mapping->interface->interface_class), 96 124 (int) mapping->interface->interface_subclass, 97 125 (int) mapping->interface->interface_protocol, 98 data->request_size, pipe->max_packet_size);126 polling->request_size, pipe->desc.max_transfer_size); 99 127 } 100 128 101 129 size_t failed_attempts = 0; 102 while (failed_attempts <= p arams->max_failures) {130 while (failed_attempts <= polling->max_failures) { 103 131 size_t actual_size; 104 const errno_t rc = usb_pipe_read(pipe, data->buffer,105 data->request_size, &actual_size);132 const errno_t rc = usb_pipe_read(pipe, polling->buffer, 133 polling->request_size, &actual_size); 106 134 107 135 if (rc == EOK) { 108 if (p arams->debug > 1) {136 if (polling->debug > 1) { 109 137 usb_log_debug( 110 138 "Poll%p: received: '%s' (%zuB).\n", 111 data,112 usb_debug_str_buffer( data->buffer,139 polling, 140 usb_debug_str_buffer(polling->buffer, 113 141 actual_size, 16), 114 142 actual_size); … … 117 145 usb_log_debug( 118 146 "Poll%p: polling failed: %s.\n", 119 data, str_error(rc));147 polling, str_error(rc)); 120 148 } 121 149 122 150 /* If the pipe stalled, we can try to reset the stall. */ 123 if ( (rc == ESTALL) && (params->auto_clear_halt)) {151 if (rc == ESTALL && polling->auto_clear_halt) { 124 152 /* 125 153 * We ignore error here as this is usually a futile 126 154 * attempt anyway. 127 155 */ 128 usb_request_clear_endpoint_halt( 129 usb_device_get_default_pipe(data->dev), 130 pipe->endpoint_no); 156 usb_pipe_clear_halt( 157 usb_device_get_default_pipe(polling->device), pipe); 131 158 } 132 159 133 160 if (rc != EOK) { 134 161 ++failed_attempts; 135 const bool cont = (params->on_error == NULL) ? true : 136 params->on_error(data->dev, rc, params->arg); 137 if (!cont) { 138 failed_attempts = params->max_failures; 162 const bool carry_on = !polling->on_error ? true : 163 polling->on_error(polling->device, rc, polling->arg); 164 165 if (!carry_on || polling->joining) { 166 /* This is user requested abort, erases failures. */ 167 failed_attempts = 0; 168 break; 139 169 } 140 170 continue; … … 142 172 143 173 /* We have the data, execute the callback now. */ 144 assert(p arams->on_data);145 const bool carry_on = p arams->on_data(146 data->dev, data->buffer, actual_size, params->arg);174 assert(polling->on_data); 175 const bool carry_on = polling->on_data(polling->device, 176 polling->buffer, actual_size, polling->arg); 147 177 148 178 if (!carry_on) { … … 156 186 157 187 /* Take a rest before next request. */ 158 188 159 189 // FIXME TODO: This is broken, the time is in ms not us. 160 190 // but first we need to fix drivers to actually stop using this, 161 191 // since polling delay should be implemented in HC schedule 162 async_usleep(p arams->delay);192 async_usleep(polling->delay); 163 193 } 164 194 165 195 const bool failed = failed_attempts > 0; 166 196 167 if (params->on_polling_end != NULL) { 168 params->on_polling_end(data->dev, failed, params->arg); 169 } 170 171 if (params->debug > 0) { 197 if (polling->on_polling_end) 198 polling->on_polling_end(polling->device, failed, polling->arg); 199 200 if (polling->debug > 0) { 172 201 if (failed) { 173 202 usb_log_error("Polling of device `%s' terminated: " 174 203 "recurring failures.\n", 175 usb_device_get_name( data->dev));204 usb_device_get_name(polling->device)); 176 205 } else { 177 206 usb_log_debug("Polling of device `%s' terminated: " 178 207 "driver request.\n", 179 usb_device_get_name( data->dev));208 usb_device_get_name(polling->device)); 180 209 } 181 210 } 182 211 183 /* Free the allocated memory. */ 184 free(data->buffer); 185 free(data); 186 212 fibril_mutex_lock(&polling->guard); 213 polling->running = false; 214 fibril_mutex_unlock(&polling->guard); 215 216 /* Notify joiners, if any. */ 217 fibril_condvar_broadcast(&polling->cv); 187 218 return EOK; 188 219 } … … 198 229 * first request would be executed prior to return from this function). 199 230 * 200 * @param dev Device to be periodically polled. 201 * @param epm Endpoint mapping to use. 202 * @param polling Polling settings. 203 * @param request_size How many bytes to ask for in each request. 204 * @param arg Custom argument (passed as is to the callbacks). 231 * @param polling Polling data structure. 205 232 * @return Error code. 206 233 * @retval EOK New fibril polling the device was already started. 207 234 */ 208 static errno_t usb_device_auto_polling_internal(usb_device_t *dev, 209 usb_endpoint_mapping_t *epm, const usb_device_auto_polling_t *polling, 210 size_t request_size) 211 { 212 if ((dev == NULL) || (polling == NULL) || (polling->on_data == NULL)) { 235 errno_t usb_polling_start(usb_polling_t *polling) 236 { 237 if (!polling || !polling->device || !polling->ep_mapping || !polling->on_data) 213 238 return EBADMEM; 214 } 215 216 if (request_size == 0) 239 240 if (!polling->request_size) 217 241 return EINVAL; 218 219 if (! epm || (epm->pipe.transfer_type != USB_TRANSFER_INTERRUPT) ||220 (epm->pipe.direction != USB_DIRECTION_IN))242 243 if (!polling->ep_mapping || (polling->ep_mapping->pipe.desc.transfer_type != USB_TRANSFER_INTERRUPT) 244 || (polling->ep_mapping->pipe.desc.direction != USB_DIRECTION_IN)) 221 245 return EINVAL; 222 223 224 polling_data_t *polling_data = malloc(sizeof(polling_data_t)); 225 if (polling_data == NULL) { 246 247 /* Negative value means use descriptor provided value. */ 248 if (polling->delay < 0) 249 polling->delay = polling->ep_mapping->descriptor->poll_interval; 250 251 polling->fibril = fibril_create(polling_fibril, polling); 252 if (!polling->fibril) 226 253 return ENOMEM; 227 } 228 229 /* Fill-in the data. */ 230 polling_data->buffer = malloc(sizeof(request_size)); 231 if (polling_data->buffer == NULL) { 232 free(polling_data); 233 return ENOMEM; 234 } 235 polling_data->request_size = request_size; 236 polling_data->dev = dev; 237 polling_data->polling_mapping = epm; 238 239 /* Copy provided settings. */ 240 polling_data->auto_polling = *polling; 241 242 /* Negative value means use descriptor provided value. */ 243 if (polling->delay < 0) { 244 polling_data->auto_polling.delay = 245 epm->descriptor->poll_interval; 246 } 247 248 fid_t fibril = fibril_create(polling_fibril, polling_data); 249 if (fibril == 0) { 250 free(polling_data->buffer); 251 free(polling_data); 252 return ENOMEM; 253 } 254 fibril_add_ready(fibril); 254 255 fibril_add_ready(polling->fibril); 255 256 256 257 /* Fibril launched. That fibril will free the allocated data. */ 257 258 258 return EOK; 259 259 } 260 /** Start automatic device polling over interrupt in pipe. 261 * 262 * The polling settings is copied thus it is okay to destroy the structure 263 * after this function returns. 264 * 265 * @warning There is no guarantee when the request to the device 266 * will be sent for the first time (it is possible that this 267 * first request would be executed prior to return from this function). 268 * 269 * @param dev Device to be periodically polled. 270 * @param pipe_index Index of the endpoint pipe used for polling. 271 * @param polling Polling settings. 272 * @param req_size How many bytes to ask for in each request. 273 * @param arg Custom argument (passed as is to the callbacks). 274 * @return Error code. 275 * @retval EOK New fibril polling the device was already started. 276 */ 277 errno_t usb_device_auto_polling(usb_device_t *usb_dev, usb_endpoint_t ep, 278 const usb_device_auto_polling_t *polling, size_t req_size) 279 { 280 usb_endpoint_mapping_t *epm = usb_device_get_mapped_ep(usb_dev, ep); 281 return usb_device_auto_polling_internal(usb_dev, epm, polling, req_size); 282 } 283 284 /** Start automatic device polling over interrupt in pipe. 285 * 286 * @warning It is up to the callback to produce delays between individual 287 * requests. 288 * 289 * @warning There is no guarantee when the request to the device 290 * will be sent for the first time (it is possible that this 291 * first request would be executed prior to return from this function). 292 * 293 * @param dev Device to be periodically polled. 294 * @param ep Endpoint used for polling. 295 * @param callback Callback when data are available. 296 * @param request_size How many bytes to ask for in each request. 297 * @param delay NUmber of ms to wait between queries, -1 to use descriptor val. 298 * @param terminated_callback Callback when polling is terminated. 299 * @param arg Custom argument (passed as is to the callbacks). 300 * @return Error code. 301 * @retval EOK New fibril polling the device was already started. 302 */ 303 errno_t usb_device_auto_poll(usb_device_t *dev, usb_endpoint_t ep, 304 usb_polling_callback_t callback, size_t request_size, int delay, 305 usb_polling_terminted_callback_t terminated_callback, void *arg) 306 { 307 const usb_device_auto_polling_t auto_polling = { 308 .debug = 1, 309 .auto_clear_halt = true, 310 .delay = delay, 311 .max_failures = MAX_FAILED_ATTEMPTS, 312 .on_data = callback, 313 .on_polling_end = terminated_callback, 314 .on_error = NULL, 315 .arg = arg, 316 }; 317 318 usb_endpoint_mapping_t *epm = usb_device_get_mapped_ep(dev, ep); 319 return usb_device_auto_polling_internal( 320 dev, epm, &auto_polling, request_size); 321 } 322 323 errno_t usb_device_auto_polling_desc(usb_device_t *usb_dev, 324 const usb_endpoint_description_t *desc, 325 const usb_device_auto_polling_t *polling, size_t req_size) 326 { 327 usb_endpoint_mapping_t *epm = 328 usb_device_get_mapped_ep_desc(usb_dev, desc); 329 return usb_device_auto_polling_internal(usb_dev, epm, polling, req_size); 330 } 331 332 errno_t usb_device_auto_poll_desc(usb_device_t * usb_dev, 333 const usb_endpoint_description_t *desc, usb_polling_callback_t callback, 334 size_t req_size, int delay, 335 usb_polling_terminted_callback_t terminated_callback, void *arg) 336 { 337 const usb_device_auto_polling_t auto_polling = { 338 .debug = 1, 339 .auto_clear_halt = true, 340 .delay = delay, 341 .max_failures = MAX_FAILED_ATTEMPTS, 342 .on_data = callback, 343 .on_polling_end = terminated_callback, 344 .on_error = NULL, 345 .arg = arg, 346 }; 347 348 usb_endpoint_mapping_t *epm = 349 usb_device_get_mapped_ep_desc(usb_dev, desc); 350 return usb_device_auto_polling_internal( 351 usb_dev, epm, &auto_polling, req_size); 260 261 /** Close the polling pipe permanently and synchronously wait 262 * until the automatic polling fibril terminates. 263 * 264 * It is safe to deallocate the polling data structure (and its 265 * data buffer) only after a successful call to this function. 266 * 267 * @warning Call to this function will trigger execution of the 268 * on_error() callback with EINTR error code. 269 * 270 * @parram polling Polling data structure. 271 * @return Error code. 272 * @retval EOK Polling fibril has been successfully terminated. 273 */ 274 errno_t usb_polling_join(usb_polling_t *polling) 275 { 276 errno_t rc; 277 if (!polling) 278 return EBADMEM; 279 280 /* Check if the fibril already terminated. */ 281 if (!polling->running) 282 return EOK; 283 284 /* Set the flag */ 285 polling->joining = true; 286 287 /* Unregister the pipe. */ 288 rc = usb_device_unmap_ep(polling->ep_mapping); 289 if (rc != EOK && rc != ENOENT && rc != EHANGUP) 290 return rc; 291 292 /* Wait for the fibril to terminate. */ 293 fibril_mutex_lock(&polling->guard); 294 while (polling->running) 295 fibril_condvar_wait(&polling->cv, &polling->guard); 296 fibril_mutex_unlock(&polling->guard); 297 298 return EOK; 352 299 } 353 300 -
uspace/lib/usbdev/src/dp.c
rf5e5f73 rdf6ded8 62 62 NESTING(CONFIGURATION, INTERFACE), 63 63 NESTING(INTERFACE, ENDPOINT), 64 NESTING(ENDPOINT, SSPEED_EP_COMPANION), 64 65 NESTING(INTERFACE, HUB), 65 66 NESTING(INTERFACE, HID), … … 126 127 * @retval -1 Invalid input. 127 128 */ 128 static int get_descriptor_type(const usb_dp_parser_data_t *data, const uint8_t *start) 129 static int get_descriptor_type(const usb_dp_parser_data_t *data, 130 const uint8_t *start) 129 131 { 130 132 if (start == NULL) { … … 257 259 int parent_type = get_descriptor_type(data, parent); 258 260 int possible_sibling_type = get_descriptor_type(data, possible_sibling); 259 if (is_nested_descriptor_type(parser, possible_sibling_type, parent_type)) { 261 if (is_nested_descriptor_type(parser, 262 possible_sibling_type, parent_type)) { 260 263 return possible_sibling; 261 264 } else { -
uspace/lib/usbdev/src/driver.c
rf5e5f73 rdf6ded8 2 2 * Copyright (c) 2011 Vojtech Horky 3 3 * Copyright (c) 2013 Jan Vesely 4 * Copyright (c) 2018 Petr Manek 4 5 * All rights reserved. 5 6 * … … 62 63 errno_t rc = usb_device_create_ddf(gen_dev, driver->endpoints, &err_msg); 63 64 if (rc != EOK) { 64 usb_log_error("USB device `%s' init failed (%s): %s. \n",65 usb_log_error("USB device `%s' init failed (%s): %s.", 65 66 ddf_dev_get_name(gen_dev), err_msg, str_error(rc)); 66 67 return rc; … … 85 86 assert(driver); 86 87 assert(driver->ops); 87 if (driver->ops->device_rem == NULL)88 if (driver->ops->device_remove == NULL) 88 89 return ENOTSUP; 90 89 91 /* Just tell the driver to stop whatever it is doing */ 90 92 usb_device_t *usb_dev = ddf_dev_data_get(gen_dev); 91 const errno_t ret = driver->ops->device_rem (usb_dev);93 const errno_t ret = driver->ops->device_remove(usb_dev); 92 94 if (ret != EOK) 93 95 return ret; 96 94 97 usb_device_destroy_ddf(gen_dev); 95 98 return EOK; … … 117 120 } 118 121 122 /** Callback when the driver is asked to online a specific function. 123 * 124 * This callback is a wrapper for USB specific version of @c fun_online. 125 * 126 * @param gen_dev Device function structure as prepared by DDF. 127 * @return Error code. 128 */ 129 static int generic_function_online(ddf_fun_t *fun) 130 { 131 assert(driver); 132 assert(driver->ops); 133 if (driver->ops->function_online == NULL) 134 return ENOTSUP; 135 return driver->ops->function_online(fun); 136 } 137 138 /** Callback when the driver is asked to offline a specific function. 139 * 140 * This callback is a wrapper for USB specific version of @c fun_offline. 141 * 142 * @param gen_dev Device function structure as prepared by DDF. 143 * @return Error code. 144 */ 145 static int generic_function_offline(ddf_fun_t *fun) 146 { 147 assert(driver); 148 assert(driver->ops); 149 if (driver->ops->function_offline == NULL) 150 return ENOTSUP; 151 return driver->ops->function_offline(fun); 152 } 153 119 154 static driver_ops_t generic_driver_ops = { 120 155 .dev_add = generic_device_add, 121 156 .dev_remove = generic_device_remove, 122 157 .dev_gone = generic_device_gone, 158 .fun_online = generic_function_online, 159 .fun_offline = generic_function_offline, 123 160 }; 124 161 static driver_t generic_driver = { -
uspace/lib/usbdev/src/pipes.c
rf5e5f73 rdf6ded8 2 2 * Copyright (c) 2011 Vojtech Horky 3 3 * Copyright (c) 2011 Jan Vesely 4 * Copyright (c) 2018 Ondrej Hlavaty, Michal Staruch 4 5 * All rights reserved. 5 6 * … … 36 37 #include <usb/dev/request.h> 37 38 #include <usb/usb.h> 38 #include <usb _iface.h>39 #include <usb/dma_buffer.h> 39 40 40 41 #include <assert.h> 42 #include <bitops.h> 41 43 #include <async.h> 44 #include <as.h> 42 45 #include <errno.h> 43 46 #include <mem.h> … … 51 54 assert(pipe != NULL); 52 55 53 if (!pipe->auto_reset_halt || (pipe-> endpoint_no != 0)) {56 if (!pipe->auto_reset_halt || (pipe->desc.endpoint_no != 0)) { 54 57 return; 55 58 } … … 57 60 /* Prevent infinite recursion. */ 58 61 pipe->auto_reset_halt = false; 59 usb_ request_clear_endpoint_halt(pipe, 0);62 usb_pipe_clear_halt(pipe, pipe); 60 63 pipe->auto_reset_halt = true; 64 } 65 66 /* Helper structure to avoid passing loads of arguments through */ 67 typedef struct { 68 usb_pipe_t *pipe; 69 usb_direction_t dir; 70 bool is_control; // Only for checking purposes 71 72 usbhc_iface_transfer_request_t req; 73 74 size_t transferred_size; 75 } transfer_t; 76 77 /** 78 * Issue a transfer in a separate exchange. 79 */ 80 static errno_t transfer_common(transfer_t *t) 81 { 82 if (!t->pipe) 83 return EBADMEM; 84 85 /* Only control writes make sense without buffer */ 86 if ((t->dir != USB_DIRECTION_OUT || !t->is_control) && t->req.size == 0) 87 return EINVAL; 88 89 /* Nonzero size requires buffer */ 90 if (!dma_buffer_is_set(&t->req.buffer) && t->req.size != 0) 91 return EINVAL; 92 93 /* Check expected direction */ 94 if (t->pipe->desc.direction != USB_DIRECTION_BOTH && 95 t->pipe->desc.direction != t->dir) 96 return EBADF; 97 98 /* Check expected transfer type */ 99 if ((t->pipe->desc.transfer_type == USB_TRANSFER_CONTROL) != t->is_control) 100 return EBADF; 101 102 async_exch_t *exch = async_exchange_begin(t->pipe->bus_session); 103 if (!exch) 104 return ENOMEM; 105 106 t->req.dir = t->dir; 107 t->req.endpoint = t->pipe->desc.endpoint_no; 108 109 const errno_t rc = usbhc_transfer(exch, &t->req, &t->transferred_size); 110 111 async_exchange_end(exch); 112 113 if (rc == ESTALL) 114 clear_self_endpoint_halt(t->pipe); 115 116 return rc; 117 } 118 119 /** 120 * Setup the transfer request inside transfer according to dma buffer provided. 121 * 122 * TODO: The buffer could have been allocated as a more strict one. Currently, 123 * we assume that the policy is just the requested one. 124 */ 125 static void setup_dma_buffer(transfer_t *t, void *base, void *ptr, size_t size) 126 { 127 t->req.buffer.virt = base; 128 t->req.buffer.policy = t->pipe->desc.transfer_buffer_policy; 129 t->req.offset = ptr - base; 130 t->req.size = size; 131 } 132 133 /** 134 * Compatibility wrapper for reads/writes without preallocated buffer. 135 */ 136 static errno_t transfer_wrap_dma(transfer_t *t, void *buf, size_t size) 137 { 138 if (size == 0) { 139 setup_dma_buffer(t, NULL, NULL, 0); 140 return transfer_common(t); 141 } 142 143 void *dma_buf = usb_pipe_alloc_buffer(t->pipe, size); 144 setup_dma_buffer(t, dma_buf, dma_buf, size); 145 146 if (t->dir == USB_DIRECTION_OUT) 147 memcpy(dma_buf, buf, size); 148 149 const errno_t err = transfer_common(t); 150 151 if (!err && t->dir == USB_DIRECTION_IN) 152 memcpy(buf, dma_buf, t->transferred_size); 153 154 usb_pipe_free_buffer(t->pipe, dma_buf); 155 return err; 156 } 157 158 static errno_t prepare_control(transfer_t *t, const void *setup, size_t setup_size) 159 { 160 if ((setup == NULL) || (setup_size != 8)) 161 return EINVAL; 162 163 memcpy(&t->req.setup, setup, 8); 164 return EOK; 61 165 } 62 166 … … 70 174 * @param[out] data_buffer Buffer for incoming data. 71 175 * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes). 72 * @param[out] data_transfer ed_size Number of bytes that were actually73 * transfer ed during the DATA stage.176 * @param[out] data_transferred_size Number of bytes that were actually 177 * transferred during the DATA stage. 74 178 * @return Error code. 75 179 */ 76 180 errno_t usb_pipe_control_read(usb_pipe_t *pipe, 77 181 const void *setup_buffer, size_t setup_buffer_size, 78 void *buffer, size_t buffer_size, size_t *transfered_size) 79 { 80 assert(pipe); 81 82 if ((setup_buffer == NULL) || (setup_buffer_size != 8)) { 83 return EINVAL; 84 } 85 86 if ((buffer == NULL) || (buffer_size == 0)) { 87 return EINVAL; 88 } 89 90 if ((pipe->direction != USB_DIRECTION_BOTH) 91 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) { 92 return EBADF; 93 } 94 95 uint64_t setup_packet; 96 memcpy(&setup_packet, setup_buffer, 8); 97 98 async_exch_t *exch = async_exchange_begin(pipe->bus_session); 99 size_t act_size = 0; 100 const errno_t rc = usb_read(exch, pipe->endpoint_no, setup_packet, buffer, 101 buffer_size, &act_size); 102 async_exchange_end(exch); 103 104 if (rc == ESTALL) { 105 clear_self_endpoint_halt(pipe); 106 } 107 108 if (rc == EOK && transfered_size != NULL) { 109 *transfered_size = act_size; 110 } 111 112 return rc; 182 void *buffer, size_t buffer_size, size_t *transferred_size) 183 { 184 errno_t err; 185 transfer_t transfer = { 186 .pipe = pipe, 187 .dir = USB_DIRECTION_IN, 188 .is_control = true, 189 }; 190 191 if ((err = prepare_control(&transfer, setup_buffer, setup_buffer_size))) 192 return err; 193 194 if ((err = transfer_wrap_dma(&transfer, buffer, buffer_size))) 195 return err; 196 197 if (transferred_size) 198 *transferred_size = transfer.transferred_size; 199 200 return EOK; 113 201 } 114 202 … … 129 217 { 130 218 assert(pipe); 131 132 if ((setup_buffer == NULL) || (setup_buffer_size != 8)) { 133 return EINVAL; 134 } 135 136 if ((buffer == NULL) && (buffer_size > 0)) { 137 return EINVAL; 138 } 139 140 if ((buffer != NULL) && (buffer_size == 0)) { 141 return EINVAL; 142 } 143 144 if ((pipe->direction != USB_DIRECTION_BOTH) 145 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) { 146 return EBADF; 147 } 148 149 uint64_t setup_packet; 150 memcpy(&setup_packet, setup_buffer, 8); 151 152 async_exch_t *exch = async_exchange_begin(pipe->bus_session); 153 const errno_t rc = usb_write(exch, 154 pipe->endpoint_no, setup_packet, buffer, buffer_size); 155 async_exchange_end(exch); 156 157 if (rc == ESTALL) { 158 clear_self_endpoint_halt(pipe); 159 } 160 161 return rc; 219 errno_t err; 220 transfer_t transfer = { 221 .pipe = pipe, 222 .dir = USB_DIRECTION_OUT, 223 .is_control = true, 224 }; 225 226 if ((err = prepare_control(&transfer, setup_buffer, setup_buffer_size))) 227 return err; 228 229 return transfer_wrap_dma(&transfer, (void *) buffer, buffer_size); 230 } 231 232 /** 233 * Allocate a buffer for data transmission, that satisfies the constraints 234 * imposed by the host controller. 235 * 236 * @param[in] pipe Pipe for which the buffer is allocated 237 * @param[in] size Size of the required buffer 238 */ 239 void *usb_pipe_alloc_buffer(usb_pipe_t *pipe, size_t size) 240 { 241 dma_buffer_t buf; 242 if (dma_buffer_alloc_policy(&buf, size, pipe->desc.transfer_buffer_policy)) 243 return NULL; 244 245 return buf.virt; 246 } 247 248 void usb_pipe_free_buffer(usb_pipe_t *pipe, void *buffer) 249 { 250 dma_buffer_t buf; 251 buf.virt = buffer; 252 dma_buffer_free(&buf); 162 253 } 163 254 … … 167 258 * @param[out] buffer Buffer where to store the data. 168 259 * @param[in] size Size of the buffer (in bytes). 169 * @param[out] size_transfer ed Number of bytes that were actually transfered.260 * @param[out] size_transferred Number of bytes that were actually transferred. 170 261 * @return Error code. 171 262 */ 172 263 errno_t usb_pipe_read(usb_pipe_t *pipe, 173 void *buffer, size_t size, size_t *size_transfered) 174 { 175 assert(pipe); 176 177 if (buffer == NULL) { 178 return EINVAL; 179 } 180 181 if (size == 0) { 182 return EINVAL; 183 } 184 185 if (pipe->direction != USB_DIRECTION_IN) { 186 return EBADF; 187 } 188 189 if (pipe->transfer_type == USB_TRANSFER_CONTROL) { 190 return EBADF; 191 } 192 193 /* Isochronous transfer are not supported (yet) */ 194 if (pipe->transfer_type != USB_TRANSFER_INTERRUPT && 195 pipe->transfer_type != USB_TRANSFER_BULK) 196 return ENOTSUP; 197 198 async_exch_t *exch = async_exchange_begin(pipe->bus_session); 199 size_t act_size = 0; 200 const errno_t rc = 201 usb_read(exch, pipe->endpoint_no, 0, buffer, size, &act_size); 202 async_exchange_end(exch); 203 204 if (rc == EOK && size_transfered != NULL) { 205 *size_transfered = act_size; 206 } 207 208 return rc; 264 void *buffer, size_t size, size_t *size_transferred) 265 { 266 assert(pipe); 267 errno_t err; 268 transfer_t transfer = { 269 .pipe = pipe, 270 .dir = USB_DIRECTION_IN, 271 }; 272 273 if ((err = transfer_wrap_dma(&transfer, buffer, size))) 274 return err; 275 276 if (size_transferred) 277 *size_transferred = transfer.transferred_size; 278 279 return EOK; 209 280 } 210 281 … … 219 290 { 220 291 assert(pipe); 221 222 if (buffer == NULL || size == 0) { 223 return EINVAL; 224 } 225 226 if (pipe->direction != USB_DIRECTION_OUT) { 227 return EBADF; 228 } 229 230 if (pipe->transfer_type == USB_TRANSFER_CONTROL) { 231 return EBADF; 232 } 233 234 /* Isochronous transfer are not supported (yet) */ 235 if (pipe->transfer_type != USB_TRANSFER_INTERRUPT && 236 pipe->transfer_type != USB_TRANSFER_BULK) 237 return ENOTSUP; 238 239 async_exch_t *exch = async_exchange_begin(pipe->bus_session); 240 const errno_t rc = usb_write(exch, pipe->endpoint_no, 0, buffer, size); 241 async_exchange_end(exch); 242 return rc; 292 transfer_t transfer = { 293 .pipe = pipe, 294 .dir = USB_DIRECTION_OUT, 295 }; 296 297 return transfer_wrap_dma(&transfer, (void *) buffer, size); 298 } 299 300 /** 301 * Request a read (in) transfer on an endpoint pipe, declaring that buffer 302 * is pointing to a memory area previously allocated by usb_pipe_alloc_buffer. 303 * 304 * @param[in] pipe Pipe used for the transfer. 305 * @param[in] buffer Buffer, previously allocated with usb_pipe_alloc_buffer. 306 * @param[in] size Size of the buffer (in bytes). 307 * @param[out] size_transferred Number of bytes that were actually transferred. 308 * @return Error code. 309 */ 310 errno_t usb_pipe_read_dma(usb_pipe_t *pipe, void *base, void *ptr, size_t size, 311 size_t *size_transferred) 312 { 313 assert(pipe); 314 errno_t err; 315 transfer_t transfer = { 316 .pipe = pipe, 317 .dir = USB_DIRECTION_IN, 318 }; 319 320 setup_dma_buffer(&transfer, base, ptr, size); 321 322 if ((err = transfer_common(&transfer))) 323 return err; 324 325 if (size_transferred) 326 *size_transferred = transfer.transferred_size; 327 328 return EOK; 329 } 330 331 /** 332 * Request a write (out) transfer on an endpoint pipe, declaring that buffer 333 * is pointing to a memory area previously allocated by usb_pipe_alloc_buffer. 334 * 335 * @param[in] pipe Pipe used for the transfer. 336 * @param[in] buffer Buffer, previously allocated with usb_pipe_alloc_buffer. 337 * @param[in] size Size of the buffer (in bytes). 338 * @return Error code. 339 */ 340 errno_t usb_pipe_write_dma(usb_pipe_t *pipe, void *base, void *ptr, size_t size) 341 { 342 assert(pipe); 343 transfer_t transfer = { 344 .pipe = pipe, 345 .dir = USB_DIRECTION_OUT, 346 }; 347 348 setup_dma_buffer(&transfer, base, ptr, size); 349 350 return transfer_common(&transfer); 243 351 } 244 352 … … 246 354 * 247 355 * @param pipe Endpoint pipe to be initialized. 248 * @param endpoint_no Endpoint number (in USB 1.1 in range 0 to 15). 249 * @param transfer_type Transfer type (e.g. interrupt or bulk). 250 * @param max_packet_size Maximum packet size in bytes. 251 * @param direction Endpoint direction (in/out). 252 * @return Error code. 253 */ 254 errno_t usb_pipe_initialize(usb_pipe_t *pipe, usb_endpoint_t endpoint_no, 255 usb_transfer_type_t transfer_type, size_t max_packet_size, 256 usb_direction_t direction, unsigned packets, usb_dev_session_t *bus_session) 257 { 258 assert(pipe); 259 260 pipe->endpoint_no = endpoint_no; 261 pipe->transfer_type = transfer_type; 262 pipe->packets = packets; 263 pipe->max_packet_size = max_packet_size; 264 pipe->direction = direction; 356 * @param bus_session Endpoint pipe to be initialized. 357 * @return Error code. 358 */ 359 errno_t usb_pipe_initialize(usb_pipe_t *pipe, usb_dev_session_t *bus_session) 360 { 361 assert(pipe); 362 265 363 pipe->auto_reset_halt = false; 266 364 pipe->bus_session = bus_session; … … 269 367 } 270 368 271 /** Initialize USB endpoint pipe as the default zero control pipe. 369 static const usb_pipe_desc_t default_control_pipe = { 370 .endpoint_no = 0, 371 .transfer_type = USB_TRANSFER_CONTROL, 372 .direction = USB_DIRECTION_BOTH, 373 .max_transfer_size = CTRL_PIPE_MIN_PACKET_SIZE, 374 .transfer_buffer_policy = DMA_POLICY_STRICT, 375 }; 376 377 /** Initialize USB default control pipe. 378 * 379 * This one is special because it must not be registered, it is registered 380 * automatically. 272 381 * 273 382 * @param pipe Endpoint pipe to be initialized. 383 * @param bus_session Endpoint pipe to be initialized. 274 384 * @return Error code. 275 385 */ … … 277 387 usb_dev_session_t *bus_session) 278 388 { 279 assert(pipe);280 281 const errno_t rc = usb_pipe_initialize(pipe, 0, USB_TRANSFER_CONTROL,282 CTRL_PIPE_MIN_PACKET_SIZE, USB_DIRECTION_BOTH, 1, bus_session); 283 389 const errno_t ret = usb_pipe_initialize(pipe, bus_session); 390 if (ret) 391 return ret; 392 393 pipe->desc = default_control_pipe; 284 394 pipe->auto_reset_halt = true; 285 395 286 return rc;396 return EOK; 287 397 } 288 398 … … 290 400 * 291 401 * @param pipe Pipe to be registered. 292 * @param interval Polling interval. 293 * @return Error code. 294 */ 295 errno_t usb_pipe_register(usb_pipe_t *pipe, unsigned interval) 402 * @param ep_desc Matched endpoint descriptor 403 * @param comp_desc Matched superspeed companion descriptro, if any 404 * @return Error code. 405 */ 406 errno_t usb_pipe_register(usb_pipe_t *pipe, 407 const usb_standard_endpoint_descriptor_t *ep_desc, 408 const usb_superspeed_endpoint_companion_descriptor_t *comp_desc) 409 { 410 assert(pipe); 411 assert(pipe->bus_session); 412 assert(ep_desc); 413 414 async_exch_t *exch = async_exchange_begin(pipe->bus_session); 415 if (!exch) 416 return ENOMEM; 417 418 usb_endpoint_descriptors_t descriptors = { 0 }; 419 420 #define COPY(field) descriptors.endpoint.field = ep_desc->field 421 COPY(endpoint_address); 422 COPY(attributes); 423 COPY(max_packet_size); 424 COPY(poll_interval); 425 #undef COPY 426 427 #define COPY(field) descriptors.companion.field = comp_desc->field 428 if (comp_desc) { 429 COPY(max_burst); 430 COPY(attributes); 431 COPY(bytes_per_interval); 432 } 433 #undef COPY 434 435 const errno_t ret = usbhc_register_endpoint(exch, 436 &pipe->desc, &descriptors); 437 async_exchange_end(exch); 438 return ret; 439 } 440 441 /** Revert endpoint registration with the host controller. 442 * 443 * @param pipe Pipe to be unregistered. 444 * @return Error code. 445 */ 446 errno_t usb_pipe_unregister(usb_pipe_t *pipe) 296 447 { 297 448 assert(pipe); … … 300 451 if (!exch) 301 452 return ENOMEM; 302 const errno_t ret = usb_register_endpoint(exch, pipe->endpoint_no, 303 pipe->transfer_type, pipe->direction, pipe->max_packet_size,304 pipe->packets, interval); 453 454 const errno_t ret = usbhc_unregister_endpoint(exch, &pipe->desc); 455 305 456 async_exchange_end(exch); 306 457 return ret; 307 458 } 308 459 309 /** Revert endpoint registration with the host controller.310 *311 * @param pipe Pipe to be unregistered.312 * @return Error code.313 */314 errno_t usb_pipe_unregister(usb_pipe_t *pipe)315 {316 assert(pipe);317 assert(pipe->bus_session);318 async_exch_t *exch = async_exchange_begin(pipe->bus_session);319 if (!exch)320 return ENOMEM;321 const errno_t ret = usb_unregister_endpoint(exch, pipe->endpoint_no,322 pipe->direction);323 async_exchange_end(exch);324 return ret;325 }326 327 460 /** 328 461 * @} -
uspace/lib/usbdev/src/pipesinit.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Vojtech Horky 3 * Copyright (c) 2018 Ondrej Hlavaty, Michal Staruch 3 4 * All rights reserved. 4 5 * … … 38 39 #include <usb/dev/request.h> 39 40 #include <usb/usb.h> 41 #include <usb/debug.h> 40 42 #include <usb/descriptor.h> 41 43 … … 59 61 NESTING(INTERFACE, HID), 60 62 NESTING(HID, HID_REPORT), 63 NESTING(ENDPOINT, SSPEED_EP_COMPANION), 61 64 LAST_NESTING 62 65 }; … … 70 73 { 71 74 return descriptor[1] == USB_DESCTYPE_ENDPOINT; 75 } 76 77 /** Tells whether given descriptor is of superspeed companion type. 78 * 79 * @param descriptor Descriptor in question. 80 * @return Whether the given descriptor is superspeed companion descriptor. 81 */ 82 static inline bool is_superspeed_companion_descriptor(const uint8_t *descriptor) 83 { 84 return descriptor[1] == USB_DESCTYPE_SSPEED_EP_COMPANION; 72 85 } 73 86 … … 134 147 if (interface_number_fits 135 148 && interface_setting_fits 136 && endpoint_descriptions_fits) { 149 && endpoint_descriptions_fits 150 && !mapping->present) { 137 151 return mapping; 138 152 } … … 141 155 mapping_count--; 142 156 } 157 143 158 return NULL; 144 159 } … … 150 165 * @param interface Interface descriptor under which belongs the @p endpoint. 151 166 * @param endpoint Endpoint descriptor. 167 * @param companion Superspeed companion descriptor. 152 168 * @return Error code. 153 169 */ … … 156 172 usb_standard_interface_descriptor_t *interface, 157 173 usb_standard_endpoint_descriptor_t *endpoint_desc, 174 usb_superspeed_endpoint_companion_descriptor_t *companion_desc, 158 175 usb_dev_session_t *bus_session) 159 176 { … … 162 179 * Get endpoint characteristics. 163 180 */ 164 165 /* Actual endpoint number is in bits 0..3 */166 const usb_endpoint_t ep_no = endpoint_desc->endpoint_address & 0x0F;167 168 181 const usb_endpoint_description_t description = { 169 /* Endpoint direction is set by bit 7 */ 170 .direction = (endpoint_desc->endpoint_address & 128) 171 ? USB_DIRECTION_IN : USB_DIRECTION_OUT, 172 /* Transfer type is in bits 0..2 and 173 * the enum values corresponds 1:1 */ 174 .transfer_type = endpoint_desc->attributes & 3, 182 .transfer_type = USB_ED_GET_TRANSFER_TYPE(*endpoint_desc), 183 .direction = USB_ED_GET_DIR(*endpoint_desc), 175 184 176 185 /* Get interface characteristics. */ … … 194 203 } 195 204 196 errno_t rc = usb_pipe_initialize(&ep_mapping->pipe, 197 ep_no, description.transfer_type, 198 ED_MPS_PACKET_SIZE_GET( 199 uint16_usb2host(endpoint_desc->max_packet_size)), 200 description.direction, 201 ED_MPS_TRANS_OPPORTUNITIES_GET( 202 uint16_usb2host(endpoint_desc->max_packet_size)), bus_session); 203 if (rc != EOK) { 204 return rc; 205 } 205 errno_t err = usb_pipe_initialize(&ep_mapping->pipe, bus_session); 206 if (err) 207 return err; 206 208 207 209 ep_mapping->present = true; 208 210 ep_mapping->descriptor = endpoint_desc; 211 ep_mapping->companion_descriptor = companion_desc; 209 212 ep_mapping->interface = interface; 210 213 … … 235 238 do { 236 239 if (is_endpoint_descriptor(descriptor)) { 240 /* Check if companion descriptor is present too, it should immediatelly follow. */ 241 const uint8_t *companion_desc = usb_dp_get_nested_descriptor(parser, 242 parser_data, descriptor); 243 if (companion_desc && !is_superspeed_companion_descriptor(companion_desc)) { 244 /* Not what we wanted, don't pass it further. */ 245 companion_desc = NULL; 246 } 247 237 248 (void) process_endpoint(mapping, mapping_count, 238 249 (usb_standard_interface_descriptor_t *) … … 240 251 (usb_standard_endpoint_descriptor_t *) 241 252 descriptor, 253 (usb_superspeed_endpoint_companion_descriptor_t *) 254 companion_desc, 242 255 bus_session); 243 256 } … … 288 301 if (config_descriptor == NULL) 289 302 return EBADMEM; 290 303 291 304 if (config_descriptor_size < 292 305 sizeof(usb_standard_configuration_descriptor_t)) { … … 328 341 } 329 342 330 /** Probe default control pipe for max packet size.331 *332 * The function tries to get the correct value of max packet size several333 * time before giving up.334 *335 * The session on the pipe shall not be started.336 *337 * @param pipe Default control pipe.338 * @return Error code.339 */340 errno_t usb_pipe_probe_default_control(usb_pipe_t *pipe)341 {342 assert(pipe);343 static_assert(DEV_DESCR_MAX_PACKET_SIZE_OFFSET < CTRL_PIPE_MIN_PACKET_SIZE);344 345 if ((pipe->direction != USB_DIRECTION_BOTH) ||346 (pipe->transfer_type != USB_TRANSFER_CONTROL) ||347 (pipe->endpoint_no != 0)) {348 return EINVAL;349 }350 351 uint8_t dev_descr_start[CTRL_PIPE_MIN_PACKET_SIZE];352 size_t transferred_size;353 errno_t rc;354 for (size_t attempt_var = 0; attempt_var < 3; ++attempt_var) {355 rc = usb_request_get_descriptor(pipe, USB_REQUEST_TYPE_STANDARD,356 USB_REQUEST_RECIPIENT_DEVICE, USB_DESCTYPE_DEVICE,357 0, 0, dev_descr_start, CTRL_PIPE_MIN_PACKET_SIZE,358 &transferred_size);359 if (rc == EOK) {360 if (transferred_size != CTRL_PIPE_MIN_PACKET_SIZE) {361 rc = ELIMIT;362 continue;363 }364 break;365 }366 }367 if (rc != EOK) {368 return rc;369 }370 371 pipe->max_packet_size372 = dev_descr_start[DEV_DESCR_MAX_PACKET_SIZE_OFFSET];373 374 return EOK;375 }376 377 343 /** 378 344 * @} -
uspace/lib/usbdev/src/request.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Vojtech Horky 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 118 119 * @param data_size Size of the @p data buffer 119 120 * (in native endianness). 120 * @param actual_data_size Actual size of transfer ed data121 * @param actual_data_size Actual size of transferred data 121 122 * (in native endianness). 122 123 * … … 183 184 184 185 uint16_t status_usb_endianess; 185 size_t data_transfer ed_size;186 size_t data_transferred_size; 186 187 errno_t rc = usb_control_request_get(pipe, USB_REQUEST_TYPE_STANDARD, 187 188 recipient, USB_DEVREQ_GET_STATUS, 0, uint16_host2usb(index), 188 &status_usb_endianess, 2, &data_transfer ed_size);189 if (rc != EOK) { 190 return rc; 191 } 192 if (data_transfer ed_size != 2) {189 &status_usb_endianess, 2, &data_transferred_size); 190 if (rc != EOK) { 191 return rc; 192 } 193 if (data_transferred_size != 2) { 193 194 return ELIMIT; 194 195 } … … 314 315 */ 315 316 uint8_t tmp_buffer; 316 size_t bytes_transfer ed;317 size_t bytes_transferred; 317 318 rc = usb_request_get_descriptor(pipe, request_type, recipient, 318 319 descriptor_type, descriptor_index, language, 319 &tmp_buffer, sizeof(tmp_buffer), &bytes_transfer ed);320 if (rc != EOK) { 321 return rc; 322 } 323 if (bytes_transfer ed != 1) {320 &tmp_buffer, sizeof(tmp_buffer), &bytes_transferred); 321 if (rc != EOK) { 322 return rc; 323 } 324 if (bytes_transferred != 1) { 324 325 return ELIMIT; 325 326 } … … 340 341 rc = usb_request_get_descriptor(pipe, request_type, recipient, 341 342 descriptor_type, descriptor_index, language, 342 buffer, size, &bytes_transfer ed);343 buffer, size, &bytes_transferred); 343 344 if (rc != EOK) { 344 345 free(buffer); 345 346 return rc; 346 347 } 347 if (bytes_transfer ed != size) {348 if (bytes_transferred != size) { 348 349 free(buffer); 349 350 return ELIMIT; … … 824 825 * @return Error code. 825 826 */ 826 errno_t usb_request_clear_endpoint_halt(usb_pipe_t *pipe, uint16_t ep_index)827 static errno_t usb_request_clear_endpoint_halt(usb_pipe_t *pipe, uint16_t ep_index) 827 828 { 828 829 return usb_request_clear_feature(pipe, … … 843 844 return EINVAL; 844 845 } 845 return usb_request_clear_endpoint_halt(ctrl_pipe, 846 target_pipe->endpoint_no); 846 847 uint16_t index = target_pipe->desc.endpoint_no; 848 index |= (target_pipe->desc.direction == USB_DIRECTION_IN) << 7; 849 return usb_request_clear_endpoint_halt(ctrl_pipe, index); 847 850 } 848 851 … … 858 861 { 859 862 uint16_t status_tmp; 860 uint16_t pipe_index = (uint16_t) pipe-> endpoint_no;863 uint16_t pipe_index = (uint16_t) pipe->desc.endpoint_no; 861 864 errno_t rc = usb_request_get_status(ctrl_pipe, 862 865 USB_REQUEST_RECIPIENT_ENDPOINT, uint16_host2usb(pipe_index), -
uspace/lib/usbhid/src/hiddescriptor.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Matej Klonfar 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 176 177 177 178 if(report_item->usages_count > 0){ 178 usages = malloc(sizeof( int32_t) * report_item->usages_count);179 usages = malloc(sizeof(uint32_t) * report_item->usages_count); 179 180 memcpy(usages, report_item->usages, sizeof(int32_t) * 180 181 report_item->usages_count); … … 247 248 field->size = report_item->size; 248 249 249 if(report_item->type == USB_HID_REPORT_TYPE_INPUT) { 250 int offset = report_item->offset + report_item->size * i; 251 int field_offset = (offset/8)*8 + (offset/8 + 1) * 8 - 252 offset - report_item->size; 253 if(field_offset < 0) { 254 field->offset = 0; 255 } 256 else { 257 field->offset = field_offset; 258 } 259 } 260 else { 261 field->offset = report_item->offset + (i * report_item->size); 262 } 263 250 field->offset = report_item->offset + (i * report_item->size); 264 251 265 252 if(report->use_report_ids != 0) { … … 896 883 { 897 884 if(list == NULL || list_empty(list)) { 898 usb_log_debug("\tempty \n");885 usb_log_debug("\tempty"); 899 886 return; 900 887 } … … 902 889 list_foreach(*list, ritems_link, usb_hid_report_field_t, 903 890 report_item) { 904 usb_log_debug("\t\tOFFSET: % X\n", report_item->offset);905 usb_log_debug("\t\tSIZE: %zu \n", report_item->size);906 usb_log_debug("\t\tLOGMIN: %d \n",891 usb_log_debug("\t\tOFFSET: %u", report_item->offset); 892 usb_log_debug("\t\tSIZE: %zu", report_item->size); 893 usb_log_debug("\t\tLOGMIN: %d", 907 894 report_item->logical_minimum); 908 usb_log_debug("\t\tLOGMAX: %d \n",895 usb_log_debug("\t\tLOGMAX: %d", 909 896 report_item->logical_maximum); 910 usb_log_debug("\t\tPHYMIN: %d \n",897 usb_log_debug("\t\tPHYMIN: %d", 911 898 report_item->physical_minimum); 912 usb_log_debug("\t\tPHYMAX: %d \n",899 usb_log_debug("\t\tPHYMAX: %d", 913 900 report_item->physical_maximum); 914 usb_log_debug("\t\ttUSAGEMIN: %X \n",901 usb_log_debug("\t\ttUSAGEMIN: %X", 915 902 report_item->usage_minimum); 916 usb_log_debug("\t\tUSAGEMAX: %X \n",903 usb_log_debug("\t\tUSAGEMAX: %X", 917 904 report_item->usage_maximum); 918 usb_log_debug("\t\tUSAGES COUNT: %zu \n",905 usb_log_debug("\t\tUSAGES COUNT: %zu", 919 906 report_item->usages_count); 920 907 921 usb_log_debug("\t\tVALUE: %X \n", report_item->value);922 usb_log_debug("\t\ttUSAGE: %X \n", report_item->usage);923 usb_log_debug("\t\tUSAGE PAGE: %X \n", report_item->usage_page);908 usb_log_debug("\t\tVALUE: %X", report_item->value); 909 usb_log_debug("\t\ttUSAGE: %X", report_item->usage); 910 usb_log_debug("\t\tUSAGE PAGE: %X", report_item->usage_page); 924 911 925 912 usb_hid_print_usage_path(report_item->collection_path); 926 927 usb_log_debug("\n");928 913 } 929 914 } … … 943 928 list_foreach(report->reports, reports_link, 944 929 usb_hid_report_description_t, report_des) { 945 usb_log_debug("Report ID: %d \n", report_des->report_id);946 usb_log_debug("\tType: %d \n", report_des->type);947 usb_log_debug("\tLength: %zu \n", report_des->bit_length);948 usb_log_debug("\tB Size: %zu \n",930 usb_log_debug("Report ID: %d", report_des->report_id); 931 usb_log_debug("\tType: %d", report_des->type); 932 usb_log_debug("\tLength: %zu", report_des->bit_length); 933 usb_log_debug("\tB Size: %zu", 949 934 usb_hid_report_byte_size(report, 950 935 report_des->report_id, 951 936 report_des->type)); 952 usb_log_debug("\tItems: %zu \n", report_des->item_length);937 usb_log_debug("\tItems: %zu", report_des->item_length); 953 938 954 939 usb_hid_descriptor_print_list(&report_des->report_items); -
uspace/lib/usbhid/src/hidparser.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Matej Klonfar 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 40 41 #include <usb/debug.h> 41 42 #include <assert.h> 43 #include <bitops.h> 44 #include <macros.h> 42 45 43 46 … … 49 52 int usb_hid_translate_data(usb_hid_report_field_t *item, const uint8_t *data); 50 53 51 uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item, 52 int32_t value);54 uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item, 55 int32_t value); 53 56 54 57 … … 73 76 * 74 77 * @param parser Opaque report parser structure 75 * @param report_id 78 * @param report_id 76 79 * @param type 77 80 * @return Number of items in specified report 78 81 */ 79 size_t usb_hid_report_size(usb_hid_report_t *report, uint8_t report_id, 82 size_t usb_hid_report_size(usb_hid_report_t *report, uint8_t report_id, 80 83 usb_hid_report_type_t type) 81 84 { … … 97 100 * 98 101 * @param parser Opaque report parser structure 99 * @param report_id 102 * @param report_id 100 103 * @param type 101 104 * @return Number of items in specified report 102 105 */ 103 size_t usb_hid_report_byte_size(usb_hid_report_t *report, uint8_t report_id, 106 size_t usb_hid_report_byte_size(usb_hid_report_t *report, uint8_t report_id, 104 107 usb_hid_report_type_t type) 105 108 { … … 114 117 return 0; 115 118 } else { 116 return ((report_des->bit_length + 7) / 8) ;119 return ((report_des->bit_length + 7) / 8); 117 120 } 118 121 } … … 126 129 * @param data Data for the report. 127 130 * @return Error code. 128 */ 129 errno_t usb_hid_parse_report(const usb_hid_report_t *report, const uint8_t *data, 131 */ 132 errno_t usb_hid_parse_report(const usb_hid_report_t *report, const uint8_t *data, 130 133 size_t size, uint8_t *report_id) 131 134 { 132 135 usb_hid_report_description_t *report_des; 133 136 usb_hid_report_type_t type = USB_HID_REPORT_TYPE_INPUT; 134 137 135 138 if (report == NULL) { 136 139 return EINVAL; … … 143 146 } 144 147 145 report_des = usb_hid_report_find_description(report, *report_id, 148 report_des = usb_hid_report_find_description(report, *report_id, 146 149 type); 147 150 … … 155 158 156 159 if (USB_HID_ITEM_FLAG_CONSTANT(item->item_flags) == 0) { 157 160 158 161 if (USB_HID_ITEM_FLAG_VARIABLE(item->item_flags) == 0) { 159 162 /* array */ 160 item->value = 161 usb_hid_translate_data(item, data);162 163 item->value = 164 usb_hid_translate_data(item, data); 165 163 166 item->usage = USB_HID_EXTENDED_USAGE( 164 167 item->usages[item->value - 165 168 item->physical_minimum]); 166 169 167 item->usage_page = 170 item->usage_page = 168 171 USB_HID_EXTENDED_USAGE_PAGE( 169 172 item->usages[item->value - … … 171 174 172 175 usb_hid_report_set_last_item( 173 item->collection_path, 174 USB_HID_TAG_CLASS_GLOBAL, 176 item->collection_path, 177 USB_HID_TAG_CLASS_GLOBAL, 175 178 item->usage_page); 176 179 177 180 usb_hid_report_set_last_item( 178 item->collection_path, 181 item->collection_path, 179 182 USB_HID_TAG_CLASS_LOCAL, item->usage); 180 183 } else { 181 184 /* variable item */ 182 item->value = usb_hid_translate_data(item, 185 item->value = usb_hid_translate_data(item, 183 186 data); 184 187 } 185 188 } 186 189 } 187 190 188 191 return EOK; 189 192 } … … 199 202 int usb_hid_translate_data(usb_hid_report_field_t *item, const uint8_t *data) 200 203 { 201 int resolution;202 int offset;203 int part_size;204 205 int32_t value = 0;206 int32_t mask = 0;207 const uint8_t *foo = 0;208 209 204 /* now only short tags are allowed */ 210 205 if (item->size > 32) { … … 214 209 if ((item->physical_minimum == 0) && (item->physical_maximum == 0)) { 215 210 item->physical_minimum = item->logical_minimum; 216 item->physical_maximum = item->logical_maximum; 217 } 218 219 211 item->physical_maximum = item->logical_maximum; 212 } 213 214 int resolution; 220 215 if (item->physical_maximum == item->physical_minimum) { 221 resolution = 1; 222 } else { 223 resolution = (item->logical_maximum - item->logical_minimum) / 224 ((item->physical_maximum - item->physical_minimum) * 225 (usb_pow(10, (item->unit_exponent)))); 226 } 227 228 offset = item->offset; 229 // FIXME 230 if ((size_t) (offset / 8) != (size_t) ((offset+item->size - 1) / 8)) { 231 232 part_size = 0; 233 234 size_t i = 0; 235 for (i = (size_t) (offset / 8); 236 i <= (size_t) (offset + item->size - 1) / 8; i++) { 237 if (i == (size_t) (offset / 8)) { 238 /* the higher one */ 239 part_size = 8 - (offset % 8); 240 foo = data + i; 241 mask = ((1 << (item->size - part_size)) - 1); 242 value = (*foo & mask); 243 } else if (i == ((offset + item->size - 1) / 8)) { 244 /* the lower one */ 245 foo = data + i; 246 mask = ((1 << (item->size - part_size)) - 1) << 247 (8 - (item->size - part_size)); 248 249 value = (((*foo & mask) >> (8 - 250 (item->size - part_size))) << part_size) + 251 value; 252 } else { 253 value = (*(data + 1) << (part_size + 8)) + 254 value; 255 part_size += 8; 256 } 257 } 258 } else { 259 foo = data + (offset / 8); 260 mask = ((1 << item->size) - 1) << 261 (8 - ((offset % 8) + item->size)); 262 value = (*foo & mask) >> (8 - ((offset % 8) + item->size)); 216 resolution = 1; 217 } else { 218 resolution = (item->logical_maximum - item->logical_minimum) / 219 ((item->physical_maximum - item->physical_minimum) * 220 (usb_pow(10, (item->unit_exponent)))); 221 } 222 223 int32_t value = 0; 224 225 /* First, skip all bytes we don't care */ 226 data += item->offset / 8; 227 228 int bits = item->size; 229 int taken = 0; 230 231 /* Than we take the higher bits from the LSB */ 232 const unsigned bit_offset = item->offset % 8; 233 const int lsb_bits = min(bits, 8); 234 235 value |= (*data >> bit_offset) & BIT_RRANGE(uint8_t, lsb_bits); 236 bits -= lsb_bits; 237 taken += lsb_bits; 238 data++; 239 240 /* Then there may be bytes, which we take as a whole. */ 241 while (bits > 8) { 242 value |= *data << taken; 243 taken += 8; 244 bits -= 8; 245 data++; 246 } 247 248 /* And, finally, lower bits from HSB. */ 249 if (bits > 0) { 250 value |= (*data & BIT_RRANGE(uint8_t, bits)) << taken; 263 251 } 264 252 … … 267 255 } 268 256 269 return (int) (((value - item->logical_minimum) / resolution) + 257 return (int) (((value - item->logical_minimum) / resolution) + 270 258 item->physical_minimum); 271 259 } … … 274 262 /* OUTPUT API */ 275 263 276 /** 264 /** 277 265 * Allocates output report buffer for output report 278 266 * … … 282 270 * @return Returns allocated output buffer for specified output 283 271 */ 284 uint8_t *usb_hid_report_output(usb_hid_report_t *report, size_t *size, 272 uint8_t *usb_hid_report_output(usb_hid_report_t *report, size_t *size, 285 273 uint8_t report_id) 286 274 { … … 334 322 * @return Error code 335 323 */ 336 errno_t usb_hid_report_output_translate(usb_hid_report_t *report, 324 errno_t usb_hid_report_output_translate(usb_hid_report_t *report, 337 325 uint8_t report_id, uint8_t *buffer, size_t size) 338 326 { … … 341 329 int length; 342 330 int32_t tmp_value; 343 331 344 332 if (report == NULL) { 345 333 return EINVAL; … … 351 339 352 340 usb_hid_report_description_t *report_des; 353 report_des = usb_hid_report_find_description(report, report_id, 341 report_des = usb_hid_report_find_description(report, report_id, 354 342 USB_HID_REPORT_TYPE_OUTPUT); 355 343 356 344 if (report_des == NULL) { 357 345 return EINVAL; … … 360 348 list_foreach(report_des->report_items, ritems_link, 361 349 usb_hid_report_field_t, report_item) { 362 value = usb_hid_translate_data_reverse(report_item, 350 value = usb_hid_translate_data_reverse(report_item, 363 351 report_item->value); 364 352 365 353 offset = report_des->bit_length - report_item->offset - 1; 366 354 length = report_item->size; 367 368 usb_log_debug("\ttranslated value: %x \n", value);355 356 usb_log_debug("\ttranslated value: %x", value); 369 357 370 358 if ((offset / 8) == ((offset + length - 1) / 8)) { 371 if (((size_t) (offset / 8) >= size) || 359 if (((size_t) (offset / 8) >= size) || 372 360 ((size_t) (offset + length - 1) / 8) >= size) { 373 361 break; // TODO ErrorCode … … 376 364 value = value << shift; 377 365 value = value & (((1 << length) - 1) << shift); 378 366 379 367 uint8_t mask = 0; 380 368 mask = 0xff - (((1 << length) - 1) << shift); … … 388 376 if (i == (offset / 8)) { 389 377 tmp_value = value; 390 tmp_value = tmp_value & 378 tmp_value = tmp_value & 391 379 ((1 << (8 - (offset % 8))) - 1); 392 380 393 381 tmp_value = tmp_value << (offset % 8); 394 382 395 383 mask = ~(((1 << (8 - (offset % 8))) - 1) 396 384 << (offset % 8)); 397 385 398 buffer[i] = (buffer[i] & mask) | 386 buffer[i] = (buffer[i] & mask) | 399 387 tmp_value; 400 388 } else if (i == ((offset + length - 1) / 8)) { 401 402 value = value >> (length - 389 390 value = value >> (length - 403 391 ((offset + length) % 8)); 404 392 405 value = value & ((1 << (length - 393 value = value & ((1 << (length - 406 394 ((offset + length) % 8))) - 1); 407 408 mask = (1 << (length - 395 396 mask = (1 << (length - 409 397 ((offset + length) % 8))) - 1; 410 398 … … 419 407 report_item->value = 0; 420 408 } 421 409 422 410 return EOK; 423 411 } … … 430 418 * @return ranslated value 431 419 */ 432 uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item, 420 uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item, 433 421 int value) 434 422 { … … 437 425 438 426 if (USB_HID_ITEM_FLAG_CONSTANT(item->item_flags)) { 439 ret =item->logical_minimum;427 return item->logical_minimum; 440 428 } 441 429 442 430 if ((item->physical_minimum == 0) && (item->physical_maximum == 0)) { 443 431 item->physical_minimum = item->logical_minimum; 444 item->physical_maximum = item->logical_maximum; 445 } 446 432 item->physical_maximum = item->logical_maximum; 433 } 434 447 435 /* variable item */ 448 436 if (item->physical_maximum == item->physical_minimum) { 449 resolution = 1;450 } else { 451 resolution = (item->logical_maximum - item->logical_minimum) /452 ((item->physical_maximum - item->physical_minimum) *453 (usb_pow(10, (item->unit_exponent))));454 } 455 456 ret = ((value - item->physical_minimum) * resolution) + 437 resolution = 1; 438 } else { 439 resolution = (item->logical_maximum - item->logical_minimum) / 440 ((item->physical_maximum - item->physical_minimum) * 441 (usb_pow(10, (item->unit_exponent)))); 442 } 443 444 ret = ((value - item->physical_minimum) * resolution) + 457 445 item->logical_minimum; 458 446 459 447 usb_log_debug("\tvalue(%x), resolution(%x), phymin(%x) logmin(%x), " 460 "ret(%x)\n", value, resolution, item->physical_minimum, 448 "ret(%x)\n", value, resolution, item->physical_minimum, 461 449 item->logical_minimum, ret); 462 450 463 451 if ((item->logical_minimum < 0) || (item->logical_maximum < 0)) { 464 452 return USB_HID_INT32_TO_UINT32(ret, item->size); … … 479 467 { 480 468 usb_hid_report_item_t *new_report_item; 481 469 482 470 if (!(new_report_item = malloc(sizeof(usb_hid_report_item_t)))) { 483 471 return NULL; 484 } 472 } 485 473 memcpy(new_report_item,item, sizeof(usb_hid_report_item_t)); 486 474 link_initialize(&(new_report_item->link)); … … 497 485 * @param field Current field. If NULL is given, the first one in the report 498 486 * is returned. Otherwise the next one i nthe list is returned. 499 * @param path Usage path specifying which fields wa are interested in. 487 * @param path Usage path specifying which fields wa are interested in. 500 488 * @param flags Flags defining mode of usage paths comparison 501 489 * @param type Type of report we search. … … 503 491 * @retval Pointer to the founded report structure when founded 504 492 */ 505 usb_hid_report_field_t *usb_hid_report_get_sibling(usb_hid_report_t *report, 506 usb_hid_report_field_t *field, usb_hid_report_path_t *path, int flags, 493 usb_hid_report_field_t *usb_hid_report_get_sibling(usb_hid_report_t *report, 494 usb_hid_report_field_t *field, usb_hid_report_path_t *path, int flags, 507 495 usb_hid_report_type_t type) 508 496 { 509 usb_hid_report_description_t *report_des = 497 usb_hid_report_description_t *report_des = 510 498 usb_hid_report_find_description(report, path->report_id, type); 511 499 512 500 link_t *field_it; 513 501 514 502 if (report_des == NULL) { 515 503 return NULL; … … 523 511 524 512 while (field_it != &report_des->report_items.head) { 525 field = list_get_instance(field_it, usb_hid_report_field_t, 513 field = list_get_instance(field_it, usb_hid_report_field_t, 526 514 ritems_link); 527 515 … … 565 553 usb_hid_report_description_t *report_des; 566 554 link_t *report_it; 567 555 568 556 if (report_id > 0) { 569 report_des = usb_hid_report_find_description(report, report_id, 557 report_des = usb_hid_report_find_description(report, report_id, 570 558 type); 571 559 if (report_des == NULL) { … … 573 561 } else { 574 562 report_it = report_des->reports_link.next; 575 } 563 } 576 564 } else { 577 565 report_it = report->reports.head.next; … … 579 567 580 568 while (report_it != &report->reports.head) { 581 report_des = list_get_instance(report_it, 569 report_des = list_get_instance(report_it, 582 570 usb_hid_report_description_t, reports_link); 583 571 … … 606 594 return; 607 595 } 608 596 609 597 report_item->usages_count = 0; 610 598 memset(report_item->usages, 0, USB_HID_MAX_USAGES); 611 599 612 600 report_item->extended_usage_page = 0; 613 601 report_item->usage_minimum = 0; -
uspace/lib/usbhid/src/hidpath.c
rf5e5f73 rdf6ded8 73 73 * @return Error code 74 74 */ 75 errno_t usb_hid_report_path_append_item(usb_hid_report_path_t *usage_path, 76 int32_t usage_page, int32_t usage)77 { 78 usb_hid_report_usage_path_t *item 79 =malloc(sizeof(usb_hid_report_usage_path_t));75 errno_t usb_hid_report_path_append_item(usb_hid_report_path_t *usage_path, 76 int32_t usage_page, int32_t usage) 77 { 78 usb_hid_report_usage_path_t *item = 79 malloc(sizeof(usb_hid_report_usage_path_t)); 80 80 81 81 if (item == NULL) { … … 87 87 item->usage_page = usage_page; 88 88 item->flags = 0; 89 89 90 90 list_append (&item->rpath_items_link, &usage_path->items); 91 91 usage_path->depth++; … … 96 96 /** 97 97 * Removes last item from the usage path structure 98 * @param usage_path 98 * @param usage_path 99 99 * @return void 100 100 */ … … 103 103 link_t *item_link; 104 104 usb_hid_report_usage_path_t *item; 105 106 if (!list_empty(&usage_path->items)){105 106 if (!list_empty(&usage_path->items)) { 107 107 item_link = list_last(&usage_path->items); 108 108 item = list_get_instance(item_link, … … 124 124 { 125 125 usb_hid_report_usage_path_t *item; 126 127 if (!list_empty(&usage_path->items)){126 127 if (!list_empty(&usage_path->items)) { 128 128 item = list_get_instance(list_last(&usage_path->items), 129 usb_hid_report_usage_path_t, rpath_items_link);129 usb_hid_report_usage_path_t, rpath_items_link); 130 130 131 131 memset(item, 0, sizeof(usb_hid_report_usage_path_t)); … … 143 143 * @return void 144 144 */ 145 void usb_hid_report_set_last_item(usb_hid_report_path_t *usage_path, 146 int32_t tag, int32_t data)145 void usb_hid_report_set_last_item(usb_hid_report_path_t *usage_path, 146 int32_t tag, int32_t data) 147 147 { 148 148 usb_hid_report_usage_path_t *item; 149 150 if (!list_empty(&usage_path->items)){149 150 if (!list_empty(&usage_path->items)) { 151 151 item = list_get_instance(list_last(&usage_path->items), 152 152 usb_hid_report_usage_path_t, rpath_items_link); 153 153 154 switch(tag) { 155 case USB_HID_TAG_CLASS_GLOBAL: 156 item->usage_page = data; 157 break; 158 case USB_HID_TAG_CLASS_LOCAL: 159 item->usage = data; 160 break; 161 } 162 } 163 164 } 165 166 167 /** 168 * 169 * 170 * 171 * 172 */ 154 switch (tag) { 155 case USB_HID_TAG_CLASS_GLOBAL: 156 item->usage_page = data; 157 break; 158 case USB_HID_TAG_CLASS_LOCAL: 159 item->usage = data; 160 break; 161 } 162 } 163 } 164 173 165 void usb_hid_print_usage_path(usb_hid_report_path_t *path) 174 166 { 175 usb_log_debug("USAGE_PATH FOR RId(%d): \n", path->report_id);176 usb_log_debug("\tLENGTH: %d \n", path->depth);167 usb_log_debug("USAGE_PATH FOR RId(%d):", path->report_id); 168 usb_log_debug("\tLENGTH: %d", path->depth); 177 169 178 170 list_foreach(path->items, rpath_items_link, 179 171 usb_hid_report_usage_path_t, path_item) { 180 172 181 usb_log_debug("\tUSAGE_PAGE: %X \n", path_item->usage_page);182 usb_log_debug("\tUSAGE: %X \n", path_item->usage);183 usb_log_debug("\tFLAGS: %d \n", path_item->flags);173 usb_log_debug("\tUSAGE_PAGE: %X", path_item->usage_page); 174 usb_log_debug("\tUSAGE: %X", path_item->usage); 175 usb_log_debug("\tFLAGS: %d", path_item->flags); 184 176 } 185 177 } … … 199 191 usb_hid_report_usage_path_t *report_item; 200 192 usb_hid_report_usage_path_t *path_item; 201 193 202 194 link_t *report_link; 203 195 link_t *path_link; 204 196 205 197 int only_page; 206 198 207 199 if (report_path->report_id != path->report_id) { 208 200 if (path->report_id != 0) { … … 210 202 } 211 203 } 212 204 213 205 // Empty path match all others 214 206 if (path->depth == 0) { 215 207 return 0; 216 208 } 217 209 218 210 if ((only_page = flags & USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY) != 0) { 219 211 flags -= USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY; 220 212 } 221 213 222 214 switch (flags) { 223 215 /* Path is somewhere in report_path */ … … 226 218 return 1; 227 219 } 228 220 229 221 path_link = list_first(&path->items); 230 222 path_item = list_get_instance(path_link, 231 223 usb_hid_report_usage_path_t, rpath_items_link); 232 224 233 225 list_foreach(report_path->items, rpath_items_link, 234 226 usb_hid_report_usage_path_t, report_item) { 235 227 if (USB_HID_SAME_USAGE_PAGE(report_item->usage_page, 236 228 path_item->usage_page)) { 237 229 238 230 if (only_page == 0) { 239 231 if (USB_HID_SAME_USAGE(report_item->usage, … … 245 237 } 246 238 } 247 239 248 240 return 1; 249 241 break; 250 242 251 243 /* The paths must be identical */ 252 244 case USB_HID_PATH_COMPARE_STRICT: … … 255 247 } 256 248 /* Fallthrough */ 257 249 258 250 /* Path is prefix of the report_path */ 259 251 case USB_HID_PATH_COMPARE_BEGIN: 260 252 report_link = report_path->items.head.next; 261 253 path_link = path->items.head.next; 262 254 263 255 while ((report_link != &report_path->items.head) && 264 256 (path_link != &path->items.head)) { 265 257 266 258 report_item = list_get_instance(report_link, 267 259 usb_hid_report_usage_path_t, rpath_items_link); 268 260 269 261 path_item = list_get_instance(path_link, 270 262 usb_hid_report_usage_path_t, rpath_items_link); 271 263 272 264 if (!USB_HID_SAME_USAGE_PAGE(report_item->usage_page, 273 265 path_item->usage_page) || ((only_page == 0) && … … 280 272 } 281 273 } 282 274 283 275 if ((((flags & USB_HID_PATH_COMPARE_BEGIN) != 0) && 284 276 (path_link == &path->items.head)) || … … 290 282 } 291 283 break; 292 284 293 285 /* Path is suffix of report_path */ 294 286 case USB_HID_PATH_COMPARE_END: 295 287 report_link = report_path->items.head.prev; 296 288 path_link = path->items.head.prev; 297 289 298 290 if (list_empty(&path->items)) { 299 291 return 0; 300 292 } 301 293 302 294 while ((report_link != &report_path->items.head) && 303 295 (path_link != &path->items.head)) { 304 296 report_item = list_get_instance(report_link, 305 297 usb_hid_report_usage_path_t, rpath_items_link); 306 298 307 299 path_item = list_get_instance(path_link, 308 300 usb_hid_report_usage_path_t, rpath_items_link); 309 301 310 302 if (!USB_HID_SAME_USAGE_PAGE(report_item->usage_page, 311 303 path_item->usage_page) || ((only_page == 0) && … … 318 310 } 319 311 } 320 312 321 313 if (path_link == &path->items.head) { 322 314 return 0; … … 325 317 } 326 318 break; 327 319 328 320 default: 329 321 return -1; … … 340 332 usb_hid_report_path_t *path; 341 333 path = malloc(sizeof(usb_hid_report_path_t)); 342 if (path == NULL){334 if (path == NULL) { 343 335 return NULL; 344 336 } … … 363 355 if (path == NULL) 364 356 return; 365 while (!list_empty(&path->items)){357 while (!list_empty(&path->items)) { 366 358 usb_hid_report_remove_last_item(path); 367 359 } … … 379 371 */ 380 372 usb_hid_report_path_t *usb_hid_report_path_clone( 381 usb_hid_report_path_t *usage_path)373 usb_hid_report_path_t *usage_path) 382 374 { 383 375 usb_hid_report_usage_path_t *new_path_item; 384 376 usb_hid_report_path_t *new_usage_path = usb_hid_report_path (); 385 377 386 if (new_usage_path == NULL){378 if (new_usage_path == NULL) { 387 379 return NULL; 388 380 } 389 381 390 382 new_usage_path->report_id = usage_path->report_id; 391 392 if (list_empty(&usage_path->items)){383 384 if (list_empty(&usage_path->items)) { 393 385 return new_usage_path; 394 386 } … … 398 390 399 391 new_path_item = malloc(sizeof(usb_hid_report_usage_path_t)); 400 if (new_path_item == NULL) {392 if (new_path_item == NULL) { 401 393 return NULL; 402 394 } 403 395 404 396 link_initialize(&new_path_item->rpath_items_link); 405 397 new_path_item->usage_page = path_item->usage_page; 406 new_path_item->usage = path_item->usage; 407 new_path_item->flags = path_item->flags; 408 398 new_path_item->usage = path_item->usage; 399 new_path_item->flags = path_item->flags; 400 409 401 list_append(&new_path_item->rpath_items_link, 410 402 &new_usage_path->items); … … 423 415 * @return Error code 424 416 */ 425 errno_t usb_hid_report_path_set_report_id(usb_hid_report_path_t *path, 426 uint8_t report_id)427 { 428 if (path == NULL){417 errno_t usb_hid_report_path_set_report_id(usb_hid_report_path_t *path, 418 uint8_t report_id) 419 { 420 if (path == NULL) { 429 421 return EINVAL; 430 422 } -
uspace/lib/usbhid/src/hidreport.c
rf5e5f73 rdf6ded8 71 71 const uint8_t *d = 72 72 usb_dp_get_nested_descriptor(&parser, &parser_data, 73 usb_device_descriptors(dev)->full_config);73 usb_device_descriptors(dev)->full_config); 74 74 75 75 /* … … 84 84 85 85 if (d == NULL) { 86 usb_log_error("The %d. interface descriptor not found! \n",86 usb_log_error("The %d. interface descriptor not found!", 87 87 usb_device_get_iface_number(dev)); 88 88 return ENOENT; … … 104 104 105 105 if (d == NULL) { 106 usb_log_fatal("No HID descriptor found! \n");106 usb_log_fatal("No HID descriptor found!"); 107 107 return ENOENT; 108 108 } … … 130 130 } 131 131 132 usb_log_debug("Getting Report descriptor, expected size: %u \n", length);132 usb_log_debug("Getting Report descriptor, expected size: %u", length); 133 133 134 134 /* … … 156 156 *size = length; 157 157 158 usb_log_debug("Done. \n");158 usb_log_debug("Done."); 159 159 160 160 return EOK; … … 163 163 164 164 165 errno_t usb_hid_process_report_descriptor(usb_device_t *dev, 165 errno_t usb_hid_process_report_descriptor(usb_device_t *dev, 166 166 usb_hid_report_t *report, uint8_t **report_desc, size_t *report_size) 167 167 { … … 178 178 179 179 if (rc != EOK) { 180 usb_log_error("Problem with getting Report descriptor: %s. \n",180 usb_log_error("Problem with getting Report descriptor: %s.", 181 181 str_error(rc)); 182 182 if (*report_desc != NULL) { … … 191 191 rc = usb_hid_parse_report_descriptor(report, *report_desc, *report_size); 192 192 if (rc != EOK) { 193 usb_log_error("Problem parsing Report descriptor: %s. \n",193 usb_log_error("Problem parsing Report descriptor: %s.", 194 194 str_error(rc)); 195 195 free(*report_desc); -
uspace/lib/usbhid/src/hidreq.c
rf5e5f73 rdf6ded8 62 62 { 63 63 if (ctrl_pipe == NULL) { 64 usb_log_warning("usbhid_req_set_report(): no pipe given. \n");65 return EINVAL; 66 } 67 68 if (iface_no < 0) { 69 usb_log_warning("usbhid_req_set_report(): no interface given." 70 "\n"); 71 return EINVAL; 72 } 73 74 /* 75 * No need for checking other parameters, as they are checked in 76 * the called function (usb_control_request_set()). 77 */ 78 79 errno_t rc; 80 64 usb_log_warning("usbhid_req_set_report(): no pipe given."); 65 return EINVAL; 66 } 67 68 if (iface_no < 0) { 69 usb_log_warning("usbhid_req_set_report(): no interface given." 70 "\n"); 71 return EINVAL; 72 } 73 74 /* 75 * No need for checking other parameters, as they are checked in 76 * the called function (usb_control_request_set()). 77 */ 78 79 errno_t rc; 80 81 81 uint16_t value = 0; 82 82 value |= (type << 8); 83 83 84 usb_log_debug("Sending Set Report request to the device. \n");85 84 usb_log_debug("Sending Set Report request to the device."); 85 86 86 rc = usb_control_request_set(ctrl_pipe, 87 87 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, … … 93 93 return rc; 94 94 } 95 95 96 96 return EOK; 97 97 } … … 112 112 { 113 113 if (ctrl_pipe == NULL) { 114 usb_log_warning("usbhid_req_set_report(): no pipe given. \n");115 return EINVAL; 116 } 117 118 if (iface_no < 0) { 119 usb_log_warning("usbhid_req_set_report(): no interface given." 120 "\n"); 121 return EINVAL; 122 } 123 124 /* 125 * No need for checking other parameters, as they are checked in 126 * the called function (usb_control_request_set()). 127 */ 128 114 usb_log_warning("usbhid_req_set_report(): no pipe given."); 115 return EINVAL; 116 } 117 118 if (iface_no < 0) { 119 usb_log_warning("usbhid_req_set_report(): no interface given." 120 "\n"); 121 return EINVAL; 122 } 123 124 /* 125 * No need for checking other parameters, as they are checked in 126 * the called function (usb_control_request_set()). 127 */ 128 129 129 errno_t rc; 130 130 131 131 usb_log_debug("Sending Set Protocol request to the device (" 132 132 "protocol: %d, iface: %d).\n", protocol, iface_no); 133 134 rc = usb_control_request_set(ctrl_pipe, 135 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 133 134 rc = usb_control_request_set(ctrl_pipe, 135 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 136 136 USB_HIDREQ_SET_PROTOCOL, protocol, iface_no, NULL, 0); 137 137 … … 141 141 return rc; 142 142 } 143 143 144 144 return EOK; 145 145 } … … 160 160 { 161 161 if (ctrl_pipe == NULL) { 162 usb_log_warning("usbhid_req_set_report(): no pipe given. \n");163 return EINVAL; 164 } 165 166 if (iface_no < 0) { 167 usb_log_warning("usbhid_req_set_report(): no interface given." 168 "\n"); 169 return EINVAL; 170 } 171 172 /* 173 * No need for checking other parameters, as they are checked in 174 * the called function (usb_control_request_set()). 175 */ 176 162 usb_log_warning("usbhid_req_set_report(): no pipe given."); 163 return EINVAL; 164 } 165 166 if (iface_no < 0) { 167 usb_log_warning("usbhid_req_set_report(): no interface given." 168 "\n"); 169 return EINVAL; 170 } 171 172 /* 173 * No need for checking other parameters, as they are checked in 174 * the called function (usb_control_request_set()). 175 */ 176 177 177 errno_t rc; 178 178 179 179 usb_log_debug("Sending Set Idle request to the device (" 180 180 "duration: %u, iface: %d).\n", duration, iface_no); 181 181 182 182 uint16_t value = duration << 8; 183 183 184 184 rc = usb_control_request_set(ctrl_pipe, 185 185 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, … … 191 191 return rc; 192 192 } 193 193 194 194 return EOK; 195 195 } … … 203 203 * @param[in][out] buffer Buffer for the report data. 204 204 * @param[in] buf_size Size of the buffer (in bytes). 205 * @param[out] actual_size Actual size of report received from the device 205 * @param[out] actual_size Actual size of report received from the device 206 206 * (in bytes). 207 207 * … … 210 210 * @return Other value inherited from function usb_control_request_set(). 211 211 */ 212 errno_t usbhid_req_get_report(usb_pipe_t *ctrl_pipe, int iface_no, 213 usb_hid_report_type_t type, uint8_t *buffer, size_t buf_size, 212 errno_t usbhid_req_get_report(usb_pipe_t *ctrl_pipe, int iface_no, 213 usb_hid_report_type_t type, uint8_t *buffer, size_t buf_size, 214 214 size_t *actual_size) 215 215 { 216 216 if (ctrl_pipe == NULL) { 217 usb_log_warning("usbhid_req_set_report(): no pipe given. \n");218 return EINVAL; 219 } 220 221 if (iface_no < 0) { 222 usb_log_warning("usbhid_req_set_report(): no interface given." 223 "\n"); 224 return EINVAL; 225 } 226 227 /* 228 * No need for checking other parameters, as they are checked in 229 * the called function (usb_control_request_set()). 230 */ 231 217 usb_log_warning("usbhid_req_set_report(): no pipe given."); 218 return EINVAL; 219 } 220 221 if (iface_no < 0) { 222 usb_log_warning("usbhid_req_set_report(): no interface given." 223 "\n"); 224 return EINVAL; 225 } 226 227 /* 228 * No need for checking other parameters, as they are checked in 229 * the called function (usb_control_request_set()). 230 */ 231 232 232 errno_t rc; 233 233 234 234 uint16_t value = 0; 235 235 value |= (type << 8); 236 237 usb_log_debug("Sending Get Report request to the device. \n");238 239 rc = usb_control_request_get(ctrl_pipe, 240 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 236 237 usb_log_debug("Sending Get Report request to the device."); 238 239 rc = usb_control_request_get(ctrl_pipe, 240 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 241 241 USB_HIDREQ_GET_REPORT, value, iface_no, buffer, buf_size, 242 242 actual_size); … … 247 247 return rc; 248 248 } 249 249 250 250 return EOK; 251 251 } … … 262 262 * @return Other value inherited from function usb_control_request_set(). 263 263 */ 264 errno_t usbhid_req_get_protocol(usb_pipe_t *ctrl_pipe, int iface_no, 264 errno_t usbhid_req_get_protocol(usb_pipe_t *ctrl_pipe, int iface_no, 265 265 usb_hid_protocol_t *protocol) 266 266 { 267 267 if (ctrl_pipe == NULL) { 268 usb_log_warning("usbhid_req_set_report(): no pipe given. \n");269 return EINVAL; 270 } 271 272 if (iface_no < 0) { 273 usb_log_warning("usbhid_req_set_report(): no interface given." 274 "\n"); 275 return EINVAL; 276 } 277 278 /* 279 * No need for checking other parameters, as they are checked in 280 * the called function (usb_control_request_set()). 281 */ 282 283 errno_t rc; 268 usb_log_warning("usbhid_req_set_report(): no pipe given."); 269 return EINVAL; 270 } 271 272 if (iface_no < 0) { 273 usb_log_warning("usbhid_req_set_report(): no interface given." 274 "\n"); 275 return EINVAL; 276 } 277 278 /* 279 * No need for checking other parameters, as they are checked in 280 * the called function (usb_control_request_set()). 281 */ 282 283 errno_t rc; 284 284 285 285 usb_log_debug("Sending Get Protocol request to the device (" 286 286 "iface: %d).\n", iface_no); 287 287 288 288 uint8_t buffer[1]; 289 289 size_t actual_size = 0; 290 291 rc = usb_control_request_get(ctrl_pipe, 292 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 290 291 rc = usb_control_request_get(ctrl_pipe, 292 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 293 293 USB_HIDREQ_GET_PROTOCOL, 0, iface_no, buffer, 1, &actual_size); 294 294 … … 298 298 return rc; 299 299 } 300 300 301 301 if (actual_size != 1) { 302 usb_log_warning("Wrong data size: %zu, expected: 1. \n",303 actual_size);302 usb_log_warning("Wrong data size: %zu, expected: 1.", 303 actual_size); 304 304 return ELIMIT; 305 305 } 306 306 307 307 *protocol = buffer[0]; 308 308 309 309 return EOK; 310 310 } … … 320 320 * @retval EOK if successful. 321 321 * @retval EINVAL if no HID device is given. 322 * @return Other value inherited from one of functions 322 * @return Other value inherited from one of functions 323 323 * usb_pipe_start_session(), usb_pipe_end_session(), 324 324 * usb_control_request_set(). 325 325 */ 326 errno_t usbhid_req_get_idle(usb_pipe_t *ctrl_pipe, int iface_no, uint8_t *duration) 327 { 328 if (ctrl_pipe == NULL) { 329 usb_log_warning("usbhid_req_set_report(): no pipe given.\n"); 330 return EINVAL; 331 } 332 333 if (iface_no < 0) { 334 usb_log_warning("usbhid_req_set_report(): no interface given." 335 "\n"); 336 return EINVAL; 337 } 338 339 /* 340 * No need for checking other parameters, as they are checked in 341 * the called function (usb_control_request_set()). 342 */ 343 326 errno_t usbhid_req_get_idle(usb_pipe_t *ctrl_pipe, int iface_no, 327 uint8_t *duration) 328 { 329 if (ctrl_pipe == NULL) { 330 usb_log_warning("usbhid_req_set_report(): no pipe given."); 331 return EINVAL; 332 } 333 334 if (iface_no < 0) { 335 usb_log_warning("usbhid_req_set_report(): no interface given." 336 "\n"); 337 return EINVAL; 338 } 339 340 /* 341 * No need for checking other parameters, as they are checked in 342 * the called function (usb_control_request_set()). 343 */ 344 344 345 errno_t rc; 345 346 346 347 usb_log_debug("Sending Get Idle request to the device (" 347 348 "iface: %d).\n", iface_no); 348 349 349 350 uint16_t value = 0; 350 351 uint8_t buffer[1]; 351 352 size_t actual_size = 0; 352 353 rc = usb_control_request_get(ctrl_pipe, 354 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 355 USB_HIDREQ_GET_IDLE, value, iface_no, buffer, 1, 353 354 rc = usb_control_request_get(ctrl_pipe, 355 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 356 USB_HIDREQ_GET_IDLE, value, iface_no, buffer, 1, 356 357 &actual_size); 357 358 … … 361 362 return rc; 362 363 } 363 364 364 365 if (actual_size != 1) { 365 usb_log_warning("Wrong data size: %zu, expected: 1. \n",366 actual_size);366 usb_log_warning("Wrong data size: %zu, expected: 1.", 367 actual_size); 367 368 return ELIMIT; 368 369 } 369 370 370 371 *duration = buffer[0]; 371 372 372 373 return EOK; 373 374 } -
uspace/lib/usbhost/Makefile
rf5e5f73 rdf6ded8 37 37 src/endpoint.c \ 38 38 src/hcd.c \ 39 src/usb_bus.c \ 39 src/bus.c \ 40 src/usb2_bus.c \ 41 src/bandwidth.c \ 42 src/utility.c \ 40 43 src/usb_transfer_batch.c 41 44 -
uspace/lib/usbhost/include/usb/host/ddf_helpers.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2012 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 37 38 #define LIBUSBHOST_HOST_DDF_HELPERS_H 38 39 39 #include < usb/host/hcd.h>40 #include < usb/host/usb_bus.h>40 #include <ddf/driver.h> 41 #include <ddf/interrupt.h> 41 42 #include <usb/usb.h> 42 43 43 #include <ddf/driver.h> 44 #include <ddf/interrupt.h> 45 #include <device/hw_res_parsed.h> 44 #include <usb/host/hcd.h> 45 #include <usb/descriptor.h> 46 46 47 typedef errno_t (*driver_init_t)(hcd_t *, const hw_res_list_parsed_t *, bool);48 typedef void (*driver_fini_t)(hcd_t *);49 typedef errno_t (*claim_t)(ddf_dev_t *);50 typedef errno_t (*irq_code_gen_t)(irq_code_t *, const hw_res_list_parsed_t *, int *);51 47 52 typedef struct { 53 hcd_ops_t ops; 54 claim_t claim; 55 usb_speed_t hc_speed; 56 driver_init_t init; 57 driver_fini_t fini; 58 interrupt_handler_t *irq_handler; 59 irq_code_gen_t irq_code_gen; 60 const char *name; 61 } ddf_hc_driver_t; 48 errno_t hcd_ddf_setup_hc(ddf_dev_t *, size_t); 49 void hcd_ddf_clean_hc(hc_device_t *); 62 50 63 errno_t hcd_ddf_add_hc(ddf_dev_t *device, const ddf_hc_driver_t *driver);64 51 65 errno_t hcd_ddf_setup_hc(ddf_dev_t *device, usb_speed_t max_speed, 66 size_t bw, bw_count_func_t bw_count); 67 void hcd_ddf_clean_hc(ddf_dev_t *device); 68 errno_t hcd_ddf_setup_root_hub(ddf_dev_t *device); 52 device_t *hcd_ddf_fun_create(hc_device_t *, usb_speed_t); 53 void hcd_ddf_fun_destroy(device_t *); 69 54 70 hcd_t *dev_to_hcd(ddf_dev_t *dev);55 errno_t hcd_ddf_setup_match_ids(device_t *, usb_standard_device_descriptor_t *); 71 56 72 errno_t hcd_ddf_enable_interrupt(ddf_dev_t *device, int); 73 errno_t hcd_ddf_get_registers(ddf_dev_t *device, hw_res_list_parsed_t *hw_res); 74 errno_t hcd_ddf_setup_interrupts(ddf_dev_t *device, 75 const hw_res_list_parsed_t *hw_res, 76 interrupt_handler_t handler, 77 errno_t (*gen_irq_code)(irq_code_t *, const hw_res_list_parsed_t *, int *), 78 cap_handle_t *handle); 79 void ddf_hcd_gen_irq_handler(ipc_call_t *call, ddf_dev_t *dev); 57 errno_t hcd_ddf_enable_interrupt(hc_device_t *hcd, int); 58 errno_t hcd_ddf_get_registers(hc_device_t *hcd, hw_res_list_parsed_t *hw_res); 59 60 void hcd_ddf_gen_irq_handler(ipc_callid_t iid, ipc_call_t *call, ddf_dev_t *dev); 80 61 81 62 #endif -
uspace/lib/usbhost/include/usb/host/endpoint.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 32 33 /** @file 33 34 * 35 * Endpoint structure is tightly coupled to the bus. The bus controls the 36 * life-cycle of endpoint. In order to keep endpoints lightweight, operations 37 * on endpoints are part of the bus structure. 38 * 34 39 */ 35 40 #ifndef LIBUSBHOST_HOST_ENDPOINT_H 36 41 #define LIBUSBHOST_HOST_ENDPOINT_H 37 42 43 #include <adt/list.h> 44 #include <atomic.h> 45 #include <fibril_synch.h> 38 46 #include <stdbool.h> 39 #include <adt/list.h> 40 #include <fibril_synch.h> 47 #include <sys/time.h> 41 48 #include <usb/usb.h> 42 #include <atomic.h> 49 #include <usb/host/bus.h> 50 #include <usbhc_iface.h> 43 51 44 /** Host controller side endpoint structure. */ 52 typedef struct bus bus_t; 53 typedef struct device device_t; 54 typedef struct transfer_request transfer_request_t; 55 typedef struct usb_transfer_batch usb_transfer_batch_t; 56 57 /** 58 * Host controller side endpoint structure. 59 * 60 * This structure, though reference-counted, is very fragile. It is responsible 61 * for synchronizing transfer batch scheduling and completion. 62 * 63 * To avoid situations, in which two locks must be obtained to schedule/finish 64 * a transfer, the endpoint inherits a lock from the outside. Because the 65 * concrete instance of mutex can be unknown at the time of initialization, 66 * the HC shall pass the right lock at the time of onlining the endpoint. 67 * 68 * The fields used for scheduling (online, active_batch) are to be used only 69 * under that guard and by functions designed for this purpose. The driver can 70 * also completely avoid using this mechanism, in which case it is on its own in 71 * question of transfer aborting. 72 * 73 * Relevant information can be found in the documentation of HelenOS xHCI 74 * project. 75 */ 45 76 typedef struct endpoint { 77 /** USB device */ 78 device_t *device; 46 79 /** Reference count. */ 47 atomic_t refcnt; 48 /** Part of linked list. */ 49 link_t link; 50 /** USB address. */ 51 usb_address_t address; 52 /** USB endpoint number. */ 80 atomic_t refcnt; 81 82 /** An inherited guard */ 83 fibril_mutex_t *guard; 84 /** Whether it's allowed to schedule on this endpoint */ 85 bool online; 86 /** The currently active transfer batch. */ 87 usb_transfer_batch_t *active_batch; 88 /** Signals change of active status. */ 89 fibril_condvar_t avail; 90 91 /** Endpoint number */ 53 92 usb_endpoint_t endpoint; 54 93 /** Communication direction. */ … … 56 95 /** USB transfer type. */ 57 96 usb_transfer_type_t transfer_type; 58 /** Communication speed. */ 59 usb_speed_t speed; 60 /** Maximum size of data packets. */ 97 /** Maximum size of one packet */ 61 98 size_t max_packet_size; 62 /** Additional opportunities per uframe */ 63 unsigned packets; 64 /** Necessary bandwidth. */ 65 size_t bandwidth; 66 /** Value of the toggle bit. */ 67 unsigned toggle:1; 68 /** True if there is a batch using this scheduled for this endpoint. */ 69 volatile bool active; 70 /** Protects resources and active status changes. */ 71 fibril_mutex_t guard; 72 /** Signals change of active status. */ 73 fibril_condvar_t avail; 74 /** High speed TT data */ 75 struct { 76 usb_address_t address; 77 unsigned port; 78 } tt; 79 /** Optional device specific data. */ 80 struct { 81 /** Device specific data. */ 82 void *data; 83 /** Callback to get the value of toggle bit. */ 84 int (*toggle_get)(void *); 85 /** Callback to set the value of toggle bit. */ 86 void (*toggle_set)(void *, int); 87 } hc_data; 99 100 /** Maximum size of one transfer */ 101 size_t max_transfer_size; 102 103 /* Policies for transfer buffers */ 104 /** A hint for optimal performance. */ 105 dma_policy_t transfer_buffer_policy; 106 /** Enforced by the library. */ 107 dma_policy_t required_transfer_buffer_policy; 108 109 /** 110 * Number of packets that can be sent in one service interval 111 * (not necessarily uframe, despite its name) 112 */ 113 unsigned packets_per_uframe; 114 115 /* This structure is meant to be extended by overriding. */ 88 116 } endpoint_t; 89 117 90 extern endpoint_t *endpoint_create(usb_address_t, usb_endpoint_t, 91 usb_direction_t, usb_transfer_type_t, usb_speed_t, size_t, unsigned int, 92 size_t, usb_address_t, unsigned int); 93 extern void endpoint_destroy(endpoint_t *); 118 extern void endpoint_init(endpoint_t *, device_t *, 119 const usb_endpoint_descriptors_t *); 94 120 95 121 extern void endpoint_add_ref(endpoint_t *); 96 122 extern void endpoint_del_ref(endpoint_t *); 97 123 98 extern void endpoint_set_hc_data(endpoint_t *, void *, int (*)(void *), 99 void (*)(void *, int)); 100 extern void endpoint_clear_hc_data(endpoint_t *); 124 extern void endpoint_set_online(endpoint_t *, fibril_mutex_t *); 125 extern void endpoint_set_offline_locked(endpoint_t *); 101 126 102 extern void endpoint_use(endpoint_t *); 103 extern void endpoint_release(endpoint_t *); 127 extern void endpoint_wait_timeout_locked(endpoint_t *ep, suseconds_t); 128 extern int endpoint_activate_locked(endpoint_t *, usb_transfer_batch_t *); 129 extern void endpoint_deactivate_locked(endpoint_t *); 104 130 105 extern int endpoint_toggle_get(endpoint_t *); 106 extern void endpoint_toggle_set(endpoint_t *, int); 131 int endpoint_send_batch(endpoint_t *, const transfer_request_t *); 107 132 108 /** list_get_instance wrapper. 109 * 110 * @param item Pointer to link member. 111 * 112 * @return Pointer to endpoint_t structure. 113 * 114 */ 115 static inline endpoint_t * endpoint_get_instance(link_t *item) 133 static inline bus_t *endpoint_get_bus(endpoint_t *ep) 116 134 { 117 return item ? list_get_instance(item, endpoint_t, link) : NULL; 135 device_t * const device = ep->device; 136 return device ? device->bus : NULL; 118 137 } 138 119 139 #endif 120 140 -
uspace/lib/usbhost/include/usb/host/hcd.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 37 38 #define LIBUSBHOST_HOST_HCD_H 38 39 39 #include <usb/host/endpoint.h> 40 #include <usb/host/usb_bus.h> 41 #include <usb/host/usb_transfer_batch.h> 42 #include <usb/usb.h> 40 #include <ddf/driver.h> 41 #include <usb/request.h> 43 42 44 #include <assert.h> 45 #include <usbhc_iface.h> 46 #include <stddef.h> 47 #include <stdint.h> 43 typedef struct hw_resource_list_parsed hw_res_list_parsed_t; 44 typedef struct bus bus_t; 45 typedef struct device device_t; 48 46 49 typedef struct hcd hcd_t; 47 /* Treat this header as read-only in driver code. 48 * It could be opaque, but why to complicate matters. 49 */ 50 typedef struct hc_device { 51 /* Bus instance */ 52 bus_t *bus; 50 53 51 typedef errno_t (*schedule_hook_t)(hcd_t *, usb_transfer_batch_t *); 52 typedef errno_t (*ep_add_hook_t)(hcd_t *, endpoint_t *); 53 typedef void (*ep_remove_hook_t)(hcd_t *, endpoint_t *); 54 typedef void (*interrupt_hook_t)(hcd_t *, uint32_t); 55 typedef errno_t (*status_hook_t)(hcd_t *, uint32_t *); 54 /* Managed DDF device */ 55 ddf_dev_t *ddf_dev; 56 56 57 typedef struct { 58 /** Transfer scheduling, implement in device driver. */ 59 schedule_hook_t schedule; 60 /** Hook called upon registering new endpoint. */ 61 ep_add_hook_t ep_add_hook; 62 /** Hook called upon removing of an endpoint. */ 63 ep_remove_hook_t ep_remove_hook; 64 /** Hook to be called on device interrupt, passes ARG1 */ 65 interrupt_hook_t irq_hook; 66 /** Periodic polling hook */ 67 status_hook_t status_hook; 68 } hcd_ops_t; 57 /* Control function */ 58 ddf_fun_t *ctl_fun; 69 59 70 /** Generic host controller driver structure. */ 71 struct hcd { 72 /** Endpoint manager. */ 73 usb_bus_t bus; 60 /* Result of enabling HW IRQs */ 61 int irq_cap; 74 62 75 63 /** Interrupt replacement fibril */ 76 64 fid_t polling_fibril; 77 65 78 /** Driver implementation */ 79 hcd_ops_t ops; 80 /** Device specific driver data. */ 81 void * driver_data; 82 }; 66 /* This structure is meant to be extended by driver code. */ 67 } hc_device_t; 83 68 84 extern void hcd_init(hcd_t *, usb_speed_t, size_t, bw_count_func_t); 69 typedef struct hc_driver { 70 const char *name; 85 71 86 static inline void hcd_set_implementation(hcd_t *hcd, void *data, 87 const hcd_ops_t *ops) 72 /** Size of the device data to be allocated, and passed as the 73 * hc_device_t. */ 74 size_t hc_device_size; 75 76 /** Initialize device structures. */ 77 int (*hc_add)(hc_device_t *, const hw_res_list_parsed_t *); 78 79 /** Generate IRQ code to handle interrupts. */ 80 int (*irq_code_gen)(irq_code_t *, hc_device_t *, 81 const hw_res_list_parsed_t *, int *); 82 83 /** Claim device from BIOS. */ 84 int (*claim)(hc_device_t *); 85 86 /** Start the host controller. */ 87 int (*start)(hc_device_t *); 88 89 /** Setup the virtual roothub. */ 90 int (*setup_root_hub)(hc_device_t *); 91 92 /** Stop the host controller (after start has been called) */ 93 int (*stop)(hc_device_t *); 94 95 /** HC was asked to be removed (after hc_add has been called) */ 96 int (*hc_remove)(hc_device_t *); 97 98 /** HC is gone. */ 99 int (*hc_gone)(hc_device_t *); 100 } hc_driver_t; 101 102 /* Drivers should call this before leaving hc_add */ 103 static inline void hc_device_setup(hc_device_t *hcd, bus_t *bus) 88 104 { 89 assert(hcd); 90 if (ops) { 91 hcd->driver_data = data; 92 hcd->ops = *ops; 93 } else { 94 memset(&hcd->ops, 0, sizeof(hcd->ops)); 95 } 105 hcd->bus = bus; 96 106 } 97 107 98 static inline void * hcd_get_driver_data(hcd_t *hcd)108 static inline hc_device_t *dev_to_hcd(ddf_dev_t *dev) 99 109 { 100 assert(hcd); 101 return hcd->driver_data; 110 return ddf_dev_data_get(dev); 102 111 } 103 112 104 extern errno_t hcd_request_address(hcd_t *, usb_speed_t, usb_address_t *); 105 106 extern errno_t hcd_release_address(hcd_t *, usb_address_t); 107 108 extern errno_t hcd_reserve_default_address(hcd_t *, usb_speed_t); 109 110 static inline errno_t hcd_release_default_address(hcd_t *hcd) 111 { 112 return hcd_release_address(hcd, USB_ADDRESS_DEFAULT); 113 } 114 115 extern errno_t hcd_add_ep(hcd_t *, usb_target_t, usb_direction_t, 116 usb_transfer_type_t, size_t, unsigned int, size_t, usb_address_t, 117 unsigned int); 118 119 extern errno_t hcd_remove_ep(hcd_t *, usb_target_t, usb_direction_t); 120 121 extern errno_t hcd_send_batch(hcd_t *, usb_target_t, usb_direction_t, void *, 122 size_t, uint64_t, usbhc_iface_transfer_in_callback_t, 123 usbhc_iface_transfer_out_callback_t, void *, const char *); 124 125 extern errno_t hcd_send_batch_sync(hcd_t *, usb_target_t, usb_direction_t, 126 void *, size_t, uint64_t, const char *, size_t *); 113 extern errno_t hc_driver_main(const hc_driver_t *); 127 114 128 115 #endif -
uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 37 38 #define LIBUSBHOST_HOST_USB_TRANSFER_BATCH_H 38 39 39 #include <usb/host/endpoint.h> 40 #include <usb/usb.h> 41 42 #include <assert.h> 40 #include <atomic.h> 41 #include <errno.h> 43 42 #include <stddef.h> 44 43 #include <stdint.h> 44 #include <usb/dma_buffer.h> 45 #include <usb/request.h> 46 #include <usb/usb.h> 45 47 #include <usbhc_iface.h> 46 48 47 #define USB_SETUP_PACKET_SIZE 8 49 #include <usb/host/hcd.h> 50 #include <usb/host/endpoint.h> 51 #include <usb/host/bus.h> 52 53 typedef struct endpoint endpoint_t; 54 typedef struct bus bus_t; 48 55 49 56 /** Structure stores additional data needed for communication with EP */ 50 57 typedef struct usb_transfer_batch { 58 /** Target for communication */ 59 usb_target_t target; 60 /** Direction of the transfer */ 61 usb_direction_t dir; 62 51 63 /** Endpoint used for communication */ 52 64 endpoint_t *ep; 53 /** Function called on completion (IN version) */ 54 usbhc_iface_transfer_in_callback_t callback_in; 55 /** Function called on completion (OUT version) */ 56 usbhc_iface_transfer_out_callback_t callback_out; 57 /** Argument to pass to the completion function */ 58 void *arg; 59 /** Place for data to send/receive */ 60 char *buffer; 61 /** Size of memory pointed to by buffer member */ 62 size_t buffer_size; 65 63 66 /** Place to store SETUP data needed by control transfers */ 64 char setup_buffer[USB_SETUP_PACKET_SIZE]; 65 /** Used portion of setup_buffer member 66 * 67 * SETUP buffer must be 8 bytes for control transfers and is left 68 * unused for all other transfers. Thus, this field is either 0 or 8. 67 union { 68 char buffer [USB_SETUP_PACKET_SIZE]; 69 usb_device_request_setup_packet_t packet; 70 uint64_t packed; 71 } setup; 72 73 /** DMA buffer with enforced policy */ 74 dma_buffer_t dma_buffer; 75 /** Size of memory buffer */ 76 size_t offset, size; 77 78 /** 79 * In case a bounce buffer is allocated, the original buffer must to be 80 * stored to be filled after the IN transaction is finished. 69 81 */ 70 size_t setup_size; 82 char *original_buffer; 83 bool is_bounced; 71 84 72 /** Actually used portion of the buffer 73 * This member is never accessed by functions provided in this header, 74 * with the exception of usb_transfer_batch_finish. For external use. 75 */ 76 size_t transfered_size; 77 /** Indicates success/failure of the communication 78 * This member is never accessed by functions provided in this header, 79 * with the exception of usb_transfer_batch_finish. For external use. 80 */ 85 /** Indicates success/failure of the communication */ 81 86 errno_t error; 87 /** Actually used portion of the buffer */ 88 size_t transferred_size; 89 90 /** Function called on completion */ 91 usbhc_iface_transfer_callback_t on_complete; 92 /** Arbitrary data for the handler */ 93 void *on_complete_data; 82 94 } usb_transfer_batch_t; 83 95 84 /** Printf formatting string for dumping usb_transfer_batch_t. */ 96 /** 97 * Printf formatting string for dumping usb_transfer_batch_t. 98 * [address:endpoint speed transfer_type-direction buffer_sizeB/max_packet_size] 99 * */ 85 100 #define USB_TRANSFER_BATCH_FMT "[%d:%d %s %s-%s %zuB/%zu]" 86 101 … … 89 104 */ 90 105 #define USB_TRANSFER_BATCH_ARGS(batch) \ 91 ( batch).ep->address, (batch).ep->endpoint, \92 usb_str_speed((batch).ep-> speed), \106 ((batch).ep->device->address), ((batch).ep->endpoint), \ 107 usb_str_speed((batch).ep->device->speed), \ 93 108 usb_str_transfer_type_short((batch).ep->transfer_type), \ 94 usb_str_direction((batch). ep->direction), \95 (batch). buffer_size, (batch).ep->max_packet_size109 usb_str_direction((batch).dir), \ 110 (batch).size, (batch).ep->max_packet_size 96 111 112 /** Wrapper for bus operation. */ 113 usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *); 97 114 98 usb_transfer_batch_t * usb_transfer_batch_create( 99 endpoint_t *ep, 100 char *buffer, 101 size_t buffer_size, 102 uint64_t setup_buffer, 103 usbhc_iface_transfer_in_callback_t func_in, 104 usbhc_iface_transfer_out_callback_t func_out, 105 void *arg 106 ); 107 void usb_transfer_batch_destroy(usb_transfer_batch_t *instance); 115 /** Batch initializer. */ 116 void usb_transfer_batch_init(usb_transfer_batch_t *, endpoint_t *); 108 117 109 void usb_transfer_batch_finish_error(const usb_transfer_batch_t *instance, 110 const void* data, size_t size, errno_t error); 118 /** Buffer handling */ 119 bool usb_transfer_batch_bounce_required(usb_transfer_batch_t *); 120 errno_t usb_transfer_batch_bounce(usb_transfer_batch_t *); 111 121 112 /** Finish batch using stored error value and transferred size. 113 * 114 * @param[in] instance Batch structure to use. 115 * @param[in] data Data to copy to the output buffer. 122 /** Batch finalization. */ 123 void usb_transfer_batch_finish(usb_transfer_batch_t *); 124 125 /** To be called from outside only when the transfer is not going to be finished 126 * (i.o.w. until successfuly scheduling) 116 127 */ 117 static inline void usb_transfer_batch_finish( 118 const usb_transfer_batch_t *instance, const void* data) 119 { 120 assert(instance); 121 usb_transfer_batch_finish_error( 122 instance, data, instance->transfered_size, instance->error); 123 } 124 125 /** Determine batch direction based on the callbacks present 126 * @param[in] instance Batch structure to use, non-null. 127 * @return USB_DIRECTION_IN, or USB_DIRECTION_OUT. 128 */ 129 static inline usb_direction_t usb_transfer_batch_direction( 130 const usb_transfer_batch_t *instance) 131 { 132 assert(instance); 133 if (instance->callback_in) { 134 assert(instance->callback_out == NULL); 135 assert(instance->ep == NULL 136 || instance->ep->transfer_type == USB_TRANSFER_CONTROL 137 || instance->ep->direction == USB_DIRECTION_IN); 138 return USB_DIRECTION_IN; 139 } 140 if (instance->callback_out) { 141 assert(instance->callback_in == NULL); 142 assert(instance->ep == NULL 143 || instance->ep->transfer_type == USB_TRANSFER_CONTROL 144 || instance->ep->direction == USB_DIRECTION_OUT); 145 return USB_DIRECTION_OUT; 146 } 147 assert(false); 148 } 128 void usb_transfer_batch_destroy(usb_transfer_batch_t *); 149 129 150 130 #endif -
uspace/lib/usbhost/src/ddf_helpers.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2013 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty, Michal Staruch, Petr Manek 3 4 * All rights reserved. 4 5 * … … 31 32 */ 32 33 /** @file 33 * 34 */ 35 36 #include <usb/classes/classes.h> 37 #include <usb/debug.h> 38 #include <usb/descriptor.h> 39 #include <usb/request.h> 40 #include <usb/usb.h> 34 * Helpers to work with the DDF interface. 35 */ 41 36 42 37 #include <adt/list.h> … … 47 42 #include <device/hw_res_parsed.h> 48 43 #include <errno.h> 49 #include <fibril_synch.h>50 #include <macros.h>51 #include <stdio.h>52 #include <stdlib.h>53 44 #include <str_error.h> 45 #include <usb/classes/classes.h> 46 #include <usb/debug.h> 47 #include <usb/descriptor.h> 48 #include <usb/usb.h> 49 #include <usb/dma_buffer.h> 54 50 #include <usb_iface.h> 51 #include <usbhc_iface.h> 52 53 #include "bus.h" 54 #include "endpoint.h" 55 55 56 56 #include "ddf_helpers.h" 57 57 58 #define CTRL_PIPE_MIN_PACKET_SIZE 8 59 60 typedef struct usb_dev { 61 link_t link; 62 list_t devices; 63 fibril_mutex_t guard; 64 ddf_fun_t *fun; 65 usb_address_t address; 66 usb_speed_t speed; 67 usb_address_t tt_address; 68 unsigned port; 69 } usb_dev_t; 70 71 typedef struct hc_dev { 72 ddf_fun_t *ctl_fun; 73 hcd_t hcd; 74 usb_dev_t *root_hub; 75 } hc_dev_t; 76 77 static hc_dev_t *dev_to_hc_dev(ddf_dev_t *dev) 78 { 79 return ddf_dev_data_get(dev); 80 } 81 82 hcd_t *dev_to_hcd(ddf_dev_t *dev) 83 { 84 hc_dev_t *hc_dev = dev_to_hc_dev(dev); 85 if (!hc_dev) { 86 usb_log_error("Invalid HCD device.\n"); 87 return NULL; 88 } 89 return &hc_dev->hcd; 90 } 91 92 93 static errno_t hcd_ddf_new_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port); 94 static errno_t hcd_ddf_remove_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port); 95 96 97 /* DDF INTERFACE */ 98 99 /** Register endpoint interface function. 100 * @param fun DDF function. 101 * @param address USB address of the device. 102 * @param endpoint USB endpoint number to be registered. 103 * @param transfer_type Endpoint's transfer type. 104 * @param direction USB communication direction the endpoint is capable of. 105 * @param max_packet_size Maximu size of packets the endpoint accepts. 106 * @param interval Preferred timeout between communication. 58 /** 59 * DDF usbhc_iface callback. Passes the endpoint descriptors, fills the pipe 60 * descriptor according to the contents of the endpoint. 61 * 62 * @param[in] fun DDF function of the device in question. 63 * @param[out] pipe_desc The pipe descriptor to be filled. 64 * @param[in] endpoint_desc Endpoint descriptors from the device. 107 65 * @return Error code. 108 66 */ 109 static errno_t register_endpoint( 110 ddf_fun_t *fun, usb_endpoint_t endpoint, 111 usb_transfer_type_t transfer_type, usb_direction_t direction, 112 size_t max_packet_size, unsigned packets, unsigned interval) 113 { 114 assert(fun); 115 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 116 usb_dev_t *dev = ddf_fun_data_get(fun); 67 static errno_t register_endpoint(ddf_fun_t *fun, usb_pipe_desc_t *pipe_desc, 68 const usb_endpoint_descriptors_t *ep_desc) 69 { 70 assert(fun); 71 hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 72 device_t *dev = ddf_fun_data_get(fun); 117 73 assert(hcd); 74 assert(hcd->bus); 118 75 assert(dev); 119 const size_t size = max_packet_size; 120 const usb_target_t target = 121 {{.address = dev->address, .endpoint = endpoint}}; 122 123 usb_log_debug("Register endpoint %d:%d %s-%s %zuB %ums.\n", 124 dev->address, endpoint, usb_str_transfer_type(transfer_type), 125 usb_str_direction(direction), max_packet_size, interval); 126 127 return hcd_add_ep(hcd, target, direction, transfer_type, 128 max_packet_size, packets, size, dev->tt_address, dev->port); 129 } 130 131 /** Unregister endpoint interface function. 132 * @param fun DDF function. 133 * @param address USB address of the endpoint. 134 * @param endpoint USB endpoint number. 135 * @param direction Communication direction of the enpdoint to unregister. 76 77 endpoint_t *ep; 78 const int err = bus_endpoint_add(dev, ep_desc, &ep); 79 if (err) 80 return err; 81 82 if (pipe_desc) { 83 pipe_desc->endpoint_no = ep->endpoint; 84 pipe_desc->direction = ep->direction; 85 pipe_desc->transfer_type = ep->transfer_type; 86 pipe_desc->max_transfer_size = ep->max_transfer_size; 87 pipe_desc->transfer_buffer_policy = ep->transfer_buffer_policy; 88 } 89 endpoint_del_ref(ep); 90 91 return EOK; 92 } 93 94 /** 95 * DDF usbhc_iface callback. Unregister endpoint that makes the other end of 96 * the pipe described. 97 * 98 * @param fun DDF function of the device in question. 99 * @param pipe_desc Pipe description. 100 * @return Error code. 101 */ 102 static errno_t unregister_endpoint(ddf_fun_t *fun, const usb_pipe_desc_t *pipe_desc) 103 { 104 assert(fun); 105 hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 106 device_t *dev = ddf_fun_data_get(fun); 107 assert(hcd); 108 assert(hcd->bus); 109 assert(dev); 110 111 endpoint_t *ep = bus_find_endpoint(dev, pipe_desc->endpoint_no, pipe_desc->direction); 112 if (!ep) 113 return ENOENT; 114 115 const errno_t err = bus_endpoint_remove(ep); 116 117 endpoint_del_ref(ep); 118 return err; 119 } 120 121 /** 122 * DDF usbhc_iface callback. Calls the respective bus operation directly. 123 * 124 * @param fun DDF function of the device (hub) requesting the address. 125 */ 126 static errno_t default_address_reservation(ddf_fun_t *fun, bool reserve) 127 { 128 assert(fun); 129 hc_device_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 130 device_t *dev = ddf_fun_data_get(fun); 131 assert(hcd); 132 assert(hcd->bus); 133 assert(dev); 134 135 usb_log_debug("Device %d %s default address", dev->address, reserve ? "requested" : "releasing"); 136 if (reserve) { 137 return bus_reserve_default_address(hcd->bus, dev); 138 } else { 139 bus_release_default_address(hcd->bus, dev); 140 return EOK; 141 } 142 } 143 144 /** 145 * DDF usbhc_iface callback. Calls the bus operation directly. 146 * 147 * @param fun DDF function of the device (hub) requesting the address. 148 * @param speed USB speed of the new device 149 */ 150 static errno_t device_enumerate(ddf_fun_t *fun, unsigned port, usb_speed_t speed) 151 { 152 assert(fun); 153 ddf_dev_t *hc = ddf_fun_get_dev(fun); 154 assert(hc); 155 hc_device_t *hcd = dev_to_hcd(hc); 156 assert(hcd); 157 device_t *hub = ddf_fun_data_get(fun); 158 assert(hub); 159 160 errno_t err; 161 162 if (!usb_speed_is_valid(speed)) 163 return EINVAL; 164 165 usb_log_debug("Hub %d reported a new %s speed device on port: %u", 166 hub->address, usb_str_speed(speed), port); 167 168 device_t *dev = hcd_ddf_fun_create(hcd, speed); 169 if (!dev) { 170 usb_log_error("Failed to create USB device function."); 171 return ENOMEM; 172 } 173 174 dev->hub = hub; 175 dev->tier = hub->tier + 1; 176 dev->port = port; 177 dev->speed = speed; 178 179 if ((err = bus_device_enumerate(dev))) { 180 usb_log_error("Failed to initialize USB dev memory structures."); 181 goto err_usb_dev; 182 } 183 184 /* If the driver didn't name the dev when enumerating, 185 * do it in some generic way. 186 */ 187 if (!ddf_fun_get_name(dev->fun)) { 188 bus_device_set_default_name(dev); 189 } 190 191 if ((err = ddf_fun_bind(dev->fun))) { 192 usb_log_error("Device(%d): Failed to register: %s.", dev->address, str_error(err)); 193 goto err_usb_dev; 194 } 195 196 return EOK; 197 198 err_usb_dev: 199 hcd_ddf_fun_destroy(dev); 200 return err; 201 } 202 203 static errno_t device_remove(ddf_fun_t *fun, unsigned port) 204 { 205 assert(fun); 206 device_t *hub = ddf_fun_data_get(fun); 207 assert(hub); 208 usb_log_debug("Hub `%s' reported removal of device on port %u", 209 ddf_fun_get_name(fun), port); 210 211 device_t *victim = NULL; 212 213 fibril_mutex_lock(&hub->guard); 214 list_foreach(hub->devices, link, device_t, it) { 215 if (it->port == port) { 216 victim = it; 217 break; 218 } 219 } 220 fibril_mutex_unlock(&hub->guard); 221 222 if (!victim) { 223 usb_log_warning("Hub '%s' tried to remove non-existent" 224 " device.", ddf_fun_get_name(fun)); 225 return ENOENT; 226 } 227 228 assert(victim->fun); 229 assert(victim->port == port); 230 assert(victim->hub == hub); 231 232 bus_device_gone(victim); 233 return EOK; 234 } 235 236 /** 237 * Gets description of the device that is calling. 238 * 239 * @param[in] fun Device function. 240 * @param[out] desc Device descriptor to be filled. 136 241 * @return Error code. 137 242 */ 138 static errno_t unregister_endpoint( 139 ddf_fun_t *fun, usb_endpoint_t endpoint, usb_direction_t direction) 140 { 141 assert(fun); 142 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 143 usb_dev_t *dev = ddf_fun_data_get(fun); 144 assert(hcd); 243 static errno_t get_device_description(ddf_fun_t *fun, usb_device_desc_t *desc) 244 { 245 assert(fun); 246 device_t *dev = ddf_fun_data_get(fun); 145 247 assert(dev); 146 const usb_target_t target = 147 {{.address = dev->address, .endpoint = endpoint}}; 148 usb_log_debug("Unregister endpoint %d:%d %s.\n", 149 dev->address, endpoint, usb_str_direction(direction)); 150 return hcd_remove_ep(hcd, target, direction); 151 } 152 153 static errno_t reserve_default_address(ddf_fun_t *fun, usb_speed_t speed) 154 { 155 assert(fun); 156 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 157 usb_dev_t *dev = ddf_fun_data_get(fun); 158 assert(hcd); 159 assert(dev); 160 161 usb_log_debug("Device %d requested default address at %s speed\n", 162 dev->address, usb_str_speed(speed)); 163 return hcd_reserve_default_address(hcd, speed); 164 } 165 166 static errno_t release_default_address(ddf_fun_t *fun) 167 { 168 assert(fun); 169 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 170 usb_dev_t *dev = ddf_fun_data_get(fun); 171 assert(hcd); 172 assert(dev); 173 174 usb_log_debug("Device %d released default address\n", dev->address); 175 return hcd_release_default_address(hcd); 176 } 177 178 static errno_t device_enumerate(ddf_fun_t *fun, unsigned port) 179 { 180 assert(fun); 181 ddf_dev_t *ddf_dev = ddf_fun_get_dev(fun); 182 usb_dev_t *dev = ddf_fun_data_get(fun); 183 assert(ddf_dev); 184 assert(dev); 185 usb_log_debug("Hub %d reported a new USB device on port: %u\n", 186 dev->address, port); 187 return hcd_ddf_new_device(ddf_dev, dev, port); 188 } 189 190 static errno_t device_remove(ddf_fun_t *fun, unsigned port) 191 { 192 assert(fun); 193 ddf_dev_t *ddf_dev = ddf_fun_get_dev(fun); 194 usb_dev_t *dev = ddf_fun_data_get(fun); 195 assert(ddf_dev); 196 assert(dev); 197 usb_log_debug("Hub `%s' reported removal of device on port %u\n", 198 ddf_fun_get_name(fun), port); 199 return hcd_ddf_remove_device(ddf_dev, dev, port); 200 } 201 202 /** Gets handle of the respective device. 203 * 204 * @param[in] fun Device function. 205 * @param[out] handle Place to write the handle. 206 * @return Error code. 207 */ 208 static errno_t get_my_device_handle(ddf_fun_t *fun, devman_handle_t *handle) 209 { 210 assert(fun); 211 if (handle) 212 *handle = ddf_fun_get_handle(fun); 213 return EOK; 214 } 215 216 /** Inbound communication interface function. 248 249 if (!desc) 250 return EOK; 251 252 *desc = (usb_device_desc_t) { 253 .address = dev->address, 254 .depth = dev->tier, 255 .speed = dev->speed, 256 .handle = ddf_fun_get_handle(fun), 257 .iface = -1, 258 }; 259 return EOK; 260 } 261 262 /** 263 * Transfer issuing interface function. 264 * 217 265 * @param fun DDF function. 218 266 * @param target Communication target. 267 * @param dir Communication direction. 219 268 * @param setup_data Data to use in setup stage (control transfers). 220 269 * @param data Pointer to data buffer. … … 224 273 * @return Error code. 225 274 */ 226 static errno_t dev_read(ddf_fun_t *fun, usb_endpoint_t endpoint, 227 uint64_t setup_data, uint8_t *data, size_t size, 228 usbhc_iface_transfer_in_callback_t callback, void *arg) 229 { 230 assert(fun); 231 usb_dev_t *usb_dev = ddf_fun_data_get(fun); 232 assert(usb_dev); 275 static errno_t transfer(ddf_fun_t *fun, 276 const usbhc_iface_transfer_request_t *ifreq, 277 usbhc_iface_transfer_callback_t callback, void *arg) 278 { 279 assert(fun); 280 device_t *dev = ddf_fun_data_get(fun); 281 assert(dev); 282 233 283 const usb_target_t target = {{ 234 .address = usb_dev->address, 235 .endpoint = endpoint, 284 .address = dev->address, 285 .endpoint = ifreq->endpoint, 286 .stream = ifreq->stream, 236 287 }}; 237 return hcd_send_batch(dev_to_hcd(ddf_fun_get_dev(fun)), target, 238 USB_DIRECTION_IN, data, size, setup_data, callback, NULL, arg, 239 "READ"); 240 } 241 242 /** Outbound communication interface function. 243 * @param fun DDF function. 244 * @param target Communication target. 245 * @param setup_data Data to use in setup stage (control transfers). 246 * @param data Pointer to data buffer. 247 * @param size Size of the data buffer. 248 * @param callback Function to call on communication end. 249 * @param arg Argument passed to the callback function. 250 * @return Error code. 251 */ 252 static errno_t dev_write(ddf_fun_t *fun, usb_endpoint_t endpoint, 253 uint64_t setup_data, const uint8_t *data, size_t size, 254 usbhc_iface_transfer_out_callback_t callback, void *arg) 255 { 256 assert(fun); 257 usb_dev_t *usb_dev = ddf_fun_data_get(fun); 258 assert(usb_dev); 259 const usb_target_t target = {{ 260 .address = usb_dev->address, 261 .endpoint = endpoint, 262 }}; 263 return hcd_send_batch(dev_to_hcd(ddf_fun_get_dev(fun)), 264 target, USB_DIRECTION_OUT, (uint8_t*)data, size, setup_data, NULL, 265 callback, arg, "WRITE"); 288 289 if (!usb_target_is_valid(&target)) 290 return EINVAL; 291 292 if (ifreq->offset > 0 && ifreq->size == 0) 293 return EINVAL; 294 295 if (ifreq->size > 0 && !dma_buffer_is_set(&ifreq->buffer)) 296 return EBADMEM; 297 298 if (!callback && arg) 299 return EBADMEM; 300 301 const transfer_request_t request = { 302 .target = target, 303 .dir = ifreq->dir, 304 .buffer = ifreq->buffer, 305 .offset = ifreq->offset, 306 .size = ifreq->size, 307 .setup = ifreq->setup, 308 .on_complete = callback, 309 .arg = arg, 310 .name = (ifreq->dir == USB_DIRECTION_IN) ? "READ" : "WRITE", 311 }; 312 313 return bus_issue_transfer(dev, &request); 266 314 } 267 315 268 316 /** USB device interface */ 269 317 static usb_iface_t usb_iface = { 270 .get_my_device_handle = get_my_device_handle, 271 272 .reserve_default_address = reserve_default_address, 273 .release_default_address = release_default_address, 318 .get_my_description = get_device_description, 319 }; 320 321 /** USB host controller interface */ 322 static usbhc_iface_t usbhc_iface = { 323 .default_address_reservation = default_address_reservation, 274 324 275 325 .device_enumerate = device_enumerate, … … 279 329 .unregister_endpoint = unregister_endpoint, 280 330 281 .read = dev_read, 282 .write = dev_write, 331 .transfer = transfer, 283 332 }; 284 333 … … 286 335 static ddf_dev_ops_t usb_ops = { 287 336 .interfaces[USB_DEV_IFACE] = &usb_iface, 337 .interfaces[USBHC_DEV_IFACE] = &usbhc_iface, 288 338 }; 289 339 290 340 291 341 /* DDF HELPERS */ 292 293 #define GET_DEVICE_DESC(size) \294 { \295 .request_type = SETUP_REQUEST_TYPE_DEVICE_TO_HOST \296 | (USB_REQUEST_TYPE_STANDARD << 5) \297 | USB_REQUEST_RECIPIENT_DEVICE, \298 .request = USB_DEVREQ_GET_DESCRIPTOR, \299 .value = uint16_host2usb(USB_DESCTYPE_DEVICE << 8), \300 .index = uint16_host2usb(0), \301 .length = uint16_host2usb(size), \302 };303 304 #define SET_ADDRESS(address) \305 { \306 .request_type = SETUP_REQUEST_TYPE_HOST_TO_DEVICE \307 | (USB_REQUEST_TYPE_STANDARD << 5) \308 | USB_REQUEST_RECIPIENT_DEVICE, \309 .request = USB_DEVREQ_SET_ADDRESS, \310 .value = uint16_host2usb(address), \311 .index = uint16_host2usb(0), \312 .length = uint16_host2usb(0), \313 };314 315 static errno_t hcd_ddf_add_device(ddf_dev_t *parent, usb_dev_t *hub_dev,316 unsigned port, usb_address_t address, usb_speed_t speed, const char *name,317 const match_id_list_t *mids)318 {319 assert(parent);320 321 char default_name[10] = { 0 }; /* usbxyz-ss */322 if (!name) {323 snprintf(default_name, sizeof(default_name) - 1,324 "usb%u-%cs", address, usb_str_speed(speed)[0]);325 name = default_name;326 }327 328 ddf_fun_t *fun = ddf_fun_create(parent, fun_inner, name);329 if (!fun)330 return ENOMEM;331 usb_dev_t *info = ddf_fun_data_alloc(fun, sizeof(usb_dev_t));332 if (!info) {333 ddf_fun_destroy(fun);334 return ENOMEM;335 }336 info->address = address;337 info->speed = speed;338 info->fun = fun;339 info->port = port;340 info->tt_address = hub_dev ? hub_dev->tt_address : -1;341 link_initialize(&info->link);342 list_initialize(&info->devices);343 fibril_mutex_initialize(&info->guard);344 345 if (hub_dev && hub_dev->speed == USB_SPEED_HIGH && usb_speed_is_11(speed))346 info->tt_address = hub_dev->address;347 348 ddf_fun_set_ops(fun, &usb_ops);349 list_foreach(mids->ids, link, const match_id_t, mid) {350 ddf_fun_add_match_id(fun, mid->id, mid->score);351 }352 353 errno_t ret = ddf_fun_bind(fun);354 if (ret != EOK) {355 ddf_fun_destroy(fun);356 return ret;357 }358 359 if (hub_dev) {360 fibril_mutex_lock(&hub_dev->guard);361 list_append(&info->link, &hub_dev->devices);362 fibril_mutex_unlock(&hub_dev->guard);363 } else {364 hc_dev_t *hc_dev = dev_to_hc_dev(parent);365 assert(hc_dev->root_hub == NULL);366 hc_dev->root_hub = info;367 }368 return EOK;369 }370 342 371 343 #define ADD_MATCHID_OR_RETURN(list, sc, str, ...) \ … … 394 366 assert(l); 395 367 assert(d); 396 368 397 369 if (d->vendor_id != 0) { 398 370 /* First, with release number. */ … … 401 373 d->vendor_id, d->product_id, (d->device_version >> 8), 402 374 (d->device_version & 0xff)); 403 375 404 376 /* Next, without release number. */ 405 377 ADD_MATCHID_OR_RETURN(l, 90, "usb&vendor=%#04x&product=%#04x", … … 415 387 416 388 return EOK; 417 418 } 419 420 static errno_t hcd_ddf_remove_device(ddf_dev_t *device, usb_dev_t *hub, 421 unsigned port) 422 { 423 assert(device); 424 425 hcd_t *hcd = dev_to_hcd(device); 426 assert(hcd); 427 428 hc_dev_t *hc_dev = dev_to_hc_dev(device); 429 assert(hc_dev); 430 431 fibril_mutex_lock(&hub->guard); 432 433 usb_dev_t *victim = NULL; 434 435 list_foreach(hub->devices, link, usb_dev_t, it) { 436 if (it->port == port) { 437 victim = it; 438 break; 439 } 440 } 441 if (victim) { 442 assert(victim->port == port); 443 list_remove(&victim->link); 444 fibril_mutex_unlock(&hub->guard); 445 const errno_t ret = ddf_fun_unbind(victim->fun); 446 if (ret == EOK) { 447 usb_address_t address = victim->address; 448 ddf_fun_destroy(victim->fun); 449 hcd_release_address(hcd, address); 450 } else { 451 usb_log_warning("Failed to unbind device `%s': %s\n", 452 ddf_fun_get_name(victim->fun), str_error(ret)); 453 } 454 return EOK; 455 } 456 fibril_mutex_unlock(&hub->guard); 457 return ENOENT; 458 } 459 460 static errno_t hcd_ddf_new_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port) 461 { 462 assert(device); 463 464 hcd_t *hcd = dev_to_hcd(device); 465 assert(hcd); 466 467 usb_speed_t speed = USB_SPEED_MAX; 468 469 /* This checks whether the default address is reserved and gets speed */ 470 errno_t ret = usb_bus_get_speed(&hcd->bus, USB_ADDRESS_DEFAULT, &speed); 471 if (ret != EOK) { 472 usb_log_error("Failed to verify speed: %s.", str_error(ret)); 473 return ret; 474 } 475 476 usb_log_debug("Found new %s speed USB device.", usb_str_speed(speed)); 477 478 static const usb_target_t default_target = {{ 479 .address = USB_ADDRESS_DEFAULT, 480 .endpoint = 0, 481 }}; 482 483 usb_address_t address; 484 ret = hcd_request_address(hcd, speed, &address); 485 if (ret != EOK) { 486 usb_log_error("Failed to reserve new address: %s.", 487 str_error(ret)); 488 return ret; 489 } 490 491 usb_log_debug("Reserved new address: %d\n", address); 492 493 const usb_target_t target = {{ 494 .address = address, 495 .endpoint = 0, 496 }}; 497 498 const usb_address_t tt_address = hub ? hub->tt_address : -1; 499 500 /* Add default pipe on default address */ 501 usb_log_debug("Device(%d): Adding default target(0:0)\n", address); 502 ret = hcd_add_ep(hcd, 503 default_target, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL, 504 CTRL_PIPE_MIN_PACKET_SIZE, CTRL_PIPE_MIN_PACKET_SIZE, 1, 505 tt_address, port); 506 if (ret != EOK) { 507 usb_log_error("Device(%d): Failed to add default target: %s.", 508 address, str_error(ret)); 509 hcd_release_address(hcd, address); 510 return ret; 511 } 512 513 /* Get max packet size for default pipe */ 514 usb_standard_device_descriptor_t desc = { 0 }; 515 const usb_device_request_setup_packet_t get_device_desc_8 = 516 GET_DEVICE_DESC(CTRL_PIPE_MIN_PACKET_SIZE); 517 518 // TODO CALLBACKS 519 usb_log_debug("Device(%d): Requesting first 8B of device descriptor.", 520 address); 521 size_t got; 522 ret = hcd_send_batch_sync(hcd, default_target, USB_DIRECTION_IN, 523 &desc, CTRL_PIPE_MIN_PACKET_SIZE, *(uint64_t *)&get_device_desc_8, 524 "read first 8 bytes of dev descriptor", &got); 525 526 if (ret == EOK && got != CTRL_PIPE_MIN_PACKET_SIZE) { 527 ret = EOVERFLOW; 528 } 529 530 if (ret != EOK) { 531 usb_log_error("Device(%d): Failed to get 8B of dev descr: %s.", 532 address, str_error(ret)); 533 hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH); 534 hcd_release_address(hcd, address); 535 return ret; 536 } 537 538 /* Register EP on the new address */ 539 usb_log_debug("Device(%d): Registering control EP.", address); 540 ret = hcd_add_ep(hcd, target, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL, 541 ED_MPS_PACKET_SIZE_GET(uint16_usb2host(desc.max_packet_size)), 542 ED_MPS_TRANS_OPPORTUNITIES_GET(uint16_usb2host(desc.max_packet_size)), 543 ED_MPS_PACKET_SIZE_GET(uint16_usb2host(desc.max_packet_size)), 544 tt_address, port); 545 if (ret != EOK) { 546 usb_log_error("Device(%d): Failed to register EP0: %s", 547 address, str_error(ret)); 548 hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH); 549 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH); 550 hcd_release_address(hcd, address); 551 return ret; 552 } 553 554 /* Set new address */ 555 const usb_device_request_setup_packet_t set_address = 556 SET_ADDRESS(target.address); 557 558 usb_log_debug("Device(%d): Setting USB address.", address); 559 ret = hcd_send_batch_sync(hcd, default_target, USB_DIRECTION_OUT, 560 NULL, 0, *(uint64_t *)&set_address, "set address", &got); 561 562 usb_log_debug("Device(%d): Removing default (0:0) EP.", address); 563 hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH); 564 565 if (ret != EOK) { 566 usb_log_error("Device(%d): Failed to set new address: %s.", 567 address, str_error(ret)); 568 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH); 569 hcd_release_address(hcd, address); 570 return ret; 571 } 572 573 /* Get std device descriptor */ 574 const usb_device_request_setup_packet_t get_device_desc = 575 GET_DEVICE_DESC(sizeof(desc)); 576 577 usb_log_debug("Device(%d): Requesting full device descriptor.", 578 address); 579 ret = hcd_send_batch_sync(hcd, target, USB_DIRECTION_IN, 580 &desc, sizeof(desc), *(uint64_t *)&get_device_desc, 581 "read device descriptor", &got); 582 if (ret != EOK) { 583 usb_log_error("Device(%d): Failed to set get dev descriptor: %s", 584 address, str_error(ret)); 585 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH); 586 hcd_release_address(hcd, target.address); 587 return ret; 588 } 389 } 390 391 device_t *hcd_ddf_fun_create(hc_device_t *hc, usb_speed_t speed) 392 { 393 /* Create DDF function for the new device */ 394 ddf_fun_t *fun = ddf_fun_create(hc->ddf_dev, fun_inner, NULL); 395 if (!fun) 396 return NULL; 397 398 ddf_fun_set_ops(fun, &usb_ops); 399 400 /* Create USB device node for the new device */ 401 device_t *dev = ddf_fun_data_alloc(fun, hc->bus->device_size); 402 if (!dev) { 403 ddf_fun_destroy(fun); 404 return NULL; 405 } 406 407 bus_device_init(dev, hc->bus); 408 dev->fun = fun; 409 dev->speed = speed; 410 return dev; 411 } 412 413 void hcd_ddf_fun_destroy(device_t *dev) 414 { 415 assert(dev); 416 assert(dev->fun); 417 ddf_fun_destroy(dev->fun); 418 } 419 420 errno_t hcd_ddf_setup_match_ids(device_t *device, usb_standard_device_descriptor_t *desc) 421 { 422 errno_t err; 423 match_id_list_t mids; 424 425 init_match_ids(&mids); 589 426 590 427 /* Create match ids from the device descriptor */ 591 match_id_list_t mids; 592 init_match_ids(&mids); 593 594 usb_log_debug("Device(%d): Creating match IDs.", address); 595 ret = create_match_ids(&mids, &desc); 596 if (ret != EOK) { 597 usb_log_error("Device(%d): Failed to create match ids: %s", 598 address, str_error(ret)); 599 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH); 600 hcd_release_address(hcd, target.address); 601 return ret; 602 } 603 604 /* Register device */ 605 usb_log_debug("Device(%d): Registering DDF device.", address); 606 ret = hcd_ddf_add_device(device, hub, port, address, speed, NULL, &mids); 607 clean_match_ids(&mids); 608 if (ret != EOK) { 609 usb_log_error("Device(%d): Failed to register: %s.", 610 address, str_error(ret)); 611 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH); 612 hcd_release_address(hcd, target.address); 613 } 614 615 return ret; 616 } 617 618 /** Announce root hub to the DDF 619 * 620 * @param[in] device Host controller ddf device 621 * @return Error code 622 */ 623 errno_t hcd_ddf_setup_root_hub(ddf_dev_t *device) 624 { 625 assert(device); 626 hcd_t *hcd = dev_to_hcd(device); 627 assert(hcd); 628 629 hcd_reserve_default_address(hcd, hcd->bus.max_speed); 630 const errno_t ret = hcd_ddf_new_device(device, NULL, 0); 631 hcd_release_default_address(hcd); 632 return ret; 428 usb_log_debug("Device(%d): Creating match IDs.", device->address); 429 if ((err = create_match_ids(&mids, desc))) { 430 return err; 431 } 432 433 list_foreach(mids.ids, link, const match_id_t, mid) { 434 ddf_fun_add_match_id(device->fun, mid->id, mid->score); 435 } 436 437 return EOK; 633 438 } 634 439 … … 643 448 * This function does all the ddf work for hc driver. 644 449 */ 645 errno_t hcd_ddf_setup_hc(ddf_dev_t *device, usb_speed_t max_speed, 646 size_t bw, bw_count_func_t bw_count) 450 errno_t hcd_ddf_setup_hc(ddf_dev_t *device, size_t size) 647 451 { 648 452 assert(device); 649 453 650 hc_dev _t *instance = ddf_dev_data_alloc(device, sizeof(hc_dev_t));454 hc_device_t *instance = ddf_dev_data_alloc(device, size); 651 455 if (instance == NULL) { 652 usb_log_error("Failed to allocate HCD ddf structure. \n");456 usb_log_error("Failed to allocate HCD ddf structure."); 653 457 return ENOMEM; 654 458 } 655 instance->root_hub = NULL; 656 hcd_init(&instance->hcd, max_speed, bw, bw_count); 459 instance->ddf_dev = device; 657 460 658 461 errno_t ret = ENOMEM; 659 462 instance->ctl_fun = ddf_fun_create(device, fun_exposed, "ctl"); 660 463 if (!instance->ctl_fun) { 661 usb_log_error("Failed to create HCD ddf fun. \n");464 usb_log_error("Failed to create HCD ddf fun."); 662 465 goto err_destroy_fun; 663 466 } … … 665 468 ret = ddf_fun_bind(instance->ctl_fun); 666 469 if (ret != EOK) { 667 usb_log_error("Failed to bind ctl_fun: %s. \n", str_error(ret));470 usb_log_error("Failed to bind ctl_fun: %s.", str_error(ret)); 668 471 goto err_destroy_fun; 669 472 } … … 671 474 ret = ddf_fun_add_to_category(instance->ctl_fun, USB_HC_CATEGORY); 672 475 if (ret != EOK) { 673 usb_log_error("Failed to add fun to category: %s. \n",476 usb_log_error("Failed to add fun to category: %s.", 674 477 str_error(ret)); 675 478 ddf_fun_unbind(instance->ctl_fun); … … 686 489 } 687 490 688 void hcd_ddf_clean_hc(ddf_dev_t *device) 689 { 690 assert(device); 691 hc_dev_t *hc = dev_to_hc_dev(device); 692 assert(hc); 693 const errno_t ret = ddf_fun_unbind(hc->ctl_fun); 694 if (ret == EOK) 695 ddf_fun_destroy(hc->ctl_fun); 696 } 697 698 //TODO: Cache parent session in HCD 491 void hcd_ddf_clean_hc(hc_device_t *hcd) 492 { 493 if (ddf_fun_unbind(hcd->ctl_fun) == EOK) 494 ddf_fun_destroy(hcd->ctl_fun); 495 } 496 699 497 /** Call the parent driver with a request to enable interrupt 700 498 * … … 703 501 * @return Error code. 704 502 */ 705 errno_t hcd_ddf_enable_interrupt( ddf_dev_t *device, int inum)706 { 707 async_sess_t *parent_sess = ddf_dev_parent_sess_get( device);503 errno_t hcd_ddf_enable_interrupt(hc_device_t *hcd, int inum) 504 { 505 async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev); 708 506 if (parent_sess == NULL) 709 507 return EIO; … … 712 510 } 713 511 714 //TODO: Cache parent session in HCD 715 errno_t hcd_ddf_get_registers(ddf_dev_t *device, hw_res_list_parsed_t *hw_res) 716 { 717 async_sess_t *parent_sess = ddf_dev_parent_sess_get(device); 512 errno_t hcd_ddf_get_registers(hc_device_t *hcd, hw_res_list_parsed_t *hw_res) 513 { 514 async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev); 718 515 if (parent_sess == NULL) 719 516 return EIO; … … 726 523 } 727 524 728 // TODO: move this someplace else729 static inline void irq_code_clean(irq_code_t *code)730 {731 if (code) {732 free(code->ranges);733 free(code->cmds);734 code->ranges = NULL;735 code->cmds = NULL;736 code->rangecount = 0;737 code->cmdcount = 0;738 }739 }740 741 /** Register interrupt handler742 *743 * @param[in] device Host controller DDF device744 * @param[in] regs Register range745 * @param[in] irq Interrupt number746 * @paran[in] handler Interrupt handler747 * @param[in] gen_irq_code IRQ code generator.748 *749 * @param[out] handle IRQ capability handle on success.750 *751 * @return Error code.752 */753 errno_t hcd_ddf_setup_interrupts(ddf_dev_t *device,754 const hw_res_list_parsed_t *hw_res,755 interrupt_handler_t handler,756 errno_t (*gen_irq_code)(irq_code_t *, const hw_res_list_parsed_t *, int *),757 cap_handle_t *handle)758 {759 760 assert(device);761 if (!handler || !gen_irq_code)762 return ENOTSUP;763 764 irq_code_t irq_code = {0};765 766 int irq;767 errno_t ret = gen_irq_code(&irq_code, hw_res, &irq);768 if (ret != EOK) {769 usb_log_error("Failed to generate IRQ code: %s.\n",770 str_error(ret));771 return ret;772 }773 774 /* Register handler to avoid interrupt lockup */775 ret = register_interrupt_handler(device, irq, handler,776 &irq_code, handle);777 irq_code_clean(&irq_code);778 if (ret != EOK) {779 usb_log_error("Failed to register interrupt handler: %s.\n",780 str_error(ret));781 return ret;782 }783 784 /* Enable interrupts */785 ret = hcd_ddf_enable_interrupt(device, irq);786 if (ret != EOK) {787 usb_log_error("Failed to register interrupt handler: %s.\n",788 str_error(ret));789 unregister_interrupt_handler(device, *handle);790 }791 return ret;792 }793 794 /** IRQ handling callback, forward status from call to diver structure.795 *796 * @param[in] dev DDF instance of the device to use.797 * @param[in] call Pointer to the call from kernel.798 */799 void ddf_hcd_gen_irq_handler(ipc_call_t *call, ddf_dev_t *dev)800 {801 assert(dev);802 hcd_t *hcd = dev_to_hcd(dev);803 if (!hcd || !hcd->ops.irq_hook) {804 usb_log_error("Interrupt on not yet initialized device.\n");805 return;806 }807 const uint32_t status = IPC_GET_ARG1(*call);808 hcd->ops.irq_hook(hcd, status);809 }810 811 static errno_t interrupt_polling(void *arg)812 {813 hcd_t *hcd = arg;814 assert(hcd);815 if (!hcd->ops.status_hook || !hcd->ops.irq_hook)816 return ENOTSUP;817 uint32_t status = 0;818 while (hcd->ops.status_hook(hcd, &status) == EOK) {819 hcd->ops.irq_hook(hcd, status);820 status = 0;821 /* We should wait 1 frame - 1ms here, but this polling is a822 * lame crutch anyway so don't hog the system. 10ms is still823 * good enough for emergency mode */824 async_usleep(10000);825 }826 return EOK;827 }828 829 /** Initialize hc and rh DDF structures and their respective drivers.830 *831 * @param device DDF instance of the device to use832 * @param speed Maximum supported speed833 * @param bw Available bandwidth (arbitrary units)834 * @param bw_count Bandwidth computing function835 * @param irq_handler IRQ handling function836 * @param gen_irq_code Function to generate IRQ pseudocode837 * (it needs to return used irq number)838 * @param driver_init Function to initialize HC driver839 * @param driver_fini Function to cleanup HC driver840 * @return Error code841 *842 * This function does all the preparatory work for hc and rh drivers:843 * - gets device's hw resources844 * - attempts to enable interrupts845 * - registers interrupt handler846 * - calls driver specific initialization847 * - registers root hub848 */849 errno_t hcd_ddf_add_hc(ddf_dev_t *device, const ddf_hc_driver_t *driver)850 {851 assert(driver);852 static const struct { size_t bw; bw_count_func_t bw_count; }bw[] = {853 [USB_SPEED_FULL] = { .bw = BANDWIDTH_AVAILABLE_USB11,854 .bw_count = bandwidth_count_usb11 },855 [USB_SPEED_HIGH] = { .bw = BANDWIDTH_AVAILABLE_USB11,856 .bw_count = bandwidth_count_usb11 },857 };858 859 errno_t ret = EOK;860 const usb_speed_t speed = driver->hc_speed;861 if (speed >= ARRAY_SIZE(bw) || bw[speed].bw == 0) {862 usb_log_error("Driver `%s' reported unsupported speed: %s",863 driver->name, usb_str_speed(speed));864 return ENOTSUP;865 }866 867 hw_res_list_parsed_t hw_res;868 ret = hcd_ddf_get_registers(device, &hw_res);869 if (ret != EOK) {870 usb_log_error("Failed to get register memory addresses "871 "for `%s': %s.\n", ddf_dev_get_name(device),872 str_error(ret));873 return ret;874 }875 876 ret = hcd_ddf_setup_hc(device, speed, bw[speed].bw, bw[speed].bw_count);877 if (ret != EOK) {878 usb_log_error("Failed to setup generic HCD.\n");879 hw_res_list_parsed_clean(&hw_res);880 return ret;881 }882 883 interrupt_handler_t *irq_handler =884 driver->irq_handler ? driver->irq_handler : ddf_hcd_gen_irq_handler;885 int irq_cap;886 errno_t irq_ret = hcd_ddf_setup_interrupts(device, &hw_res,887 irq_handler, driver->irq_code_gen, &irq_cap);888 bool irqs_enabled = (irq_ret == EOK);889 if (irqs_enabled) {890 usb_log_debug("Hw interrupts enabled.\n");891 }892 893 if (driver->claim) {894 ret = driver->claim(device);895 if (ret != EOK) {896 usb_log_error("Failed to claim `%s' for driver `%s'",897 ddf_dev_get_name(device), driver->name);898 return ret;899 }900 }901 902 903 /* Init hw driver */904 hcd_t *hcd = dev_to_hcd(device);905 ret = driver->init(hcd, &hw_res, irqs_enabled);906 hw_res_list_parsed_clean(&hw_res);907 if (ret != EOK) {908 usb_log_error("Failed to init HCD: %s.\n", str_error(ret));909 goto irq_unregister;910 }911 912 /* Need working irq replacement to setup root hub */913 if (!irqs_enabled && hcd->ops.status_hook) {914 hcd->polling_fibril = fibril_create(interrupt_polling, hcd);915 if (hcd->polling_fibril == 0) {916 usb_log_error("Failed to create polling fibril\n");917 ret = ENOMEM;918 goto irq_unregister;919 }920 fibril_add_ready(hcd->polling_fibril);921 usb_log_warning("Failed to enable interrupts: %s."922 " Falling back to polling.\n", str_error(irq_ret));923 }924 925 /*926 * Creating root hub registers a new USB device so HC927 * needs to be ready at this time.928 */929 ret = hcd_ddf_setup_root_hub(device);930 if (ret != EOK) {931 usb_log_error("Failed to setup HC root hub: %s.\n",932 str_error(ret));933 driver->fini(dev_to_hcd(device));934 irq_unregister:935 /* Unregistering non-existent should be ok */936 unregister_interrupt_handler(device, irq_cap);937 hcd_ddf_clean_hc(device);938 return ret;939 }940 941 usb_log_info("Controlling new `%s' device `%s'.\n",942 driver->name, ddf_dev_get_name(device));943 return EOK;944 }945 525 /** 946 526 * @} -
uspace/lib/usbhost/src/endpoint.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 34 35 */ 35 36 36 #include <usb/host/endpoint.h>37 38 37 #include <assert.h> 38 #include <atomic.h> 39 #include <mem.h> 39 40 #include <stdlib.h> 40 #include <atomic.h> 41 42 /** Allocate ad initialize endpoint_t structure. 43 * @param address USB address. 44 * @param endpoint USB endpoint number. 45 * @param direction Communication direction. 46 * @param type USB transfer type. 47 * @param speed Communication speed. 48 * @param max_packet_size Maximum size of data packets. 49 * @param bw Required bandwidth. 50 * @return Pointer to initialized endpoint_t structure, NULL on failure. 51 */ 52 endpoint_t * endpoint_create(usb_address_t address, usb_endpoint_t endpoint, 53 usb_direction_t direction, usb_transfer_type_t type, usb_speed_t speed, 54 size_t max_packet_size, unsigned packets, size_t bw, 55 usb_address_t tt_address, unsigned tt_p) 56 { 57 endpoint_t *instance = malloc(sizeof(endpoint_t)); 58 if (instance) { 59 atomic_set(&instance->refcnt, 0); 60 instance->address = address; 61 instance->endpoint = endpoint; 62 instance->direction = direction; 63 instance->transfer_type = type; 64 instance->speed = speed; 65 instance->max_packet_size = max_packet_size; 66 instance->packets = packets; 67 instance->bandwidth = bw; 68 instance->toggle = 0; 69 instance->active = false; 70 instance->tt.address = tt_address; 71 instance->tt.port = tt_p; 72 instance->hc_data.data = NULL; 73 instance->hc_data.toggle_get = NULL; 74 instance->hc_data.toggle_set = NULL; 75 link_initialize(&instance->link); 76 fibril_mutex_initialize(&instance->guard); 77 fibril_condvar_initialize(&instance->avail); 78 } 79 return instance; 80 } 81 82 /** Properly dispose of endpoint_t structure. 83 * @param instance endpoint_t structure. 84 */ 85 void endpoint_destroy(endpoint_t *instance) 86 { 87 assert(instance); 88 assert(!instance->active); 89 assert(instance->hc_data.data == NULL); 90 free(instance); 91 } 92 93 void endpoint_add_ref(endpoint_t *instance) 94 { 95 atomic_inc(&instance->refcnt); 96 } 97 98 void endpoint_del_ref(endpoint_t *instance) 99 { 100 if (atomic_predec(&instance->refcnt) == 0) 101 endpoint_destroy(instance); 102 } 103 104 /** Set device specific data and hooks. 105 * @param instance endpoint_t structure. 106 * @param data device specific data. 107 * @param toggle_get Hook to call when retrieving value of toggle bit. 108 * @param toggle_set Hook to call when setting the value of toggle bit. 109 */ 110 void endpoint_set_hc_data(endpoint_t *instance, 111 void *data, int (*toggle_get)(void *), void (*toggle_set)(void *, int)) 112 { 113 assert(instance); 114 fibril_mutex_lock(&instance->guard); 115 instance->hc_data.data = data; 116 instance->hc_data.toggle_get = toggle_get; 117 instance->hc_data.toggle_set = toggle_set; 118 fibril_mutex_unlock(&instance->guard); 119 } 120 121 /** Clear device specific data and hooks. 122 * @param instance endpoint_t structure. 123 * @note This function does not free memory pointed to by data pointer. 124 */ 125 void endpoint_clear_hc_data(endpoint_t *instance) 126 { 127 assert(instance); 128 endpoint_set_hc_data(instance, NULL, NULL, NULL); 129 } 130 131 /** Mark the endpoint as active and block access for further fibrils. 132 * @param instance endpoint_t structure. 133 */ 134 void endpoint_use(endpoint_t *instance) 135 { 136 assert(instance); 137 /* Add reference for active endpoint. */ 138 endpoint_add_ref(instance); 139 fibril_mutex_lock(&instance->guard); 140 while (instance->active) 141 fibril_condvar_wait(&instance->avail, &instance->guard); 142 instance->active = true; 143 fibril_mutex_unlock(&instance->guard); 144 } 145 146 /** Mark the endpoint as inactive and allow access for further fibrils. 147 * @param instance endpoint_t structure. 148 */ 149 void endpoint_release(endpoint_t *instance) 150 { 151 assert(instance); 152 fibril_mutex_lock(&instance->guard); 153 instance->active = false; 154 fibril_mutex_unlock(&instance->guard); 155 fibril_condvar_signal(&instance->avail); 156 /* Drop reference for active endpoint. */ 157 endpoint_del_ref(instance); 158 } 159 160 /** Get the value of toggle bit. 161 * @param instance endpoint_t structure. 162 * @note Will use provided hook. 163 */ 164 int endpoint_toggle_get(endpoint_t *instance) 165 { 166 assert(instance); 167 fibril_mutex_lock(&instance->guard); 168 if (instance->hc_data.toggle_get) 169 instance->toggle = 170 instance->hc_data.toggle_get(instance->hc_data.data); 171 const int ret = instance->toggle; 172 fibril_mutex_unlock(&instance->guard); 41 #include <str_error.h> 42 #include <usb/debug.h> 43 #include <usb/descriptor.h> 44 #include <usb/host/hcd.h> 45 #include <usb/host/utility.h> 46 47 #include "usb_transfer_batch.h" 48 #include "bus.h" 49 50 #include "endpoint.h" 51 52 /** 53 * Initialize provided endpoint structure. 54 */ 55 void endpoint_init(endpoint_t *ep, device_t *dev, const usb_endpoint_descriptors_t *desc) 56 { 57 memset(ep, 0, sizeof(endpoint_t)); 58 59 assert(dev); 60 ep->device = dev; 61 62 atomic_set(&ep->refcnt, 0); 63 fibril_condvar_initialize(&ep->avail); 64 65 ep->endpoint = USB_ED_GET_EP(desc->endpoint); 66 ep->direction = USB_ED_GET_DIR(desc->endpoint); 67 ep->transfer_type = USB_ED_GET_TRANSFER_TYPE(desc->endpoint); 68 ep->max_packet_size = USB_ED_GET_MPS(desc->endpoint); 69 ep->packets_per_uframe = USB_ED_GET_ADD_OPPS(desc->endpoint) + 1; 70 71 /** Direction both is our construct never present in descriptors */ 72 if (ep->transfer_type == USB_TRANSFER_CONTROL) 73 ep->direction = USB_DIRECTION_BOTH; 74 75 ep->max_transfer_size = ep->max_packet_size * ep->packets_per_uframe; 76 ep->transfer_buffer_policy = DMA_POLICY_STRICT; 77 ep->required_transfer_buffer_policy = DMA_POLICY_STRICT; 78 } 79 80 /** 81 * Get the bus endpoint belongs to. 82 */ 83 static inline const bus_ops_t *get_bus_ops(endpoint_t *ep) 84 { 85 return ep->device->bus->ops; 86 } 87 88 /** 89 * Increase the reference count on endpoint. 90 */ 91 void endpoint_add_ref(endpoint_t *ep) 92 { 93 atomic_inc(&ep->refcnt); 94 } 95 96 /** 97 * Call the desctruction callback. Default behavior is to free the memory directly. 98 */ 99 static inline void endpoint_destroy(endpoint_t *ep) 100 { 101 const bus_ops_t *ops = get_bus_ops(ep); 102 if (ops->endpoint_destroy) { 103 ops->endpoint_destroy(ep); 104 } else { 105 assert(ep->active_batch == NULL); 106 107 /* Assume mostly the eps will be allocated by malloc. */ 108 free(ep); 109 } 110 } 111 112 /** 113 * Decrease the reference count. 114 */ 115 void endpoint_del_ref(endpoint_t *ep) 116 { 117 if (atomic_predec(&ep->refcnt) == 0) { 118 endpoint_destroy(ep); 119 } 120 } 121 122 /** 123 * Mark the endpoint as online. Supply a guard to be used for this endpoint 124 * synchronization. 125 */ 126 void endpoint_set_online(endpoint_t *ep, fibril_mutex_t *guard) 127 { 128 ep->guard = guard; 129 ep->online = true; 130 } 131 132 /** 133 * Mark the endpoint as offline. All other fibrils waiting to activate this 134 * endpoint will be interrupted. 135 */ 136 void endpoint_set_offline_locked(endpoint_t *ep) 137 { 138 assert(ep); 139 assert(fibril_mutex_is_locked(ep->guard)); 140 141 ep->online = false; 142 fibril_condvar_broadcast(&ep->avail); 143 } 144 145 /** 146 * Wait until a transfer finishes. Can be used even when the endpoint is 147 * offline (and is interrupted by the endpoint going offline). 148 */ 149 void endpoint_wait_timeout_locked(endpoint_t *ep, suseconds_t timeout) 150 { 151 assert(ep); 152 assert(fibril_mutex_is_locked(ep->guard)); 153 154 if (ep->active_batch == NULL) 155 return; 156 157 fibril_condvar_wait_timeout(&ep->avail, ep->guard, timeout); 158 } 159 160 /** 161 * Mark the endpoint as active and block access for further fibrils. If the 162 * endpoint is already active, it will block on ep->avail condvar. 163 * 164 * Call only under endpoint guard. After you activate the endpoint and release 165 * the guard, you must assume that particular transfer is already 166 * finished/aborted. 167 * 168 * Activation and deactivation is not done by the library to maximize 169 * performance. The HC might want to prepare some memory buffers prior to 170 * interfering with other world. 171 * 172 * @param batch Transfer batch this endpoint is blocked by. 173 */ 174 int endpoint_activate_locked(endpoint_t *ep, usb_transfer_batch_t *batch) 175 { 176 assert(ep); 177 assert(batch); 178 assert(batch->ep == ep); 179 assert(ep->guard); 180 assert(fibril_mutex_is_locked(ep->guard)); 181 182 while (ep->online && ep->active_batch != NULL) 183 fibril_condvar_wait(&ep->avail, ep->guard); 184 185 if (!ep->online) 186 return EINTR; 187 188 assert(ep->active_batch == NULL); 189 ep->active_batch = batch; 190 return EOK; 191 } 192 193 /** 194 * Mark the endpoint as inactive and allow access for further fibrils. 195 */ 196 void endpoint_deactivate_locked(endpoint_t *ep) 197 { 198 assert(ep); 199 assert(fibril_mutex_is_locked(ep->guard)); 200 201 ep->active_batch = NULL; 202 fibril_condvar_signal(&ep->avail); 203 } 204 205 /** 206 * Initiate a transfer on an endpoint. Creates a transfer batch, checks the 207 * bandwidth requirements and schedules the batch. 208 * 209 * @param endpoint Endpoint for which to send the batch 210 */ 211 errno_t endpoint_send_batch(endpoint_t *ep, const transfer_request_t *req) 212 { 213 assert(ep); 214 assert(req); 215 216 if (ep->transfer_type == USB_TRANSFER_CONTROL) { 217 usb_log_debug("%s %d:%d %zu/%zuB, setup %#016" PRIx64, req->name, 218 req->target.address, req->target.endpoint, 219 req->size, ep->max_packet_size, 220 req->setup); 221 } else { 222 usb_log_debug("%s %d:%d %zu/%zuB", req->name, 223 req->target.address, req->target.endpoint, 224 req->size, ep->max_packet_size); 225 } 226 227 device_t * const device = ep->device; 228 if (!device) { 229 usb_log_warning("Endpoint detached"); 230 return EAGAIN; 231 } 232 233 const bus_ops_t *ops = device->bus->ops; 234 if (!ops->batch_schedule) { 235 usb_log_error("HCD does not implement scheduler."); 236 return ENOTSUP; 237 } 238 239 size_t size = req->size; 240 /* 241 * Limit transfers with reserved bandwidth to the amount reserved. 242 * OUT transfers are rejected, IN can be just trimmed in advance. 243 */ 244 if (size > ep->max_transfer_size && 245 (ep->transfer_type == USB_TRANSFER_INTERRUPT 246 || ep->transfer_type == USB_TRANSFER_ISOCHRONOUS)) { 247 if (req->dir == USB_DIRECTION_OUT) 248 return ENOSPC; 249 else 250 size = ep->max_transfer_size; 251 } 252 253 /* Offline devices don't schedule transfers other than on EP0. */ 254 if (!device->online && ep->endpoint > 0) 255 return EAGAIN; 256 257 usb_transfer_batch_t *batch = usb_transfer_batch_create(ep); 258 if (!batch) { 259 usb_log_error("Failed to create transfer batch."); 260 return ENOMEM; 261 } 262 263 batch->target = req->target; 264 batch->setup.packed = req->setup; 265 batch->dir = req->dir; 266 batch->size = size; 267 batch->offset = req->offset; 268 batch->dma_buffer = req->buffer; 269 270 dma_buffer_acquire(&batch->dma_buffer); 271 272 if (batch->offset != 0) { 273 usb_log_debug("A transfer with nonzero offset requested."); 274 usb_transfer_batch_bounce(batch); 275 } 276 277 if (usb_transfer_batch_bounce_required(batch)) 278 usb_transfer_batch_bounce(batch); 279 280 batch->on_complete = req->on_complete; 281 batch->on_complete_data = req->arg; 282 283 const int ret = ops->batch_schedule(batch); 284 if (ret != EOK) { 285 usb_log_warning("Batch %p failed to schedule: %s", batch, str_error(ret)); 286 usb_transfer_batch_destroy(batch); 287 } 288 173 289 return ret; 174 290 } 175 291 176 /** Set the value of toggle bit.177 * @param instance endpoint_t structure.178 * @note Will use provided hook.179 */180 void endpoint_toggle_set(endpoint_t *instance, int toggle)181 {182 assert(instance);183 assert(toggle == 0 || toggle == 1);184 fibril_mutex_lock(&instance->guard);185 instance->toggle = toggle;186 if (instance->hc_data.toggle_set)187 instance->hc_data.toggle_set(instance->hc_data.data, toggle);188 fibril_mutex_unlock(&instance->guard);189 }190 191 292 /** 192 293 * @} -
uspace/lib/usbhost/src/hcd.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 32 33 /** @file 33 34 * 34 */ 35 36 #include <usb/debug.h> 37 #include <usb/request.h> 35 * Host controller driver framework. Encapsulates DDF device of HC to an 36 * hc_device_t, which is passed to driver implementing hc_driver_t. 37 */ 38 38 39 39 #include <assert.h> 40 40 #include <async.h> 41 #include <ddf/interrupt.h> 41 42 #include <errno.h> 43 #include <macros.h> 44 #include <str_error.h> 45 #include <usb/debug.h> 46 #include <usb/descriptor.h> 47 #include <usb/request.h> 42 48 #include <usb_iface.h> 43 49 50 #include "bus.h" 51 #include "ddf_helpers.h" 52 #include "endpoint.h" 53 #include "usb_transfer_batch.h" 54 44 55 #include "hcd.h" 45 56 46 /** Calls ep_add_hook upon endpoint registration. 47 * @param ep Endpoint to be registered. 48 * @param arg hcd_t in disguise. 49 * @return Error code. 50 */ 51 static errno_t register_helper(endpoint_t *ep, void *arg) 52 { 53 hcd_t *hcd = arg; 54 assert(ep); 57 int hc_dev_add(ddf_dev_t *); 58 int hc_dev_remove(ddf_dev_t *); 59 int hc_dev_gone(ddf_dev_t *); 60 int hc_fun_online(ddf_fun_t *); 61 int hc_fun_offline(ddf_fun_t *); 62 63 static driver_ops_t hc_driver_ops = { 64 .dev_add = hc_dev_add, 65 .dev_remove = hc_dev_remove, 66 .dev_gone = hc_dev_gone, 67 .fun_online = hc_fun_online, 68 .fun_offline = hc_fun_offline, 69 }; 70 71 static const hc_driver_t *hc_driver; 72 73 /** 74 * The main HC driver routine. 75 */ 76 int hc_driver_main(const hc_driver_t *driver) 77 { 78 driver_t ddf_driver = { 79 .name = driver->name, 80 .driver_ops = &hc_driver_ops, 81 }; 82 83 /* Remember ops to call. */ 84 hc_driver = driver; 85 86 return ddf_driver_main(&ddf_driver); 87 } 88 89 /** 90 * IRQ handling callback. Call the bus operation. 91 * 92 * Currently, there is a bus ops lookup to find the interrupt handler. So far, 93 * the mechanism is too flexible, as it allows different instances of HC to 94 * have different IRQ handlers, disallowing us to optimize the lookup here. 95 * TODO: Make the bus mechanism less flexible in irq handling and remove the 96 * lookup. 97 */ 98 static void irq_handler(ipc_call_t *call, ddf_dev_t *dev) 99 { 100 assert(dev); 101 hc_device_t *hcd = dev_to_hcd(dev); 102 103 const uint32_t status = IPC_GET_ARG1(*call); 104 hcd->bus->ops->interrupt(hcd->bus, status); 105 } 106 107 /** 108 * Worker for the HW interrupt replacement fibril. 109 */ 110 static errno_t interrupt_polling(void *arg) 111 { 112 bus_t *bus = arg; 113 assert(bus); 114 115 if (!bus->ops->interrupt || !bus->ops->status) 116 return ENOTSUP; 117 118 uint32_t status = 0; 119 while (bus->ops->status(bus, &status) == EOK) { 120 bus->ops->interrupt(bus, status); 121 status = 0; 122 /* We should wait 1 frame - 1ms here, but this polling is a 123 * lame crutch anyway so don't hog the system. 10ms is still 124 * good enough for emergency mode */ 125 async_usleep(10000); 126 } 127 return EOK; 128 } 129 130 /** 131 * Clean the IRQ code bottom-half. 132 */ 133 static inline void irq_code_clean(irq_code_t *code) 134 { 135 if (code) { 136 free(code->ranges); 137 free(code->cmds); 138 code->ranges = NULL; 139 code->cmds = NULL; 140 code->rangecount = 0; 141 code->cmdcount = 0; 142 } 143 } 144 145 /** 146 * Register an interrupt handler. If there is a callback to setup the bottom half, 147 * invoke it and register it. Register for notifications. 148 * 149 * If this method fails, a polling fibril is started instead. 150 * 151 * @param[in] hcd Host controller device. 152 * @param[in] hw_res Resources to be used. 153 * 154 * @return IRQ capability handle on success. 155 * @return Negative error code. 156 */ 157 static errno_t hcd_ddf_setup_interrupts(hc_device_t *hcd, 158 const hw_res_list_parsed_t *hw_res) 159 { 55 160 assert(hcd); 56 if (hcd->ops.ep_add_hook) 57 return hcd->ops.ep_add_hook(hcd, ep); 161 irq_code_t irq_code = { 0 }; 162 163 if (!hc_driver->irq_code_gen) 164 return ENOTSUP; 165 166 int irq; 167 errno_t ret; 168 ret = hc_driver->irq_code_gen(&irq_code, hcd, hw_res, &irq); 169 if (ret != EOK) { 170 usb_log_error("Failed to generate IRQ code: %s.", 171 str_error(irq)); 172 return irq; 173 } 174 175 /* Register handler to avoid interrupt lockup */ 176 int irq_cap; 177 ret = register_interrupt_handler(hcd->ddf_dev, irq, irq_handler, 178 &irq_code, &irq_cap); 179 irq_code_clean(&irq_code); 180 if (ret != EOK) { 181 usb_log_error("Failed to register interrupt handler: %s.", 182 str_error(irq_cap)); 183 return irq_cap; 184 } 185 186 /* Enable interrupts */ 187 ret = hcd_ddf_enable_interrupt(hcd, irq); 188 if (ret != EOK) { 189 usb_log_error("Failed to enable interrupts: %s.", 190 str_error(ret)); 191 unregister_interrupt_handler(hcd->ddf_dev, irq_cap); 192 return ret; 193 } 194 return irq_cap; 195 } 196 197 /** 198 * Initialize HC in memory of the driver. 199 * 200 * This function does all the preparatory work for hc and rh drivers: 201 * - gets device's hw resources 202 * - attempts to enable interrupts 203 * - registers interrupt handler 204 * - calls driver specific initialization 205 * - registers root hub 206 * 207 * @param device DDF instance of the device to use 208 * @return Error code 209 */ 210 errno_t hc_dev_add(ddf_dev_t *device) 211 { 212 errno_t ret = EOK; 213 assert(device); 214 215 if (!hc_driver->hc_add) { 216 usb_log_error("Driver '%s' does not support adding devices.", 217 hc_driver->name); 218 return ENOTSUP; 219 } 220 221 ret = hcd_ddf_setup_hc(device, hc_driver->hc_device_size); 222 if (ret != EOK) { 223 usb_log_error("Failed to setup HC device."); 224 return ret; 225 } 226 227 hc_device_t *hcd = dev_to_hcd(device); 228 229 hw_res_list_parsed_t hw_res; 230 ret = hcd_ddf_get_registers(hcd, &hw_res); 231 if (ret != EOK) { 232 usb_log_error("Failed to get register memory addresses " 233 "for `%s': %s.", ddf_dev_get_name(device), 234 str_error(ret)); 235 goto err_hcd; 236 } 237 238 ret = hc_driver->hc_add(hcd, &hw_res); 239 if (ret != EOK) { 240 usb_log_error("Failed to init HCD."); 241 goto err_hw_res; 242 } 243 244 assert(hcd->bus); 245 246 /* Setup interrupts */ 247 hcd->irq_cap = hcd_ddf_setup_interrupts(hcd, &hw_res); 248 if (hcd->irq_cap >= 0) { 249 usb_log_debug("Hw interrupts enabled."); 250 } 251 252 /* Claim the device from BIOS */ 253 if (hc_driver->claim) 254 ret = hc_driver->claim(hcd); 255 if (ret != EOK) { 256 usb_log_error("Failed to claim `%s' for `%s': %s", 257 ddf_dev_get_name(device), hc_driver->name, str_error(ret)); 258 goto err_irq; 259 } 260 261 /* Start hw */ 262 if (hc_driver->start) 263 ret = hc_driver->start(hcd); 264 if (ret != EOK) { 265 usb_log_error("Failed to start HCD: %s.", str_error(ret)); 266 goto err_irq; 267 } 268 269 const bus_ops_t *ops = hcd->bus->ops; 270 271 /* Need working irq replacement to setup root hub */ 272 if (hcd->irq_cap < 0 && ops->status) { 273 hcd->polling_fibril = fibril_create(interrupt_polling, hcd->bus); 274 if (!hcd->polling_fibril) { 275 usb_log_error("Failed to create polling fibril"); 276 ret = ENOMEM; 277 goto err_started; 278 } 279 fibril_add_ready(hcd->polling_fibril); 280 usb_log_warning("Failed to enable interrupts: %s." 281 " Falling back to polling.", str_error(hcd->irq_cap)); 282 } 283 284 /* 285 * Creating root hub registers a new USB device so HC 286 * needs to be ready at this time. 287 */ 288 if (hc_driver->setup_root_hub) 289 ret = hc_driver->setup_root_hub(hcd); 290 if (ret != EOK) { 291 usb_log_error("Failed to setup HC root hub: %s.", 292 str_error(ret)); 293 goto err_polling; 294 } 295 296 usb_log_info("Controlling new `%s' device `%s'.", 297 hc_driver->name, ddf_dev_get_name(device)); 58 298 return EOK; 59 } 60 61 /** Calls ep_remove_hook upon endpoint removal. 62 * @param ep Endpoint to be unregistered. 63 * @param arg hcd_t in disguise. 64 */ 65 static void unregister_helper(endpoint_t *ep, void *arg) 66 { 67 hcd_t *hcd = arg; 68 assert(ep); 69 assert(hcd); 70 if (hcd->ops.ep_remove_hook) 71 hcd->ops.ep_remove_hook(hcd, ep); 72 } 73 74 /** Calls ep_remove_hook upon endpoint removal. Prints warning. 75 * * @param ep Endpoint to be unregistered. 76 * * @param arg hcd_t in disguise. 77 * */ 78 static void unregister_helper_warn(endpoint_t *ep, void *arg) 79 { 80 assert(ep); 81 usb_log_warning("Endpoint %d:%d %s was left behind, removing.\n", 82 ep->address, ep->endpoint, usb_str_direction(ep->direction)); 83 unregister_helper(ep, arg); 84 } 85 86 87 /** Initialize hcd_t structure. 88 * Initializes device and endpoint managers. Sets data and hook pointer to NULL. 89 * 90 * @param hcd hcd_t structure to initialize, non-null. 91 * @param max_speed Maximum supported USB speed (full, high). 92 * @param bandwidth Available bandwidth, passed to endpoint manager. 93 * @param bw_count Bandwidth compute function, passed to endpoint manager. 94 */ 95 void hcd_init(hcd_t *hcd, usb_speed_t max_speed, size_t bandwidth, 96 bw_count_func_t bw_count) 97 { 98 assert(hcd); 99 usb_bus_init(&hcd->bus, bandwidth, bw_count, max_speed); 100 101 hcd_set_implementation(hcd, NULL, NULL); 102 } 103 104 errno_t hcd_request_address(hcd_t *hcd, usb_speed_t speed, usb_address_t *address) 105 { 106 assert(hcd); 107 return usb_bus_request_address(&hcd->bus, address, false, speed); 108 } 109 110 errno_t hcd_release_address(hcd_t *hcd, usb_address_t address) 111 { 112 assert(hcd); 113 return usb_bus_remove_address(&hcd->bus, address, 114 unregister_helper_warn, hcd); 115 } 116 117 errno_t hcd_reserve_default_address(hcd_t *hcd, usb_speed_t speed) 118 { 119 assert(hcd); 120 usb_address_t address = 0; 121 return usb_bus_request_address(&hcd->bus, &address, true, speed); 122 } 123 124 errno_t hcd_add_ep(hcd_t *hcd, usb_target_t target, usb_direction_t dir, 125 usb_transfer_type_t type, size_t max_packet_size, unsigned packets, 126 size_t size, usb_address_t tt_address, unsigned tt_port) 127 { 128 assert(hcd); 129 return usb_bus_add_ep(&hcd->bus, target.address, 130 target.endpoint, dir, type, max_packet_size, packets, size, 131 register_helper, hcd, tt_address, tt_port); 132 } 133 134 errno_t hcd_remove_ep(hcd_t *hcd, usb_target_t target, usb_direction_t dir) 135 { 136 assert(hcd); 137 return usb_bus_remove_ep(&hcd->bus, target.address, 138 target.endpoint, dir, unregister_helper, hcd); 139 } 140 141 142 typedef struct { 143 void *original_data; 144 usbhc_iface_transfer_out_callback_t original_callback; 145 usb_target_t target; 146 hcd_t *hcd; 147 } toggle_t; 148 149 static void toggle_reset_callback(errno_t retval, void *arg) 150 { 151 assert(arg); 152 toggle_t *toggle = arg; 153 if (retval == EOK) { 154 usb_log_debug2("Reseting toggle on %d:%d.\n", 155 toggle->target.address, toggle->target.endpoint); 156 usb_bus_reset_toggle(&toggle->hcd->bus, 157 toggle->target, toggle->target.endpoint == 0); 158 } 159 160 toggle->original_callback(retval, toggle->original_data); 161 } 162 163 /** Prepare generic usb_transfer_batch and schedule it. 164 * @param hcd Host controller driver. 165 * @param fun DDF fun 166 * @param target address and endpoint number. 167 * @param setup_data Data to use in setup stage (Control communication type) 168 * @param in Callback for device to host communication. 169 * @param out Callback for host to device communication. 170 * @param arg Callback parameter. 171 * @param name Communication identifier (for nicer output). 172 * @return Error code. 173 */ 174 errno_t hcd_send_batch( 175 hcd_t *hcd, usb_target_t target, usb_direction_t direction, 176 void *data, size_t size, uint64_t setup_data, 177 usbhc_iface_transfer_in_callback_t in, 178 usbhc_iface_transfer_out_callback_t out, void *arg, const char* name) 179 { 180 assert(hcd); 181 182 endpoint_t *ep = usb_bus_find_ep(&hcd->bus, 183 target.address, target.endpoint, direction); 184 if (ep == NULL) { 185 usb_log_error("Endpoint(%d:%d) not registered for %s.\n", 186 target.address, target.endpoint, name); 187 return ENOENT; 188 } 189 190 usb_log_debug2("%s %d:%d %zu(%zu).\n", 191 name, target.address, target.endpoint, size, ep->max_packet_size); 192 193 const size_t bw = bandwidth_count_usb11( 194 ep->speed, ep->transfer_type, size, ep->max_packet_size); 195 /* Check if we have enough bandwidth reserved */ 196 if (ep->bandwidth < bw) { 197 usb_log_error("Endpoint(%d:%d) %s needs %zu bw " 198 "but only %zu is reserved.\n", 199 ep->address, ep->endpoint, name, bw, ep->bandwidth); 200 return ENOSPC; 201 } 202 if (!hcd->ops.schedule) { 203 usb_log_error("HCD does not implement scheduler.\n"); 204 return ENOTSUP; 205 } 206 207 /* Check for commands that reset toggle bit */ 208 if (ep->transfer_type == USB_TRANSFER_CONTROL) { 209 const int reset_toggle = usb_request_needs_toggle_reset( 210 (usb_device_request_setup_packet_t *) &setup_data); 211 if (reset_toggle >= 0) { 212 assert(out); 213 toggle_t *toggle = malloc(sizeof(toggle_t)); 214 if (!toggle) 215 return ENOMEM; 216 toggle->target.address = target.address; 217 toggle->target.endpoint = reset_toggle; 218 toggle->original_callback = out; 219 toggle->original_data = arg; 220 toggle->hcd = hcd; 221 222 arg = toggle; 223 out = toggle_reset_callback; 224 } 225 } 226 227 usb_transfer_batch_t *batch = usb_transfer_batch_create( 228 ep, data, size, setup_data, in, out, arg); 229 if (!batch) { 230 usb_log_error("Failed to create transfer batch.\n"); 231 return ENOMEM; 232 } 233 234 const errno_t ret = hcd->ops.schedule(hcd, batch); 235 if (ret != EOK) 236 usb_transfer_batch_destroy(batch); 237 238 /* Drop our own reference to ep. */ 239 endpoint_del_ref(ep); 240 299 300 err_polling: 301 // TODO: Stop the polling fibril (refactor the interrupt_polling func) 302 // 303 err_started: 304 if (hc_driver->stop) 305 hc_driver->stop(hcd); 306 err_irq: 307 unregister_interrupt_handler(device, hcd->irq_cap); 308 if (hc_driver->hc_remove) 309 hc_driver->hc_remove(hcd); 310 err_hw_res: 311 hw_res_list_parsed_clean(&hw_res); 312 err_hcd: 313 hcd_ddf_clean_hc(hcd); 241 314 return ret; 242 315 } 243 316 244 typedef struct { 245 volatile unsigned done; 246 errno_t ret; 247 size_t size; 248 } sync_data_t; 249 250 static void transfer_in_cb(errno_t ret, size_t size, void* data) 251 { 252 sync_data_t *d = data; 253 assert(d); 254 d->ret = ret; 255 d->done = 1; 256 d->size = size; 257 } 258 259 static void transfer_out_cb(errno_t ret, void* data) 260 { 261 sync_data_t *d = data; 262 assert(data); 263 d->ret = ret; 264 d->done = 1; 265 } 266 267 /** this is really ugly version of sync usb communication */ 268 errno_t hcd_send_batch_sync( 269 hcd_t *hcd, usb_target_t target, usb_direction_t dir, 270 void *data, size_t size, uint64_t setup_data, const char* name, size_t *out_size) 271 { 272 assert(hcd); 273 sync_data_t sd = { .done = 0, .ret = EBUSY, .size = size }; 274 275 const errno_t ret = hcd_send_batch(hcd, target, dir, data, size, setup_data, 276 dir == USB_DIRECTION_IN ? transfer_in_cb : NULL, 277 dir == USB_DIRECTION_OUT ? transfer_out_cb : NULL, &sd, name); 278 if (ret != EOK) 279 return ret; 280 281 while (!sd.done) { 282 async_usleep(1000); 283 } 284 285 if (sd.ret == EOK) 286 *out_size = sd.size; 287 return sd.ret; 317 errno_t hc_dev_remove(ddf_dev_t *dev) 318 { 319 errno_t err; 320 hc_device_t *hcd = dev_to_hcd(dev); 321 322 if (hc_driver->stop) 323 if ((err = hc_driver->stop(hcd))) 324 return err; 325 326 unregister_interrupt_handler(dev, hcd->irq_cap); 327 328 if (hc_driver->hc_remove) 329 if ((err = hc_driver->hc_remove(hcd))) 330 return err; 331 332 hcd_ddf_clean_hc(hcd); 333 334 // TODO probably not complete 335 336 return EOK; 337 } 338 339 errno_t hc_dev_gone(ddf_dev_t *dev) 340 { 341 errno_t err = ENOTSUP; 342 hc_device_t *hcd = dev_to_hcd(dev); 343 344 if (hc_driver->hc_gone) 345 err = hc_driver->hc_gone(hcd); 346 347 hcd_ddf_clean_hc(hcd); 348 349 return err; 350 } 351 352 errno_t hc_fun_online(ddf_fun_t *fun) 353 { 354 assert(fun); 355 356 device_t *dev = ddf_fun_data_get(fun); 357 assert(dev); 358 359 usb_log_info("Device(%d): Requested to be brought online.", dev->address); 360 return bus_device_online(dev); 361 } 362 363 int hc_fun_offline(ddf_fun_t *fun) 364 { 365 assert(fun); 366 367 device_t *dev = ddf_fun_data_get(fun); 368 assert(dev); 369 370 usb_log_info("Device(%d): Requested to be taken offline.", dev->address); 371 return bus_device_offline(dev); 288 372 } 289 373 -
uspace/lib/usbhost/src/usb_transfer_batch.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 33 34 */ 34 35 35 #include <usb/host/usb_transfer_batch.h>36 #include <usb/debug.h>37 38 36 #include <assert.h> 39 37 #include <errno.h> 40 #include <macros.h>41 #include <mem.h>42 38 #include <stdlib.h> 43 #include <usbhc_iface.h> 44 45 /** Allocate and initialize usb_transfer_batch structure. 46 * @param ep endpoint used by the transfer batch. 47 * @param buffer data to send/recieve. 48 * @param buffer_size Size of data buffer. 49 * @param setup_buffer Data to send in SETUP stage of control transfer. 50 * @param func_in callback on IN transfer completion. 51 * @param func_out callback on OUT transfer completion. 52 * @param fun DDF function (passed to callback function). 53 * @param arg Argument to pass to the callback function. 54 * @param private_data driver specific per batch data. 55 * @param private_data_dtor Function to properly destroy private_data. 56 * @return Pointer to valid usb_transfer_batch_t structure, NULL on failure. 57 */ 58 usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *ep, char *buffer, 59 size_t buffer_size, 60 uint64_t setup_buffer, 61 usbhc_iface_transfer_in_callback_t func_in, 62 usbhc_iface_transfer_out_callback_t func_out, 63 void *arg) 64 { 65 if (func_in == NULL && func_out == NULL) 66 return NULL; 67 if (func_in != NULL && func_out != NULL) 68 return NULL; 69 70 usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t)); 71 if (instance) { 72 instance->ep = ep; 73 instance->callback_in = func_in; 74 instance->callback_out = func_out; 75 instance->arg = arg; 76 instance->buffer = buffer; 77 instance->buffer_size = buffer_size; 78 instance->setup_size = 0; 79 instance->transfered_size = 0; 80 instance->error = EOK; 81 if (ep && ep->transfer_type == USB_TRANSFER_CONTROL) { 82 memcpy(instance->setup_buffer, &setup_buffer, 83 USB_SETUP_PACKET_SIZE); 84 instance->setup_size = USB_SETUP_PACKET_SIZE; 39 #include <str_error.h> 40 #include <usb/debug.h> 41 42 #include "endpoint.h" 43 #include "bus.h" 44 45 #include "usb_transfer_batch.h" 46 47 /** 48 * Create a batch on a given endpoint. 49 * 50 * If the bus callback is not defined, it just creates a default batch. 51 */ 52 usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *ep) 53 { 54 assert(ep); 55 56 bus_t *bus = endpoint_get_bus(ep); 57 58 if (!bus->ops->batch_create) { 59 usb_transfer_batch_t *batch = calloc(1, sizeof(usb_transfer_batch_t)); 60 if (!batch) 61 return NULL; 62 usb_transfer_batch_init(batch, ep); 63 return batch; 64 } 65 66 return bus->ops->batch_create(ep); 67 } 68 69 /** 70 * Initialize given batch structure. 71 */ 72 void usb_transfer_batch_init(usb_transfer_batch_t *batch, endpoint_t *ep) 73 { 74 assert(ep); 75 /* Batch reference */ 76 endpoint_add_ref(ep); 77 batch->ep = ep; 78 } 79 80 /** 81 * Destroy the batch. If there's no bus callback, just free it. 82 */ 83 void usb_transfer_batch_destroy(usb_transfer_batch_t *batch) 84 { 85 assert(batch); 86 assert(batch->ep); 87 88 bus_t *bus = endpoint_get_bus(batch->ep); 89 endpoint_t *ep = batch->ep; 90 91 if (bus->ops) { 92 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " destroying.", 93 batch, USB_TRANSFER_BATCH_ARGS(*batch)); 94 bus->ops->batch_destroy(batch); 95 } 96 else { 97 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " disposing.", 98 batch, USB_TRANSFER_BATCH_ARGS(*batch)); 99 free(batch); 100 } 101 102 /* Batch reference */ 103 endpoint_del_ref(ep); 104 } 105 106 bool usb_transfer_batch_bounce_required(usb_transfer_batch_t *batch) 107 { 108 if (!batch->size) 109 return false; 110 111 unsigned flags = batch->dma_buffer.policy & DMA_POLICY_FLAGS_MASK; 112 unsigned required_flags = 113 batch->ep->required_transfer_buffer_policy & DMA_POLICY_FLAGS_MASK; 114 115 if (required_flags & ~flags) 116 return true; 117 118 size_t chunk_mask = dma_policy_chunk_mask(batch->dma_buffer.policy); 119 size_t required_chunk_mask = 120 dma_policy_chunk_mask(batch->ep->required_transfer_buffer_policy); 121 122 /* If the chunks are at least as large as required, we're good */ 123 if ((required_chunk_mask & ~chunk_mask) == 0) 124 return false; 125 126 size_t start_chunk = batch->offset & ~chunk_mask; 127 size_t end_chunk = (batch->offset + batch->size - 1) & ~chunk_mask; 128 129 /* The requested area crosses a chunk boundary */ 130 if (start_chunk != end_chunk) 131 return true; 132 133 return false; 134 } 135 136 errno_t usb_transfer_batch_bounce(usb_transfer_batch_t *batch) 137 { 138 assert(batch); 139 assert(!batch->is_bounced); 140 141 dma_buffer_release(&batch->dma_buffer); 142 143 batch->original_buffer = batch->dma_buffer.virt + batch->offset; 144 145 usb_log_debug("Batch(%p): Buffer cannot be used directly, " 146 "falling back to bounce buffer!", batch); 147 148 const errno_t err = dma_buffer_alloc_policy(&batch->dma_buffer, 149 batch->size, batch->ep->transfer_buffer_policy); 150 if (err) 151 return err; 152 153 /* Copy the data out */ 154 if (batch->dir == USB_DIRECTION_OUT) 155 memcpy(batch->dma_buffer.virt, 156 batch->original_buffer, 157 batch->size); 158 159 batch->is_bounced = true; 160 batch->offset = 0; 161 162 return err; 163 } 164 165 /** 166 * Finish a transfer batch: call handler, destroy batch, release endpoint. 167 * 168 * Call only after the batch have been scheduled && completed! 169 */ 170 void usb_transfer_batch_finish(usb_transfer_batch_t *batch) 171 { 172 assert(batch); 173 assert(batch->ep); 174 175 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " finishing.", 176 batch, USB_TRANSFER_BATCH_ARGS(*batch)); 177 178 if (batch->error == EOK && batch->size > 0) { 179 if (batch->is_bounced) { 180 /* We we're forced to use bounce buffer, copy it back */ 181 if (batch->dir == USB_DIRECTION_IN) 182 memcpy(batch->original_buffer, 183 batch->dma_buffer.virt, 184 batch->transferred_size); 185 186 dma_buffer_free(&batch->dma_buffer); 85 187 } 86 if (instance->ep) 87 endpoint_use(instance->ep); 88 } 89 return instance; 90 } 91 92 /** Correctly dispose all used data structures. 93 * 94 * @param[in] instance Batch structure to use. 95 */ 96 void usb_transfer_batch_destroy(usb_transfer_batch_t *instance) 97 { 98 if (!instance) 99 return; 100 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " disposing.\n", 101 instance, USB_TRANSFER_BATCH_ARGS(*instance)); 102 if (instance->ep) { 103 endpoint_release(instance->ep); 104 } 105 free(instance); 106 } 107 108 /** Prepare data and call the right callback. 109 * 110 * @param[in] instance Batch structure to use. 111 * @param[in] data Data to copy to the output buffer. 112 * @param[in] size Size of @p data. 113 * @param[in] error Error value to use. 114 */ 115 void usb_transfer_batch_finish_error(const usb_transfer_batch_t *instance, 116 const void *data, size_t size, errno_t error) 117 { 118 assert(instance); 119 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " finishing.\n", 120 instance, USB_TRANSFER_BATCH_ARGS(*instance)); 121 122 /* NOTE: Only one of these pointers should be set. */ 123 if (instance->callback_out) { 124 instance->callback_out(error, instance->arg); 125 } 126 127 if (instance->callback_in) { 128 /* We care about the data and there are some to copy */ 129 const size_t safe_size = min(size, instance->buffer_size); 130 if (data) { 131 memcpy(instance->buffer, data, safe_size); 188 else { 189 dma_buffer_release(&batch->dma_buffer); 132 190 } 133 instance->callback_in(error, safe_size, instance->arg); 134 } 135 } 191 } 192 193 if (batch->on_complete) { 194 const int err = batch->on_complete(batch->on_complete_data, batch->error, batch->transferred_size); 195 if (err) 196 usb_log_warning("Batch %p failed to complete: %s", 197 batch, str_error(err)); 198 } 199 200 usb_transfer_batch_destroy(batch); 201 } 202 136 203 /** 137 204 * @} -
uspace/lib/usbvirt/src/ctrltransfer.c
rf5e5f73 rdf6ded8 68 68 } 69 69 70 usb_log_debug("Control transfer: %s(%s) \n", handler->name,70 usb_log_debug("Control transfer: %s(%s)", handler->name, 71 71 usb_debug_str_buffer((uint8_t*) setup, sizeof(*setup), 0)); 72 72 errno_t rc = handler->callback(dev, setup, data, data_sent_size); -
uspace/lib/usbvirt/src/ipc_hc.c
rf5e5f73 rdf6ded8 50 50 * @param data_buffer Data buffer (DATA stage of control transfer). 51 51 * @param data_buffer_size Size of data buffer in bytes. 52 * @param data_transfer ed_size Number of actually transferred bytes.52 * @param data_transferred_size Number of actually transferred bytes. 53 53 * 54 54 * @return Error code. … … 57 57 errno_t usbvirt_ipc_send_control_read(async_sess_t *sess, void *setup_buffer, 58 58 size_t setup_buffer_size, void *data_buffer, size_t data_buffer_size, 59 size_t *data_transfer ed_size)59 size_t *data_transferred_size) 60 60 { 61 61 if (!sess) … … 77 77 } 78 78 79 errno_t rc = async_data_write_start(exch, setup_buffer, setup_buffer_size); 79 errno_t rc = async_data_write_start(exch, setup_buffer, 80 setup_buffer_size); 80 81 if (rc != EOK) { 81 82 async_exchange_end(exch); … … 85 86 86 87 ipc_call_t data_request_call; 87 aid_t data_request = async_data_read(exch, data_buffer, data_buffer_size,88 &data_request_call);88 aid_t data_request = async_data_read(exch, data_buffer, 89 data_buffer_size, &data_request_call); 89 90 90 91 async_exchange_end(exch); … … 111 112 return (errno_t) opening_request_rc; 112 113 113 if (data_transfer ed_size != NULL)114 *data_transfer ed_size = IPC_GET_ARG2(data_request_call);114 if (data_transferred_size != NULL) 115 *data_transferred_size = IPC_GET_ARG2(data_request_call); 115 116 116 117 return EOK; … … 150 151 } 151 152 152 errno_t rc = async_data_write_start(exch, setup_buffer, setup_buffer_size); 153 errno_t rc = async_data_write_start(exch, setup_buffer, 154 setup_buffer_size); 153 155 if (rc != EOK) { 154 156 async_exchange_end(exch); … … 158 160 159 161 if (data_buffer_size > 0) { 160 rc = async_data_write_start(exch, data_buffer, data_buffer_size); 162 rc = async_data_write_start(exch, data_buffer, 163 data_buffer_size); 161 164 if (rc != EOK) { 162 165 async_exchange_end(exch); -
uspace/lib/usbvirt/src/transfer.c
rf5e5f73 rdf6ded8 79 79 80 80 if (rc == EFORWARD) { 81 usb_log_warning("Control transfer {%s (%s)} not handled. \n",81 usb_log_warning("Control transfer {%s (%s)} not handled.", 82 82 usb_debug_str_buffer(setup, setup_size, 10), 83 83 setup_packet->request_type & 0x80 … … 119 119 * @return Error code. 120 120 */ 121 errno_t usbvirt_control_read(usbvirt_device_t *dev, const void *setup, size_t setup_size, 121 errno_t usbvirt_control_read(usbvirt_device_t *dev, 122 const void *setup, size_t setup_size, 122 123 void *data, size_t data_size, size_t *data_size_sent) 123 124 {
Note:
See TracChangeset
for help on using the changeset viewer.
