Changes in uspace/lib/usb/src/hcdhubd.c [8f62b0f:4317827] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usb/src/hcdhubd.c
r8f62b0f r4317827 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) 264 { 92 int usb_hcd_add_root_hub(device_t *dev) 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 { 118 struct child_device_info *child_info 119 = (struct child_device_info *) arg; 265 120 int rc; 266 121 267 /* 268 * Announce presence of child device. 269 */ 270 device_t *hub = NULL; 122 async_usleep(1000); 123 124 device_t *child = create_device(); 271 125 match_id_t *match_id = NULL; 272 126 273 hub = create_device(); 274 if (hub == NULL) { 127 if (child == NULL) { 275 128 rc = ENOMEM; 276 129 goto failure; 277 130 } 278 hub->name = USB_HUB_DEVICE_NAME;131 child->name = child_info->name; 279 132 280 133 match_id = create_match_id(); … … 283 136 goto failure; 284 137 } 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); 138 match_id->id = child_info->match_id; 139 match_id->score = 10; 140 add_match_id(&child->match_ids, match_id); 141 142 printf("%s: adding child device `%s' with match \"%s\"\n", 143 hc_driver->name, child->name, match_id->id); 144 rc = child_device_register(child, child_info->parent); 145 printf("%s: child device `%s' registration: %s\n", 146 hc_driver->name, child->name, str_error(rc)); 147 299 148 if (rc != EOK) { 300 149 goto failure; 301 150 } 302 151 303 printf("%s: registered root hub\n", dev->generic->name); 152 goto leave; 153 154 failure: 155 if (child != NULL) { 156 child->name = NULL; 157 delete_device(child); 158 } 159 160 if (match_id != NULL) { 161 match_id->id = NULL; 162 delete_match_id(match_id); 163 } 164 165 leave: 166 free(arg); 304 167 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; 168 } 169 170 /** Adds a child. 171 * Due to deadlock in devman when parent registers child that oughts to be 172 * driven by the same task, the child adding is done in separate fibril. 173 * Not optimal, but it works. 174 * Update: not under all circumstances the new fibril is successful either. 175 * Thus the last parameter to let the caller choose. 176 * 177 * @param parent Parent device. 178 * @param name Device name. 179 * @param match_id Match id. 180 * @param create_fibril Whether to run the addition in new fibril. 181 * @return Error code. 182 */ 183 int usb_hc_add_child_device(device_t *parent, const char *name, 184 const char *match_id, bool create_fibril) 185 { 186 printf("%s: about to add child device `%s' (%s)\n", hc_driver->name, 187 name, match_id); 188 189 /* 190 * Seems that creating fibril which postpones the action 191 * is the best solution. 192 */ 193 create_fibril = true; 194 195 struct child_device_info *child_info 196 = malloc(sizeof(struct child_device_info)); 197 198 child_info->parent = parent; 199 child_info->name = name; 200 child_info->match_id = match_id; 201 202 if (create_fibril) { 203 fid_t fibril = fibril_create(fibril_add_child_device, child_info); 204 if (!fibril) { 205 return ENOMEM; 206 } 207 fibril_add_ready(fibril); 208 } else { 209 fibril_add_child_device(child_info); 210 } 211 212 return EOK; 213 } 214 215 /** Tell USB address of given device. 216 * 217 * @param handle Devman handle of the device. 218 * @return USB device address or error code. 219 */ 220 usb_address_t usb_get_address_by_handle(devman_handle_t handle) 221 { 222 /* TODO: search list of attached devices. */ 223 return ENOENT; 314 224 } 315 225
Note:
See TracChangeset
for help on using the changeset viewer.