Changes in uspace/lib/usb/src/recognise.c [b207803:3f0ef89d] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usb/src/recognise.c
rb207803 r3f0ef89d 27 27 */ 28 28 29 /** @addtogroup libusb usb29 /** @addtogroup libusb 30 30 * @{ 31 31 */ … … 33 33 * @brief Functions for recognising kind of attached devices. 34 34 */ 35 #include <usb_iface.h> 36 #include <usb/usbdrv.h> 35 #include <sys/types.h> 36 #include <fibril_synch.h> 37 #include <usb/pipes.h> 38 #include <usb/recognise.h> 39 #include <usb/ddfiface.h> 40 #include <usb/request.h> 37 41 #include <usb/classes/classes.h> 38 42 #include <stdio.h> 39 43 #include <errno.h> 40 41 static int usb_iface_get_hc_handle(device_t *dev, devman_handle_t *handle) 42 { 43 assert(dev); 44 assert(dev->parent != NULL); 45 46 device_t *parent = dev->parent; 47 48 if (parent->ops && parent->ops->interfaces[USB_DEV_IFACE]) { 49 usb_iface_t *usb_iface 50 = (usb_iface_t *) parent->ops->interfaces[USB_DEV_IFACE]; 51 assert(usb_iface != NULL); 52 if (usb_iface->get_hc_handle) { 53 int rc = usb_iface->get_hc_handle(parent, handle); 54 return rc; 55 } 56 } 57 58 return ENOTSUP; 59 } 60 61 static usb_iface_t usb_iface = { 62 .get_hc_handle = usb_iface_get_hc_handle 63 }; 64 65 static device_ops_t child_ops = { 66 .interfaces[USB_DEV_IFACE] = &usb_iface 44 #include <assert.h> 45 46 static size_t device_name_index = 0; 47 static FIBRIL_MUTEX_INITIALIZE(device_name_index_mutex); 48 49 ddf_dev_ops_t child_ops = { 50 .interfaces[USB_DEV_IFACE] = &usb_iface_hub_child_impl 67 51 }; 68 52 … … 129 113 } 130 114 115 #define ADD_MATCHID_OR_RETURN(match_ids, score, format, ...) \ 116 do { \ 117 int __rc = usb_add_match_id((match_ids), (score), \ 118 format, ##__VA_ARGS__); \ 119 if (__rc != EOK) { \ 120 return __rc; \ 121 } \ 122 } while (0) 123 124 /** Create device match ids based on its interface. 125 * 126 * @param[in] descriptor Interface descriptor. 127 * @param[out] matches Initialized list of match ids. 128 * @return Error code (the two mentioned are not the only ones). 129 * @retval EINVAL Invalid input parameters (expects non NULL pointers). 130 * @retval ENOENT Interface does not specify class. 131 */ 132 int usb_device_create_match_ids_from_interface( 133 const usb_standard_device_descriptor_t *desc_device, 134 const usb_standard_interface_descriptor_t *desc_interface, 135 match_id_list_t *matches) 136 { 137 if (desc_interface == NULL) { 138 return EINVAL; 139 } 140 if (matches == NULL) { 141 return EINVAL; 142 } 143 144 if (desc_interface->interface_class == USB_CLASS_USE_INTERFACE) { 145 return ENOENT; 146 } 147 148 const char *classname = usb_str_class(desc_interface->interface_class); 149 assert(classname != NULL); 150 151 #define IFACE_PROTOCOL_FMT "interface&class=%s&subclass=0x%02x&protocol=0x%02x" 152 #define IFACE_PROTOCOL_ARGS classname, desc_interface->interface_subclass, \ 153 desc_interface->interface_protocol 154 155 #define IFACE_SUBCLASS_FMT "interface&class=%s&subclass=0x%02x" 156 #define IFACE_SUBCLASS_ARGS classname, desc_interface->interface_subclass 157 158 #define IFACE_CLASS_FMT "interface&class=%s" 159 #define IFACE_CLASS_ARGS classname 160 161 #define VENDOR_RELEASE_FMT "vendor=0x%04x&product=0x%04x&release=" BCD_FMT 162 #define VENDOR_RELEASE_ARGS desc_device->vendor_id, desc_device->product_id, \ 163 BCD_ARGS(desc_device->device_version) 164 165 #define VENDOR_PRODUCT_FMT "vendor=0x%04x&product=0x%04x" 166 #define VENDOR_PRODUCT_ARGS desc_device->vendor_id, desc_device->product_id 167 168 #define VENDOR_ONLY_FMT "vendor=0x%04x" 169 #define VENDOR_ONLY_ARGS desc_device->vendor_id 170 171 /* 172 * If the vendor is specified, create match ids with vendor with 173 * higher score. 174 * Then the same ones without the vendor part. 175 */ 176 if ((desc_device != NULL) && (desc_device->vendor_id != 0)) { 177 /* First, interface matches with device release number. */ 178 ADD_MATCHID_OR_RETURN(matches, 250, 179 "usb&" VENDOR_RELEASE_FMT "&" IFACE_PROTOCOL_FMT, 180 VENDOR_RELEASE_ARGS, IFACE_PROTOCOL_ARGS); 181 ADD_MATCHID_OR_RETURN(matches, 240, 182 "usb&" VENDOR_RELEASE_FMT "&" IFACE_SUBCLASS_FMT, 183 VENDOR_RELEASE_ARGS, IFACE_SUBCLASS_ARGS); 184 ADD_MATCHID_OR_RETURN(matches, 230, 185 "usb&" VENDOR_RELEASE_FMT "&" IFACE_CLASS_FMT, 186 VENDOR_RELEASE_ARGS, IFACE_CLASS_ARGS); 187 188 /* Next, interface matches without release number. */ 189 ADD_MATCHID_OR_RETURN(matches, 220, 190 "usb&" VENDOR_PRODUCT_FMT "&" IFACE_PROTOCOL_FMT, 191 VENDOR_PRODUCT_ARGS, IFACE_PROTOCOL_ARGS); 192 ADD_MATCHID_OR_RETURN(matches, 210, 193 "usb&" VENDOR_PRODUCT_FMT "&" IFACE_SUBCLASS_FMT, 194 VENDOR_PRODUCT_ARGS, IFACE_SUBCLASS_ARGS); 195 ADD_MATCHID_OR_RETURN(matches, 200, 196 "usb&" VENDOR_PRODUCT_FMT "&" IFACE_CLASS_FMT, 197 VENDOR_PRODUCT_ARGS, IFACE_CLASS_ARGS); 198 199 /* Finally, interface matches with only vendor. */ 200 ADD_MATCHID_OR_RETURN(matches, 190, 201 "usb&" VENDOR_ONLY_FMT "&" IFACE_PROTOCOL_FMT, 202 VENDOR_ONLY_ARGS, IFACE_PROTOCOL_ARGS); 203 ADD_MATCHID_OR_RETURN(matches, 180, 204 "usb&" VENDOR_ONLY_FMT "&" IFACE_SUBCLASS_FMT, 205 VENDOR_ONLY_ARGS, IFACE_SUBCLASS_ARGS); 206 ADD_MATCHID_OR_RETURN(matches, 170, 207 "usb&" VENDOR_ONLY_FMT "&" IFACE_CLASS_FMT, 208 VENDOR_ONLY_ARGS, IFACE_CLASS_ARGS); 209 } 210 211 /* Now, the same but without any vendor specification. */ 212 ADD_MATCHID_OR_RETURN(matches, 160, 213 "usb&" IFACE_PROTOCOL_FMT, 214 IFACE_PROTOCOL_ARGS); 215 ADD_MATCHID_OR_RETURN(matches, 150, 216 "usb&" IFACE_SUBCLASS_FMT, 217 IFACE_SUBCLASS_ARGS); 218 ADD_MATCHID_OR_RETURN(matches, 140, 219 "usb&" IFACE_CLASS_FMT, 220 IFACE_CLASS_ARGS); 221 222 #undef IFACE_PROTOCOL_FMT 223 #undef IFACE_PROTOCOL_ARGS 224 #undef IFACE_SUBCLASS_FMT 225 #undef IFACE_SUBCLASS_ARGS 226 #undef IFACE_CLASS_FMT 227 #undef IFACE_CLASS_ARGS 228 #undef VENDOR_RELEASE_FMT 229 #undef VENDOR_RELEASE_ARGS 230 #undef VENDOR_PRODUCT_FMT 231 #undef VENDOR_PRODUCT_ARGS 232 #undef VENDOR_ONLY_FMT 233 #undef VENDOR_ONLY_ARGS 234 235 return EOK; 236 } 237 131 238 /** Create DDF match ids from USB device descriptor. 132 239 * … … 135 242 * @return Error code. 136 243 */ 137 int usb_d rv_create_match_ids_from_device_descriptor(138 match_id_list_t *matches,139 const usb_standard_device_descriptor_t *device_descriptor)244 int usb_device_create_match_ids_from_device_descriptor( 245 const usb_standard_device_descriptor_t *device_descriptor, 246 match_id_list_t *matches) 140 247 { 141 int rc;142 143 248 /* 144 249 * Unless the vendor id is 0, the pair idVendor-idProduct … … 147 252 if (device_descriptor->vendor_id != 0) { 148 253 /* First, with release number. */ 149 rc = usb_add_match_id(matches, 100,150 "usb&vendor= %d&product=%d&release=" BCD_FMT,254 ADD_MATCHID_OR_RETURN(matches, 100, 255 "usb&vendor=0x%04x&product=0x%04x&release=" BCD_FMT, 151 256 (int) device_descriptor->vendor_id, 152 257 (int) device_descriptor->product_id, 153 258 BCD_ARGS(device_descriptor->device_version)); 154 if (rc != EOK) {155 return rc;156 }157 259 158 260 /* Next, without release number. */ 159 rc = usb_add_match_id(matches, 90, "usb&vendor=%d&product=%d", 261 ADD_MATCHID_OR_RETURN(matches, 90, 262 "usb&vendor=0x%04x&product=0x%04x", 160 263 (int) device_descriptor->vendor_id, 161 264 (int) device_descriptor->product_id); 162 if (rc != EOK) {163 return rc;164 }165 265 } 166 266 167 267 /* 168 268 * If the device class points to interface we skip adding 169 * class directly .269 * class directly but we add a multi interface device. 170 270 */ 171 271 if (device_descriptor->device_class != USB_CLASS_USE_INTERFACE) { 172 rc = usb_add_match_id(matches, 50, "usb&class=%s",272 ADD_MATCHID_OR_RETURN(matches, 50, "usb&class=%s", 173 273 usb_str_class(device_descriptor->device_class)); 174 if (rc != EOK) { 175 return rc; 176 } 274 } else { 275 ADD_MATCHID_OR_RETURN(matches, 50, "usb&mid"); 177 276 } 178 277 … … 180 279 } 181 280 182 /** Create DDF match ids from USB configuration descriptor. 183 * The configuration descriptor is expected to be in the complete form, 184 * i.e. including interface, endpoint etc. descriptors. 185 * 186 * @param matches List of match ids to extend. 187 * @param config_descriptor Configuration descriptor returned by given device. 188 * @param total_size Size of the @p config_descriptor. 281 282 /** Create match ids describing attached device. 283 * 284 * @warning The list of match ids @p matches may change even when 285 * function exits with error. 286 * 287 * @param ctrl_pipe Control pipe to given device (session must be already 288 * started). 289 * @param matches Initialized list of match ids. 189 290 * @return Error code. 190 291 */ 191 int usb_drv_create_match_ids_from_configuration_descriptor( 192 match_id_list_t *matches, 193 const void *config_descriptor, size_t total_size) 292 int usb_device_create_match_ids(usb_endpoint_pipe_t *ctrl_pipe, 293 match_id_list_t *matches) 194 294 { 195 /* 196 * Iterate through config descriptor to find the interface 197 * descriptors. 198 */ 199 size_t position = sizeof(usb_standard_configuration_descriptor_t); 200 while (position + 1 < total_size) { 201 uint8_t *current_descriptor 202 = ((uint8_t *) config_descriptor) + position; 203 uint8_t cur_descr_len = current_descriptor[0]; 204 uint8_t cur_descr_type = current_descriptor[1]; 205 206 position += cur_descr_len; 207 208 if (cur_descr_type != USB_DESCTYPE_INTERFACE) { 209 continue; 210 } 211 212 /* 213 * Finally, we found an interface descriptor. 214 */ 215 usb_standard_interface_descriptor_t *interface 216 = (usb_standard_interface_descriptor_t *) 217 current_descriptor; 218 219 int rc = usb_add_match_id(matches, 50, 220 "usb&interface&class=%s", 221 usb_str_class(interface->interface_class)); 222 if (rc != EOK) { 223 return rc; 224 } 225 } 226 295 int rc; 296 /* 297 * Retrieve device descriptor and add matches from it. 298 */ 299 usb_standard_device_descriptor_t device_descriptor; 300 301 rc = usb_request_get_device_descriptor(ctrl_pipe, &device_descriptor); 302 if (rc != EOK) { 303 return rc; 304 } 305 306 rc = usb_device_create_match_ids_from_device_descriptor( 307 &device_descriptor, matches); 308 if (rc != EOK) { 309 return rc; 310 } 311 227 312 return EOK; 228 313 } 229 314 230 /** Add match ids based on configuration descriptor. 231 * 232 * @param hc Open phone to host controller. 233 * @param matches Match ids list to add matches to. 234 * @param address USB address of the attached device. 315 /** Probe for device kind and register it in devman. 316 * 317 * @param[in] address Address of the (unknown) attached device. 318 * @param[in] hc_handle Handle of the host controller. 319 * @param[in] parent Parent device. 320 * @param[out] child_handle Handle of the child device. 235 321 * @return Error code. 236 322 */ 237 static int usb_add_config_descriptor_match_ids(int hc, 238 match_id_list_t *matches, usb_address_t address, 239 int config_count) 323 int usb_device_register_child_in_devman(usb_address_t address, 324 devman_handle_t hc_handle, 325 ddf_dev_t *parent, devman_handle_t *child_handle, 326 ddf_dev_ops_t *dev_ops, void *dev_data, ddf_fun_t **child_fun) 240 327 { 241 int final_rc = EOK; 242 243 int config_index; 244 for (config_index = 0; config_index < config_count; config_index++) { 245 int rc; 246 usb_standard_configuration_descriptor_t config_descriptor; 247 rc = usb_drv_req_get_bare_configuration_descriptor(hc, 248 address, config_index, &config_descriptor); 249 if (rc != EOK) { 250 final_rc = rc; 251 continue; 252 } 253 254 size_t full_config_descriptor_size; 255 void *full_config_descriptor 256 = malloc(config_descriptor.total_length); 257 rc = usb_drv_req_get_full_configuration_descriptor(hc, 258 address, config_index, 259 full_config_descriptor, config_descriptor.total_length, 260 &full_config_descriptor_size); 261 if (rc != EOK) { 262 final_rc = rc; 263 continue; 264 } 265 if (full_config_descriptor_size 266 != config_descriptor.total_length) { 267 final_rc = ERANGE; 268 continue; 269 } 270 271 rc = usb_drv_create_match_ids_from_configuration_descriptor( 272 matches, 273 full_config_descriptor, full_config_descriptor_size); 274 if (rc != EOK) { 275 final_rc = rc; 276 continue; 277 } 278 279 } 280 281 return final_rc; 282 } 283 284 /** Create match ids describing attached device. 285 * 286 * @warning The list of match ids @p matches may change even when 287 * function exits with error. 288 * 289 * @param hc Open phone to host controller. 290 * @param matches Initialized list of match ids. 291 * @param address USB address of the attached device. 292 * @return Error code. 293 */ 294 int usb_drv_create_device_match_ids(int hc, match_id_list_t *matches, 295 usb_address_t address) 296 { 297 int rc; 298 299 /* 300 * Retrieve device descriptor and add matches from it. 301 */ 302 usb_standard_device_descriptor_t device_descriptor; 303 304 rc = usb_drv_req_get_device_descriptor(hc, address, 305 &device_descriptor); 306 if (rc != EOK) { 307 return rc; 308 } 309 310 rc = usb_drv_create_match_ids_from_device_descriptor(matches, 311 &device_descriptor); 312 if (rc != EOK) { 313 return rc; 314 } 315 316 /* 317 * Go through all configurations and add matches 318 * based on interface class. 319 */ 320 rc = usb_add_config_descriptor_match_ids(hc, matches, 321 address, device_descriptor.configuration_count); 322 if (rc != EOK) { 323 return rc; 324 } 325 326 /* 327 * As a fallback, provide the simplest match id possible. 328 */ 329 rc = usb_add_match_id(matches, 1, "usb&fallback"); 330 if (rc != EOK) { 331 return rc; 332 } 333 334 return EOK; 335 } 336 337 338 /** Probe for device kind and register it in devman. 339 * 340 * @param hc Open phone to the host controller. 341 * @param parent Parent device. 342 * @param address Address of the (unknown) attached device. 343 * @return Error code. 344 */ 345 int usb_drv_register_child_in_devman(int hc, device_t *parent, 346 usb_address_t address, devman_handle_t *child_handle) 347 { 348 static size_t device_name_index = 0; 349 350 device_t *child = NULL; 328 size_t this_device_name_index; 329 330 fibril_mutex_lock(&device_name_index_mutex); 331 this_device_name_index = device_name_index; 332 device_name_index++; 333 fibril_mutex_unlock(&device_name_index_mutex); 334 335 ddf_fun_t *child = NULL; 351 336 char *child_name = NULL; 352 337 int rc; 353 354 child = create_device(); 338 usb_device_connection_t dev_connection; 339 usb_endpoint_pipe_t ctrl_pipe; 340 341 rc = usb_device_connection_initialize(&dev_connection, hc_handle, address); 342 if (rc != EOK) { 343 goto failure; 344 } 345 346 rc = usb_endpoint_pipe_initialize_default_control(&ctrl_pipe, 347 &dev_connection); 348 if (rc != EOK) { 349 goto failure; 350 } 351 352 /* 353 * TODO: Once the device driver framework support persistent 354 * naming etc., something more descriptive could be created. 355 */ 356 rc = asprintf(&child_name, "usbdev%02zu", this_device_name_index); 357 if (rc < 0) { 358 goto failure; 359 } 360 361 child = ddf_fun_create(parent, fun_inner, child_name); 355 362 if (child == NULL) { 356 363 rc = ENOMEM; … … 358 365 } 359 366 360 /* 361 * TODO: Once the device driver framework support persistent 362 * naming etc., something more descriptive could be created. 363 */ 364 rc = asprintf(&child_name, "usbdev%02zu", device_name_index); 365 if (rc < 0) { 366 goto failure; 367 } 368 child->parent = parent; 369 child->name = child_name; 370 child->ops = &child_ops; 371 372 rc = usb_drv_create_device_match_ids(hc, &child->match_ids, address); 373 if (rc != EOK) { 374 goto failure; 375 } 376 377 rc = child_device_register(child, parent); 367 if (dev_ops != NULL) { 368 child->ops = dev_ops; 369 } else { 370 child->ops = &child_ops; 371 } 372 373 child->driver_data = dev_data; 374 375 rc = usb_endpoint_pipe_start_session(&ctrl_pipe); 376 if (rc != EOK) { 377 goto failure; 378 } 379 380 rc = usb_device_create_match_ids(&ctrl_pipe, &child->match_ids); 381 if (rc != EOK) { 382 goto failure; 383 } 384 385 rc = usb_endpoint_pipe_end_session(&ctrl_pipe); 386 if (rc != EOK) { 387 goto failure; 388 } 389 390 rc = ddf_fun_bind(child); 378 391 if (rc != EOK) { 379 392 goto failure; … … 383 396 *child_handle = child->handle; 384 397 } 385 386 device_name_index++; 398 399 if (child_fun != NULL) { 400 *child_fun = child; 401 } 387 402 388 403 return EOK; … … 392 407 child->name = NULL; 393 408 /* This takes care of match_id deallocation as well. */ 394 d elete_device(child);409 ddf_fun_destroy(child); 395 410 } 396 411 if (child_name != NULL) { … … 399 414 400 415 return rc; 401 402 416 } 403 417
Note:
See TracChangeset
for help on using the changeset viewer.