Changeset 84439d7 in mainline for uspace/lib/usb/src/hcdhubd.c
- Timestamp:
- 2010-12-05T09:34:46Z (13 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. - File:
-
- 1 edited
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
Note:
See TracChangeset
for help on using the changeset viewer.