Changes in uspace/lib/usb/src/recognise.c [3b77628:3f0ef89d] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usb/src/recognise.c
r3b77628 r3f0ef89d 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 /** Callback for getting host controller handle. 42 * 43 * @param dev Device in question. 44 * @param[out] handle Devman handle of the host controller. 45 * @return Error code. 46 */ 47 static int usb_iface_get_hc_handle(device_t *dev, devman_handle_t *handle) 48 { 49 assert(dev); 50 assert(dev->parent != NULL); 51 52 device_t *parent = dev->parent; 53 54 if (parent->ops && parent->ops->interfaces[USB_DEV_IFACE]) { 55 usb_iface_t *usb_iface 56 = (usb_iface_t *) parent->ops->interfaces[USB_DEV_IFACE]; 57 assert(usb_iface != NULL); 58 if (usb_iface->get_hc_handle) { 59 int rc = usb_iface->get_hc_handle(parent, handle); 60 return rc; 61 } 62 } 63 64 return ENOTSUP; 65 } 66 67 static usb_iface_t usb_iface = { 68 .get_hc_handle = usb_iface_get_hc_handle 69 }; 70 71 static device_ops_t child_ops = { 72 .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 73 51 }; 74 52 … … 135 113 } 136 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 137 238 /** Create DDF match ids from USB device descriptor. 138 239 * … … 141 242 * @return Error code. 142 243 */ 143 int usb_d rv_create_match_ids_from_device_descriptor(144 match_id_list_t *matches,145 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) 146 247 { 147 int rc;148 149 248 /* 150 249 * Unless the vendor id is 0, the pair idVendor-idProduct … … 153 252 if (device_descriptor->vendor_id != 0) { 154 253 /* First, with release number. */ 155 rc = usb_add_match_id(matches, 100,156 "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, 157 256 (int) device_descriptor->vendor_id, 158 257 (int) device_descriptor->product_id, 159 258 BCD_ARGS(device_descriptor->device_version)); 160 if (rc != EOK) {161 return rc;162 }163 259 164 260 /* Next, without release number. */ 165 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", 166 263 (int) device_descriptor->vendor_id, 167 264 (int) device_descriptor->product_id); 168 if (rc != EOK) {169 return rc;170 }171 265 } 172 266 173 267 /* 174 268 * If the device class points to interface we skip adding 175 * class directly .269 * class directly but we add a multi interface device. 176 270 */ 177 271 if (device_descriptor->device_class != USB_CLASS_USE_INTERFACE) { 178 rc = usb_add_match_id(matches, 50, "usb&class=%s",272 ADD_MATCHID_OR_RETURN(matches, 50, "usb&class=%s", 179 273 usb_str_class(device_descriptor->device_class)); 180 if (rc != EOK) { 181 return rc; 182 } 274 } else { 275 ADD_MATCHID_OR_RETURN(matches, 50, "usb&mid"); 183 276 } 184 277 … … 186 279 } 187 280 188 /** Create DDF match ids from USB configuration descriptor. 189 * The configuration descriptor is expected to be in the complete form, 190 * i.e. including interface, endpoint etc. descriptors. 191 * 192 * @param matches List of match ids to extend. 193 * @param config_descriptor Configuration descriptor returned by given device. 194 * @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. 195 290 * @return Error code. 196 291 */ 197 int usb_drv_create_match_ids_from_configuration_descriptor( 198 match_id_list_t *matches, 199 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) 200 294 { 201 /* 202 * Iterate through config descriptor to find the interface 203 * descriptors. 204 */ 205 size_t position = sizeof(usb_standard_configuration_descriptor_t); 206 while (position + 1 < total_size) { 207 uint8_t *current_descriptor 208 = ((uint8_t *) config_descriptor) + position; 209 uint8_t cur_descr_len = current_descriptor[0]; 210 uint8_t cur_descr_type = current_descriptor[1]; 211 212 if (cur_descr_len == 0) { 213 return ENOENT; 214 } 215 216 position += cur_descr_len; 217 218 if (cur_descr_type != USB_DESCTYPE_INTERFACE) { 219 continue; 220 } 221 222 /* 223 * Finally, we found an interface descriptor. 224 */ 225 usb_standard_interface_descriptor_t *interface 226 = (usb_standard_interface_descriptor_t *) 227 current_descriptor; 228 229 int rc = usb_add_match_id(matches, 50, 230 "usb&interface&class=%s", 231 usb_str_class(interface->interface_class)); 232 if (rc != EOK) { 233 return rc; 234 } 235 } 236 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 237 312 return EOK; 238 313 } 239 314 240 /** Add match ids based on configuration descriptor.241 *242 * @param hc Open phone to host controller.243 * @param matches Match ids list to add matches to.244 * @param address USB address of the attached device.245 * @param config_count Number of configurations the device has.246 * @return Error code.247 */248 static int usb_add_config_descriptor_match_ids(int hc,249 match_id_list_t *matches, usb_address_t address,250 int config_count)251 {252 int final_rc = EOK;253 254 int config_index;255 for (config_index = 0; config_index < config_count; config_index++) {256 int rc;257 usb_standard_configuration_descriptor_t config_descriptor;258 rc = usb_drv_req_get_bare_configuration_descriptor(hc,259 address, config_index, &config_descriptor);260 if (rc != EOK) {261 final_rc = rc;262 continue;263 }264 265 size_t full_config_descriptor_size;266 void *full_config_descriptor267 = malloc(config_descriptor.total_length);268 rc = usb_drv_req_get_full_configuration_descriptor(hc,269 address, config_index,270 full_config_descriptor, config_descriptor.total_length,271 &full_config_descriptor_size);272 if (rc != EOK) {273 final_rc = rc;274 continue;275 }276 if (full_config_descriptor_size277 != config_descriptor.total_length) {278 final_rc = ERANGE;279 continue;280 }281 282 rc = usb_drv_create_match_ids_from_configuration_descriptor(283 matches,284 full_config_descriptor, full_config_descriptor_size);285 if (rc != EOK) {286 final_rc = rc;287 continue;288 }289 290 }291 292 return final_rc;293 }294 295 /** Create match ids describing attached device.296 *297 * @warning The list of match ids @p matches may change even when298 * function exits with error.299 *300 * @param hc Open phone to host controller.301 * @param matches Initialized list of match ids.302 * @param address USB address of the attached device.303 * @return Error code.304 */305 int usb_drv_create_device_match_ids(int hc, match_id_list_t *matches,306 usb_address_t address)307 {308 int rc;309 310 /*311 * Retrieve device descriptor and add matches from it.312 */313 usb_standard_device_descriptor_t device_descriptor;314 315 rc = usb_drv_req_get_device_descriptor(hc, address,316 &device_descriptor);317 if (rc != EOK) {318 return rc;319 }320 321 rc = usb_drv_create_match_ids_from_device_descriptor(matches,322 &device_descriptor);323 if (rc != EOK) {324 return rc;325 }326 327 /*328 * Go through all configurations and add matches329 * based on interface class.330 */331 rc = usb_add_config_descriptor_match_ids(hc, matches,332 address, device_descriptor.configuration_count);333 if (rc != EOK) {334 return rc;335 }336 337 /*338 * As a fallback, provide the simplest match id possible.339 */340 rc = usb_add_match_id(matches, 1, "usb&fallback");341 if (rc != EOK) {342 return rc;343 }344 345 return EOK;346 }347 348 349 315 /** Probe for device kind and register it in devman. 350 316 * 351 * @param[in] hc Open phone to the host controller. 317 * @param[in] address Address of the (unknown) attached device. 318 * @param[in] hc_handle Handle of the host controller. 352 319 * @param[in] parent Parent device. 353 * @param[in] address Address of the (unknown) attached device.354 320 * @param[out] child_handle Handle of the child device. 355 321 * @return Error code. 356 322 */ 357 int usb_drv_register_child_in_devman(int hc, device_t *parent, 358 usb_address_t address, devman_handle_t *child_handle) 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) 359 327 { 360 static size_t device_name_index = 0; 361 362 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; 363 336 char *child_name = NULL; 364 337 int rc; 365 366 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); 367 362 if (child == NULL) { 368 363 rc = ENOMEM; … … 370 365 } 371 366 372 /* 373 * TODO: Once the device driver framework support persistent 374 * naming etc., something more descriptive could be created. 375 */ 376 rc = asprintf(&child_name, "usbdev%02zu", device_name_index); 377 if (rc < 0) { 378 goto failure; 379 } 380 child->parent = parent; 381 child->name = child_name; 382 child->ops = &child_ops; 383 384 rc = usb_drv_create_device_match_ids(hc, &child->match_ids, address); 385 if (rc != EOK) { 386 goto failure; 387 } 388 389 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); 390 391 if (rc != EOK) { 391 392 goto failure; … … 395 396 *child_handle = child->handle; 396 397 } 397 398 device_name_index++; 398 399 if (child_fun != NULL) { 400 *child_fun = child; 401 } 399 402 400 403 return EOK; … … 404 407 child->name = NULL; 405 408 /* This takes care of match_id deallocation as well. */ 406 d elete_device(child);409 ddf_fun_destroy(child); 407 410 } 408 411 if (child_name != NULL) { … … 411 414 412 415 return rc; 413 414 416 } 415 417
Note:
See TracChangeset
for help on using the changeset viewer.