Changeset 84439d7 in mainline for uspace/lib/usb/src
- Timestamp:
- 2010-12-05T09:34:46Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 75732da
- Parents:
- 56b962d (diff), 35537a7 (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. - Location:
- uspace/lib/usb/src
- Files:
-
- 3 added
- 3 edited
-
hcdhubd.c (modified) (5 diffs)
-
hcdhubd_private.h (added)
-
hcdrv.c (added)
-
localdrv.c (modified) (1 diff)
-
remotedrv.c (added)
-
usbdrv.c (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usb/src/hcdhubd.c
r56b962d r84439d7 31 31 */ 32 32 /** @file 33 * @brief HC driver and hub driver (implementation).33 * @brief Common stuff for both HC driver and hub driver. 34 34 */ 35 35 #include <usb/hcdhubd.h> 36 36 #include <usb/devreq.h> 37 37 #include <usbhc_iface.h> 38 #include <usb/descriptor.h> 38 39 #include <driver.h> 39 40 #include <bool.h> 40 41 #include <errno.h> 41 42 #define USB_HUB_DEVICE_NAME "usbhub" 43 44 /** List of handled host controllers. */ 45 static LIST_INITIALIZE(hc_list); 46 47 /** Our HC driver. */ 48 static usb_hc_driver_t *hc_driver = NULL; 49 50 static usbhc_iface_t usb_interface = { 51 .interrupt_out = NULL, 52 .interrupt_in = NULL 53 }; 54 55 static device_ops_t usb_device_ops = { 56 .interfaces[USBHC_DEV_IFACE] = &usb_interface 57 }; 58 59 static void set_hub_address(usb_hc_device_t *hc, usb_address_t address); 42 #include <str_error.h> 43 #include <usb/classes/hub.h> 44 45 #include "hcdhubd_private.h" 60 46 61 47 /** Callback when new device is detected and must be handled by this driver. … … 64 50 * @return Error code. 65 51 */ 66 static int add_device(device_t *dev) 67 { 68 /* 69 * FIXME: use some magic to determine whether hub or another HC 70 * was connected. 71 */ 72 bool is_hc = str_cmp(dev->name, USB_HUB_DEVICE_NAME) != 0; 73 printf("%s: add_device(name=\"%s\")\n", hc_driver->name, dev->name); 74 75 if (is_hc) { 76 /* 77 * We are the HC itself. 78 */ 79 usb_hc_device_t *hc_dev = malloc(sizeof(usb_hc_device_t)); 80 list_initialize(&hc_dev->link); 81 hc_dev->transfer_ops = NULL; 82 83 hc_dev->generic = dev; 84 dev->ops = &usb_device_ops; 85 hc_dev->generic->driver_data = hc_dev; 86 87 int rc = hc_driver->add_hc(hc_dev); 88 if (rc != EOK) { 89 free(hc_dev); 90 return rc; 91 } 92 93 /* 94 * FIXME: The following line causes devman to hang. 95 * Will investigate later why. 96 */ 97 // add_device_to_class(dev, "usbhc"); 98 99 list_append(&hc_dev->link, &hc_list); 100 101 return EOK; 102 } else { 103 usb_hc_device_t *hc = list_get_instance(hc_list.next, usb_hc_device_t, link); 104 set_hub_address(hc, 5); 105 106 /* 107 * We are some (probably deeply nested) hub. 108 * Thus, assign our own operations and explore already 109 * connected devices. 110 */ 111 112 return ENOTSUP; 113 } 114 } 115 116 /** Sample usage of usb_hc_async functions. 117 * This function sets hub address using standard SET_ADDRESS request. 118 * 119 * @warning This function shall be removed once you are familiar with 120 * the usb_hc_ API. 121 * 122 * @param hc Host controller the hub belongs to. 123 * @param address New hub address. 124 */ 125 static void set_hub_address(usb_hc_device_t *hc, usb_address_t address) 126 { 127 printf("%s: setting hub address to %d\n", hc->generic->name, address); 128 usb_target_t target = {0, 0}; 129 usb_handle_t handle; 130 int rc; 131 132 usb_device_request_setup_packet_t setup_packet = { 133 .request_type = 0, 134 .request = USB_DEVREQ_SET_ADDRESS, 135 .index = 0, 136 .length = 0, 137 }; 138 setup_packet.value = address; 139 140 rc = usb_hc_async_control_write_setup(hc, target, 141 &setup_packet, sizeof(setup_packet), &handle); 142 if (rc != EOK) { 143 return; 144 } 145 146 rc = usb_hc_async_wait_for(handle); 147 if (rc != EOK) { 148 return; 149 } 150 151 rc = usb_hc_async_control_write_status(hc, target, &handle); 152 if (rc != EOK) { 153 return; 154 } 155 156 rc = usb_hc_async_wait_for(handle); 157 if (rc != EOK) { 158 return; 159 } 160 161 printf("%s: hub address changed\n", hc->generic->name); 162 } 163 164 /** Check changes on all known hubs. 165 */ 166 static void check_hub_changes(void) 167 { 168 /* 169 * Iterate through all HCs. 170 */ 171 link_t *link_hc; 172 for (link_hc = hc_list.next; 173 link_hc != &hc_list; 174 link_hc = link_hc->next) { 175 usb_hc_device_t *hc = list_get_instance(link_hc, 176 usb_hc_device_t, link); 177 /* 178 * Iterate through all their hubs. 179 */ 180 link_t *link_hub; 181 for (link_hub = hc->hubs.next; 182 link_hub != &hc->hubs; 183 link_hub = link_hub->next) { 184 usb_hcd_hub_info_t *hub = list_get_instance(link_hub, 185 usb_hcd_hub_info_t, link); 186 187 /* 188 * Check status change pipe of this hub. 189 */ 190 usb_target_t target = { 191 .address = hub->device->address, 192 .endpoint = 1 193 }; 194 195 // FIXME: count properly 196 size_t byte_length = (hub->port_count / 8) + 1; 197 198 void *change_bitmap = malloc(byte_length); 199 size_t actual_size; 200 usb_handle_t handle; 201 202 /* 203 * Send the request. 204 * FIXME: check returned value for possible errors 205 */ 206 usb_hc_async_interrupt_in(hc, target, 207 change_bitmap, byte_length, &actual_size, 208 &handle); 209 210 usb_hc_async_wait_for(handle); 211 212 /* 213 * TODO: handle the changes. 214 */ 215 } 216 } 52 static int add_device(device_t *dev) { 53 return ENOTSUP; 217 54 } 218 55 … … 234 71 * @return Error code. 235 72 */ 236 int usb_hcd_main(usb_hc_driver_t *hc) 237 { 73 int usb_hcd_main(usb_hc_driver_t *hc) { 238 74 hc_driver = hc; 239 75 hc_driver_generic.name = hc->name; 240 241 /*242 * Launch here fibril that will periodically check all243 * attached hubs for status change.244 * WARN: This call will effectively do nothing.245 */246 check_hub_changes();247 76 248 77 /* … … 261 90 * @return Error code. 262 91 */ 263 int usb_hcd_add_root_hub( usb_hc_device_t *dev)92 int usb_hcd_add_root_hub(device_t *dev) 264 93 { 94 char *id; 95 int rc = asprintf(&id, "usb&hub"); 96 if (rc <= 0) { 97 return rc; 98 } 99 100 rc = usb_hc_add_child_device(dev, USB_HUB_DEVICE_NAME, id, true); 101 if (rc != EOK) { 102 free(id); 103 } 104 105 return rc; 106 } 107 108 /** Info about child device. */ 109 struct child_device_info { 110 device_t *parent; 111 const char *name; 112 const char *match_id; 113 }; 114 115 /** Adds a child device fibril worker. */ 116 static int fibril_add_child_device(void *arg) { 117 struct child_device_info *child_info 118 = (struct child_device_info *) arg; 265 119 int rc; 266 120 267 /* 268 * Announce presence of child device. 269 */ 270 device_t *hub = NULL; 121 async_usleep(1000); 122 123 device_t *child = create_device(); 271 124 match_id_t *match_id = NULL; 272 125 273 hub = create_device(); 274 if (hub == NULL) { 126 if (child == NULL) { 275 127 rc = ENOMEM; 276 128 goto failure; 277 129 } 278 hub->name = USB_HUB_DEVICE_NAME;130 child->name = child_info->name; 279 131 280 132 match_id = create_match_id(); … … 283 135 goto failure; 284 136 } 285 286 char *id; 287 rc = asprintf(&id, "usb&hc=%s&hub", dev->generic->name); 288 if (rc <= 0) { 289 rc = ENOMEM; 290 goto failure; 291 } 292 293 match_id->id = id; 294 match_id->score = 30; 295 296 add_match_id(&hub->match_ids, match_id); 297 298 rc = child_device_register(hub, dev->generic); 137 match_id->id = child_info->match_id; 138 match_id->score = 10; 139 add_match_id(&child->match_ids, match_id); 140 141 printf("%s: adding child device `%s' with match \"%s\"\n", 142 hc_driver->name, child->name, match_id->id); 143 rc = child_device_register(child, child_info->parent); 144 printf("%s: child device `%s' registration: %s\n", 145 hc_driver->name, child->name, str_error(rc)); 146 299 147 if (rc != EOK) { 300 148 goto failure; 301 149 } 302 150 303 printf("%s: registered root hub\n", dev->generic->name); 151 goto leave; 152 153 failure: 154 if (child != NULL) { 155 child->name = NULL; 156 delete_device(child); 157 } 158 159 if (match_id != NULL) { 160 match_id->id = NULL; 161 delete_match_id(match_id); 162 } 163 164 leave: 165 free(arg); 304 166 return EOK; 305 306 failure: 307 if (hub != NULL) { 308 hub->name = NULL; 309 delete_device(hub); 310 } 311 delete_match_id(match_id); 312 313 return rc; 167 } 168 169 /** Adds a child. 170 * Due to deadlock in devman when parent registers child that oughts to be 171 * driven by the same task, the child adding is done in separate fibril. 172 * Not optimal, but it works. 173 * Update: not under all circumstances the new fibril is successful either. 174 * Thus the last parameter to let the caller choose. 175 * 176 * @param parent Parent device. 177 * @param name Device name. 178 * @param match_id Match id. 179 * @param create_fibril Whether to run the addition in new fibril. 180 * @return Error code. 181 */ 182 int usb_hc_add_child_device(device_t *parent, const char *name, 183 const char *match_id, bool create_fibril) { 184 printf("%s: about to add child device `%s' (%s)\n", hc_driver->name, 185 name, match_id); 186 187 /* 188 * Seems that creating fibril which postpones the action 189 * is the best solution. 190 */ 191 create_fibril = true; 192 193 struct child_device_info *child_info 194 = malloc(sizeof (struct child_device_info)); 195 196 child_info->parent = parent; 197 child_info->name = name; 198 child_info->match_id = match_id; 199 200 if (create_fibril) { 201 fid_t fibril = fibril_create(fibril_add_child_device, child_info); 202 if (!fibril) { 203 return ENOMEM; 204 } 205 fibril_add_ready(fibril); 206 } else { 207 fibril_add_child_device(child_info); 208 } 209 210 return EOK; 211 } 212 213 /** Tell USB address of given device. 214 * 215 * @param handle Devman handle of the device. 216 * @return USB device address or error code. 217 */ 218 usb_address_t usb_get_address_by_handle(devman_handle_t handle) { 219 /* TODO: search list of attached devices. */ 220 return ENOENT; 221 } 222 223 usb_address_t usb_use_free_address(usb_hc_device_t * this_hcd) { 224 //is there free address? 225 link_t * addresses = &this_hcd->addresses; 226 if (list_empty(addresses)) return -1; 227 link_t * link_addr = addresses; 228 bool found = false; 229 usb_address_list_t * range = NULL; 230 while (!found) { 231 link_addr = link_addr->next; 232 if (link_addr == addresses) return -2; 233 range = list_get_instance(link_addr, 234 usb_address_list_t, link); 235 if (range->upper_bound - range->lower_bound > 0) { 236 found = true; 237 } 238 } 239 //now we have interval 240 int result = range->lower_bound; 241 ++(range->lower_bound); 242 if (range->upper_bound - range->lower_bound == 0) { 243 list_remove(&range->link); 244 free(range); 245 } 246 return result; 247 } 248 249 void usb_free_used_address(usb_hc_device_t * this_hcd, usb_address_t addr) { 250 //check range 251 if (addr < usb_lowest_address || addr > usb_highest_address) 252 return; 253 link_t * addresses = &this_hcd->addresses; 254 link_t * link_addr = addresses; 255 //find 'good' interval 256 usb_address_list_t * found_range = NULL; 257 bool found = false; 258 while (!found) { 259 link_addr = link_addr->next; 260 if (link_addr == addresses) { 261 found = true; 262 } else { 263 usb_address_list_t * range = list_get_instance(link_addr, 264 usb_address_list_t, link); 265 if ( (range->lower_bound - 1 == addr) || 266 (range->upper_bound == addr)) { 267 found = true; 268 found_range = range; 269 } 270 if (range->lower_bound - 1 > addr) { 271 found = true; 272 } 273 274 } 275 } 276 if (found_range == NULL) { 277 //no suitable range found 278 usb_address_list_t * result_range = 279 (usb_address_list_t*) malloc(sizeof (usb_address_list_t)); 280 result_range->lower_bound = addr; 281 result_range->upper_bound = addr + 1; 282 list_insert_before(&result_range->link, link_addr); 283 } else { 284 //we have good range 285 if (found_range->lower_bound - 1 == addr) { 286 --found_range->lower_bound; 287 } else { 288 //only one possible case 289 ++found_range->upper_bound; 290 if (found_range->link.next != addresses) { 291 usb_address_list_t * next_range = 292 list_get_instance( &found_range->link.next, 293 usb_address_list_t, link); 294 //check neighbour range 295 if (next_range->lower_bound == addr + 1) { 296 //join ranges 297 found_range->upper_bound = next_range->upper_bound; 298 list_remove(&next_range->link); 299 free(next_range); 300 } 301 } 302 } 303 } 304 314 305 } 315 306 -
uspace/lib/usb/src/localdrv.c
r56b962d r84439d7 39 39 #include <errno.h> 40 40 41 /** Find host controller when handled by current task. 42 * 43 * @param dev Device asking for connection. 44 * @return Device structure corresponding to parent host controller. 45 * @retval NULL Corresponding host controller not found. 46 */ 47 device_t *usb_hc_connect(device_t *dev) 48 { 49 /* 50 * FIXME: this will not work when some hub on the path is 51 * not driven by the same task. 52 */ 53 device_t *parent = dev; 54 while (parent->parent != NULL) { 55 parent = parent->parent; 56 } 57 58 if (dev == parent) { 59 printf("FIXME in %s:%d encountered!\n", __FILE__, __LINE__); 60 parent = NULL; 61 } 62 63 return parent; 64 } 65 41 66 /** Information about pending transaction on HC. */ 42 67 typedef struct { -
uspace/lib/usb/src/usbdrv.c
r56b962d r84439d7 55 55 /** Connect to host controller the device is physically attached to. 56 56 * 57 * @param handle Device handle.57 * @param dev Device asking for connection. 58 58 * @param flags Connection flags (blocking connection). 59 59 * @return Phone to corresponding HC or error code. … … 64 64 * Call parent hub to obtain device handle of respective HC. 65 65 */ 66 return ENOTSUP; 66 67 /* 68 * FIXME: currently we connect always to virtual host controller. 69 */ 70 int rc; 71 devman_handle_t handle; 72 73 rc = devman_device_get_handle("/vhc", &handle, 0); 74 if (rc != EOK) { 75 return rc; 76 } 77 78 int phone = devman_device_connect(handle, 0); 79 80 return phone; 67 81 } 68 82 … … 75 89 usb_address_t usb_drv_get_my_address(int phone, device_t *dev) 76 90 { 77 return ENOTSUP; 91 ipcarg_t address; 92 int rc = async_req_1_1(phone, IPC_M_USBHC_GET_ADDRESS, 93 dev->handle, &address); 94 95 if (rc != EOK) { 96 return rc; 97 } 98 99 return (usb_address_t) address; 100 } 101 102 /** Tell HC to reserve default address. 103 * 104 * @param phone Open phone to host controller driver. 105 * @return Error code. 106 */ 107 int usb_drv_reserve_default_address(int phone) 108 { 109 return async_req_0_0(phone, IPC_M_USBHC_RESERVE_DEFAULT_ADDRESS); 110 } 111 112 /** Tell HC to release default address. 113 * 114 * @param phone Open phone to host controller driver. 115 * @return Error code. 116 */ 117 int usb_drv_release_default_address(int phone) 118 { 119 return async_req_0_0(phone, IPC_M_USBHC_RELEASE_DEFAULT_ADDRESS); 120 } 121 122 /** Ask HC for free address assignment. 123 * 124 * @param phone Open phone to host controller driver. 125 * @return Assigned USB address or negative error code. 126 */ 127 usb_address_t usb_drv_request_address(int phone) 128 { 129 ipcarg_t address; 130 int rc = async_req_0_1(phone, IPC_M_USBHC_REQUEST_ADDRESS, &address); 131 if (rc != EOK) { 132 return rc; 133 } else { 134 return (usb_address_t) address; 135 } 136 } 137 138 /** Inform HC about binding address with devman handle. 139 * 140 * @param phone Open phone to host controller driver. 141 * @param address Address to be binded. 142 * @param handle Devman handle of the device. 143 * @return Error code. 144 */ 145 int usb_drv_bind_address(int phone, usb_address_t address, 146 devman_handle_t handle) 147 { 148 int rc = async_req_2_0(phone, IPC_M_USBHC_BIND_ADDRESS, 149 address, handle); 150 151 return rc; 152 } 153 154 /** Inform HC about address release. 155 * 156 * @param phone Open phone to host controller driver. 157 * @param address Address to be released. 158 * @return Error code. 159 */ 160 int usb_drv_release_address(int phone, usb_address_t address) 161 { 162 return async_req_1_0(phone, IPC_M_USBHC_RELEASE_ADDRESS, address); 78 163 } 79 164 … … 323 408 } 324 409 410 /** Start control write transfer. */ 411 int usb_drv_async_control_write_setup(int phone, usb_target_t target, 412 void *buffer, size_t size, 413 usb_handle_t *handle) 414 { 415 return async_send_buffer(phone, 416 IPC_M_USBHC_CONTROL_WRITE_SETUP, 417 target, 418 buffer, size, 419 handle); 420 } 421 422 /** Send data during control write transfer. */ 423 int usb_drv_async_control_write_data(int phone, usb_target_t target, 424 void *buffer, size_t size, 425 usb_handle_t *handle) 426 { 427 return async_send_buffer(phone, 428 IPC_M_USBHC_CONTROL_WRITE_DATA, 429 target, 430 buffer, size, 431 handle); 432 } 433 434 /** Finalize control write transfer. */ 435 int usb_drv_async_control_write_status(int phone, usb_target_t target, 436 usb_handle_t *handle) 437 { 438 return async_recv_buffer(phone, 439 IPC_M_USBHC_CONTROL_WRITE_STATUS, 440 target, 441 NULL, 0, NULL, 442 handle); 443 } 444 445 /** Start control read transfer. */ 446 int usb_drv_async_control_read_setup(int phone, usb_target_t target, 447 void *buffer, size_t size, 448 usb_handle_t *handle) 449 { 450 return async_send_buffer(phone, 451 IPC_M_USBHC_CONTROL_READ_SETUP, 452 target, 453 buffer, size, 454 handle); 455 } 456 457 /** Read data during control read transfer. */ 458 int usb_drv_async_control_read_data(int phone, usb_target_t target, 459 void *buffer, size_t size, size_t *actual_size, 460 usb_handle_t *handle) 461 { 462 return async_recv_buffer(phone, 463 IPC_M_USBHC_CONTROL_READ_DATA, 464 target, 465 buffer, size, actual_size, 466 handle); 467 } 468 469 /** Finalize control read transfer. */ 470 int usb_drv_async_control_read_status(int phone, usb_target_t target, 471 usb_handle_t *handle) 472 { 473 return async_send_buffer(phone, 474 IPC_M_USBHC_CONTROL_READ_STATUS, 475 target, 476 NULL, 0, 477 handle); 478 } 479 325 480 /** 326 481 * @}
Note:
See TracChangeset
for help on using the changeset viewer.
