Changes in uspace/lib/usbdev/src/hub.c [79ae36dd:6e3c005] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbdev/src/hub.c
r79ae36dd r6e3c005 37 37 #include <usb/dev/request.h> 38 38 #include <usb/dev/recognise.h> 39 #include <usb hc_iface.h>39 #include <usb/debug.h> 40 40 #include <errno.h> 41 41 #include <assert.h> … … 44 44 #include <async.h> 45 45 46 /** How much time to wait between attempts to register endpoint 0:0.46 /** How much time to wait between attempts to get the default address. 47 47 * The value is based on typical value for port reset + some overhead. 48 48 */ 49 #define ENDPOINT_0_0_REGISTER_ATTEMPT_DELAY_USEC (1000 * (10 + 2)) 50 51 /** Check that HC connection is alright. 52 * 53 * @param conn Connection to be checked. 54 */ 55 #define CHECK_CONNECTION(conn) \ 56 do { \ 57 assert((conn)); \ 58 if (!usb_hc_connection_is_opened((conn))) { \ 59 return ENOENT; \ 60 } \ 61 } while (false) 62 63 /** Ask host controller for free address assignment. 64 * 65 * @param connection Opened connection to host controller. 66 * @param speed Speed of the new device (device that will be assigned 67 * the returned address). 68 * @return Assigned USB address or negative error code. 69 */ 70 usb_address_t usb_hc_request_address(usb_hc_connection_t *connection, 71 usb_speed_t speed) 72 { 73 CHECK_CONNECTION(connection); 74 75 async_exch_t *exch = async_exchange_begin(connection->hc_sess); 76 77 sysarg_t address; 78 int rc = async_req_2_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), 79 IPC_M_USBHC_REQUEST_ADDRESS, speed, 80 &address); 81 82 async_exchange_end(exch); 83 84 if (rc != EOK) 85 return (usb_address_t) rc; 86 87 return (usb_address_t) address; 88 } 49 #define DEFAULT_ADDRESS_ATTEMPT_DELAY_USEC (1000 * (10 + 2)) 89 50 90 51 /** Inform host controller about new device. … … 94 55 * @return Error code. 95 56 */ 96 int usb_h c_register_device(usb_hc_connection_t *connection,97 const usb_h c_attached_device_t *attached_device)57 int usb_hub_register_device(usb_hc_connection_t *connection, 58 const usb_hub_attached_device_t *attached_device) 98 59 { 99 CHECK_CONNECTION(connection); 100 101 if (attached_device == NULL) 60 assert(connection); 61 if (attached_device == NULL || attached_device->fun == NULL) 102 62 return EBADMEM; 103 104 async_exch_t *exch = async_exchange_begin(connection->hc_sess); 105 int rc = async_req_3_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), 106 IPC_M_USBHC_BIND_ADDRESS, 107 attached_device->address, attached_device->handle); 108 async_exchange_end(exch); 109 110 return rc; 63 return usb_hc_bind_address(connection, 64 attached_device->address, attached_device->fun->handle); 111 65 } 112 66 113 /** Inform host controller about device removal. 114 * 115 * @param connection Opened connection to host controller. 116 * @param address Address of the device that is being removed. 67 /** Change address of connected device. 68 * This function automatically updates the backing connection to point to 69 * the new address. It also unregisterrs the old endpoint and registers 70 * a new one. 71 * This creates whole bunch of problems: 72 * 1. All pipes using this wire are broken because they are not 73 * registered for new address 74 * 2. All other pipes for this device are using wrong address, 75 * possibly targeting completely different device 76 * 77 * @param pipe Control endpoint pipe (session must be already started). 78 * @param new_address New USB address to be set (in native endianness). 117 79 * @return Error code. 118 80 */ 119 int usb_hc_unregister_device(usb_hc_connection_t *connection, 120 usb_address_t address) 81 static int usb_request_set_address(usb_pipe_t *pipe, usb_address_t new_address) 121 82 { 122 CHECK_CONNECTION(connection); 123 124 async_exch_t *exch = async_exchange_begin(connection->hc_sess); 125 int rc = async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), 126 IPC_M_USBHC_RELEASE_ADDRESS, address); 127 async_exchange_end(exch); 128 129 return rc; 130 } 131 132 133 static void unregister_control_endpoint_on_default_address( 134 usb_hc_connection_t *connection) 135 { 136 usb_device_connection_t dev_conn; 137 int rc = usb_device_connection_initialize_on_default_address(&dev_conn, 138 connection); 139 if (rc != EOK) { 140 return; 141 } 142 143 usb_pipe_t ctrl_pipe; 144 rc = usb_pipe_initialize_default_control(&ctrl_pipe, &dev_conn); 145 if (rc != EOK) { 146 return; 147 } 148 149 usb_pipe_unregister(&ctrl_pipe, connection); 83 if ((new_address < 0) || (new_address >= USB11_ADDRESS_MAX)) { 84 return EINVAL; 85 } 86 assert(pipe); 87 assert(pipe->wire != NULL); 88 89 const uint16_t addr = uint16_host2usb((uint16_t)new_address); 90 91 int rc = usb_control_request_set(pipe, 92 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE, 93 USB_DEVREQ_SET_ADDRESS, addr, 0, NULL, 0); 94 95 if (rc != EOK) { 96 return rc; 97 } 98 99 /* TODO: prevent others from accessing the wire now. */ 100 if (usb_pipe_unregister(pipe) != EOK) { 101 usb_log_warning( 102 "Failed to unregister the old pipe on address change.\n"); 103 } 104 /* Address changed. We can release the old one, thus 105 * allowing other to us it. */ 106 usb_hc_release_address(pipe->wire->hc_connection, pipe->wire->address); 107 108 /* The address is already changed so set it in the wire */ 109 pipe->wire->address = new_address; 110 rc = usb_pipe_register(pipe, 0); 111 if (rc != EOK) 112 return EADDRNOTAVAIL; 113 114 return EOK; 150 115 } 151 116 … … 155 120 * The @p enable_port function is expected to enable signaling on given 156 121 * port. 157 * The two arguments to it can have arbitrary meaning 158 * (the @p port_no is only a suggestion) 159 * and are not touched at all by this function 160 * (they are passed as is to the @p enable_port function). 122 * The argument can have arbitrary meaning and it is not touched at all 123 * by this function (it is passed as is to the @p enable_port function). 161 124 * 162 125 * If the @p enable_port fails (i.e. does not return EOK), the device … … 171 134 * 172 135 * @param[in] parent Parent device (i.e. the hub device). 173 * @param[in] connection Connection to host controller. 136 * @param[in] connection Connection to host controller. Must be non-null. 174 137 * @param[in] dev_speed New device speed. 175 138 * @param[in] enable_port Function for enabling signaling through the port the 176 139 * device is attached to. 177 * @param[in] port_no Port number (passed through to @p enable_port).178 140 * @param[in] arg Any data argument to @p enable_port. 179 141 * @param[out] assigned_address USB address of the device. 180 * @param[out] assigned_handle Devman handle of the new device. 181 * @param[in] dev_ops Child device ops. 142 * @param[in] dev_ops Child device ops. Will use default if not provided. 182 143 * @param[in] new_dev_data Arbitrary pointer to be stored in the child 183 * as @c driver_data. 144 * as @c driver_data. Will allocate and assign usb_hub_attached_device_t 145 * structure if NULL. 184 146 * @param[out] new_fun Storage where pointer to allocated child function 185 * will be written. 147 * will be written. Must be non-null. 186 148 * @return Error code. 149 * @retval EINVAL Either connection or new_fun is a NULL pointer. 187 150 * @retval ENOENT Connection to HC not opened. 188 151 * @retval EADDRNOTAVAIL Failed retrieving free address from host controller. … … 192 155 * request or requests for descriptors when creating match ids). 193 156 */ 194 int usb_hc_new_device_wrapper(ddf_dev_t *parent, usb_hc_connection_t *connection, 195 usb_speed_t dev_speed, 196 int (*enable_port)(int port_no, void *arg), int port_no, void *arg, 197 usb_address_t *assigned_address, devman_handle_t *assigned_handle, 157 int usb_hc_new_device_wrapper(ddf_dev_t *parent, 158 usb_hc_connection_t *hc_conn, usb_speed_t dev_speed, 159 int (*enable_port)(void *arg), void *arg, usb_address_t *assigned_address, 198 160 ddf_dev_ops_t *dev_ops, void *new_dev_data, ddf_fun_t **new_fun) 199 161 { 200 assert(connection != NULL); 201 // FIXME: this is awful, we are accessing directly the structure. 202 usb_hc_connection_t hc_conn = { 203 .hc_handle = connection->hc_handle, 204 .hc_sess = NULL 205 }; 162 if (new_fun == NULL || hc_conn == NULL) 163 return EINVAL; 206 164 207 165 int rc; … … 213 171 } 214 172 215 rc = usb_hc_connection_open(&hc_conn); 173 /* We are gona do a lot of communication better open it in advance. */ 174 rc = usb_hc_connection_open(hc_conn); 216 175 if (rc != EOK) { 217 176 return rc; 218 177 } 219 178 179 /* Request a new address. */ 180 usb_address_t dev_addr = 181 usb_hc_request_address(hc_conn, 0, false, dev_speed); 182 if (dev_addr < 0) { 183 rc = EADDRNOTAVAIL; 184 goto close_connection; 185 } 186 187 /* Initialize connection to device. */ 188 usb_device_connection_t dev_conn; 189 rc = usb_device_connection_initialize( 190 &dev_conn, hc_conn, USB_ADDRESS_DEFAULT); 191 if (rc != EOK) { 192 rc = ENOTCONN; 193 goto leave_release_free_address; 194 } 195 196 /* Initialize control pipe on default address. Don't register yet. */ 197 usb_pipe_t ctrl_pipe; 198 rc = usb_pipe_initialize_default_control(&ctrl_pipe, &dev_conn); 199 if (rc != EOK) { 200 rc = ENOTCONN; 201 goto leave_release_free_address; 202 } 220 203 221 204 /* 222 * Request new address. 223 */ 224 usb_address_t dev_addr = usb_hc_request_address(&hc_conn, dev_speed); 225 if (dev_addr < 0) { 226 usb_hc_connection_close(&hc_conn); 227 return EADDRNOTAVAIL; 228 } 229 230 /* 231 * We will not register control pipe on default address. 232 * The registration might fail. That means that someone else already 233 * registered that endpoint. We will simply wait and try again. 205 * The default address request might fail. 206 * That means that someone else is already using that address. 207 * We will simply wait and try again. 234 208 * (Someone else already wants to add a new device.) 235 209 */ 236 usb_device_connection_t dev_conn; 237 rc = usb_device_connection_initialize_on_default_address(&dev_conn, 238 &hc_conn); 210 do { 211 rc = usb_hc_request_address(hc_conn, USB_ADDRESS_DEFAULT, 212 true, dev_speed); 213 if (rc == ENOENT) { 214 /* Do not overheat the CPU ;-). */ 215 async_usleep(DEFAULT_ADDRESS_ATTEMPT_DELAY_USEC); 216 } 217 } while (rc == ENOENT); 218 if (rc < 0) { 219 goto leave_release_free_address; 220 } 221 222 /* Register control pipe on default address. 0 means no interval. */ 223 rc = usb_pipe_register(&ctrl_pipe, 0); 239 224 if (rc != EOK) { 240 225 rc = ENOTCONN; 241 goto leave_release_free_address; 242 } 243 244 usb_pipe_t ctrl_pipe; 245 rc = usb_pipe_initialize_default_control(&ctrl_pipe, 246 &dev_conn); 247 if (rc != EOK) { 248 rc = ENOTCONN; 249 goto leave_release_free_address; 250 } 251 252 do { 253 rc = usb_pipe_register_with_speed(&ctrl_pipe, dev_speed, 0, 254 &hc_conn); 255 if (rc != EOK) { 256 /* Do not overheat the CPU ;-). */ 257 async_usleep(ENDPOINT_0_0_REGISTER_ATTEMPT_DELAY_USEC); 258 } 259 } while (rc != EOK); 226 goto leave_release_default_address; 227 } 228 260 229 struct timeval end_time; 261 262 230 rc = gettimeofday(&end_time, NULL); 263 231 if (rc != EOK) { … … 270 238 * above might use much of this time so we should only wait to fill 271 239 * up the 100ms quota*/ 272 suseconds_t elapsed = tv_sub(&end_time, &start_time);240 const suseconds_t elapsed = tv_sub(&end_time, &start_time); 273 241 if (elapsed < 100000) { 274 242 async_usleep(100000 - elapsed); 275 243 } 276 244 277 /* 278 * Endpoint is registered. We can enable the port and change 279 * device address. 280 */ 281 rc = enable_port(port_no, arg); 245 /* Endpoint is registered. We can enable the port and change address. */ 246 rc = enable_port(arg); 282 247 if (rc != EOK) { 283 248 goto leave_release_default_address; … … 290 255 async_usleep(10000); 291 256 257 /* Get max_packet_size value. */ 292 258 rc = usb_pipe_probe_default_control(&ctrl_pipe); 293 259 if (rc != EOK) { … … 302 268 } 303 269 304 /* 305 * Address changed. We can release the original endpoint, thus 306 * allowing other to access the default address. 307 */ 308 unregister_control_endpoint_on_default_address(&hc_conn); 309 310 /* 311 * Time to register the new endpoint. 312 */ 313 rc = usb_pipe_register(&ctrl_pipe, 0, &hc_conn); 314 if (rc != EOK) { 315 goto leave_release_free_address; 316 } 317 318 /* 319 * It is time to register the device with devman. 320 */ 270 271 /* Register the device with devman. */ 321 272 /* FIXME: create device_register that will get opened ctrl pipe. */ 322 devman_handle_t child_handle; 323 rc = usb_device_register_child_in_devman(dev_addr, dev_conn.hc_handle, 324 parent, &child_handle, 325 dev_ops, new_dev_data, new_fun); 326 if (rc != EOK) { 327 rc = ESTALL; 328 goto leave_release_free_address; 329 } 330 331 /* 332 * And now inform the host controller about the handle. 333 */ 334 usb_hc_attached_device_t new_device = { 273 ddf_fun_t *child_fun; 274 rc = usb_device_register_child_in_devman(&ctrl_pipe, 275 parent, dev_ops, new_dev_data, &child_fun); 276 if (rc != EOK) { 277 goto leave_release_free_address; 278 } 279 280 const usb_hub_attached_device_t new_device = { 335 281 .address = dev_addr, 336 . handle = child_handle282 .fun = child_fun, 337 283 }; 338 rc = usb_hc_register_device(&hc_conn, &new_device); 339 if (rc != EOK) { 284 285 286 /* Inform the host controller about the handle. */ 287 rc = usb_hub_register_device(hc_conn, &new_device); 288 if (rc != EOK) { 289 /* We know nothing about that data. */ 290 if (new_dev_data) 291 child_fun->driver_data = NULL; 292 /* The child function is already created. */ 293 ddf_fun_destroy(child_fun); 340 294 rc = EDESTADDRREQ; 341 295 goto leave_release_free_address; 342 296 } 343 344 usb_hc_connection_close(&hc_conn); 345 346 /* 347 * And we are done. 348 */ 297 349 298 if (assigned_address != NULL) { 350 299 *assigned_address = dev_addr; 351 300 } 352 if (assigned_handle != NULL) { 353 *assigned_handle = child_handle; 354 } 355 356 return EOK; 357 358 301 302 *new_fun = child_fun; 303 304 rc = EOK; 305 goto close_connection; 359 306 360 307 /* … … 363 310 */ 364 311 leave_release_default_address: 365 usb_pipe_unregister(&ctrl_pipe, &hc_conn); 312 if (usb_hc_release_address(hc_conn, USB_ADDRESS_DEFAULT) != EOK) 313 usb_log_warning("%s: Failed to release defaut address.\n", 314 __FUNCTION__); 366 315 367 316 leave_release_free_address: 368 usb_hc_unregister_device(&hc_conn, dev_addr); 369 370 usb_hc_connection_close(&hc_conn); 317 /* This might be either 0:0 or dev_addr:0 */ 318 if (usb_pipe_unregister(&ctrl_pipe) != EOK) 319 usb_log_warning("%s: Failed to unregister default pipe.\n", 320 __FUNCTION__); 321 322 if (usb_hc_release_address(hc_conn, dev_addr) != EOK) 323 usb_log_warning("%s: Failed to release address: %d.\n", 324 __FUNCTION__, dev_addr); 325 326 close_connection: 327 if (usb_hc_connection_close(hc_conn) != EOK) 328 usb_log_warning("%s: Failed to close hc connection.\n", 329 __FUNCTION__); 371 330 372 331 return rc;
Note:
See TracChangeset
for help on using the changeset viewer.