Changes in uspace/lib/usb/src/recognise.c [3f0ef89d:3b77628] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usb/src/recognise.c
r3f0ef89d r3b77628 33 33 * @brief Functions for recognising kind of attached devices. 34 34 */ 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> 35 #include <usb_iface.h> 36 #include <usb/usbdrv.h> 41 37 #include <usb/classes/classes.h> 42 38 #include <stdio.h> 43 39 #include <errno.h> 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 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 51 73 }; 52 74 … … 113 135 } 114 136 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_protocol154 155 #define IFACE_SUBCLASS_FMT "interface&class=%s&subclass=0x%02x"156 #define IFACE_SUBCLASS_ARGS classname, desc_interface->interface_subclass157 158 #define IFACE_CLASS_FMT "interface&class=%s"159 #define IFACE_CLASS_ARGS classname160 161 #define VENDOR_RELEASE_FMT "vendor=0x%04x&product=0x%04x&release=" BCD_FMT162 #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_id167 168 #define VENDOR_ONLY_FMT "vendor=0x%04x"169 #define VENDOR_ONLY_ARGS desc_device->vendor_id170 171 /*172 * If the vendor is specified, create match ids with vendor with173 * 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_FMT223 #undef IFACE_PROTOCOL_ARGS224 #undef IFACE_SUBCLASS_FMT225 #undef IFACE_SUBCLASS_ARGS226 #undef IFACE_CLASS_FMT227 #undef IFACE_CLASS_ARGS228 #undef VENDOR_RELEASE_FMT229 #undef VENDOR_RELEASE_ARGS230 #undef VENDOR_PRODUCT_FMT231 #undef VENDOR_PRODUCT_ARGS232 #undef VENDOR_ONLY_FMT233 #undef VENDOR_ONLY_ARGS234 235 return EOK;236 }237 238 137 /** Create DDF match ids from USB device descriptor. 239 138 * … … 242 141 * @return Error code. 243 142 */ 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) 247 { 143 int usb_drv_create_match_ids_from_device_descriptor( 144 match_id_list_t *matches, 145 const usb_standard_device_descriptor_t *device_descriptor) 146 { 147 int rc; 148 248 149 /* 249 150 * Unless the vendor id is 0, the pair idVendor-idProduct … … 252 153 if (device_descriptor->vendor_id != 0) { 253 154 /* First, with release number. */ 254 ADD_MATCHID_OR_RETURN(matches, 100,255 "usb&vendor= 0x%04x&product=0x%04x&release=" BCD_FMT,155 rc = usb_add_match_id(matches, 100, 156 "usb&vendor=%d&product=%d&release=" BCD_FMT, 256 157 (int) device_descriptor->vendor_id, 257 158 (int) device_descriptor->product_id, 258 159 BCD_ARGS(device_descriptor->device_version)); 160 if (rc != EOK) { 161 return rc; 162 } 259 163 260 164 /* Next, without release number. */ 261 ADD_MATCHID_OR_RETURN(matches, 90, 262 "usb&vendor=0x%04x&product=0x%04x", 165 rc = usb_add_match_id(matches, 90, "usb&vendor=%d&product=%d", 263 166 (int) device_descriptor->vendor_id, 264 167 (int) device_descriptor->product_id); 168 if (rc != EOK) { 169 return rc; 170 } 265 171 } 266 172 267 173 /* 268 174 * If the device class points to interface we skip adding 269 * class directly but we add a multi interface device.175 * class directly. 270 176 */ 271 177 if (device_descriptor->device_class != USB_CLASS_USE_INTERFACE) { 272 ADD_MATCHID_OR_RETURN(matches, 50, "usb&class=%s",178 rc = usb_add_match_id(matches, 50, "usb&class=%s", 273 179 usb_str_class(device_descriptor->device_class)); 274 } else { 275 ADD_MATCHID_OR_RETURN(matches, 50, "usb&mid"); 180 if (rc != EOK) { 181 return rc; 182 } 276 183 } 277 184 … … 279 186 } 280 187 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. 195 * @return Error code. 196 */ 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) 200 { 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 237 return EOK; 238 } 239 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_descriptor 267 = 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_size 277 != 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 } 281 294 282 295 /** Create match ids describing attached device. … … 285 298 * function exits with error. 286 299 * 287 * @param ctrl_pipe Control pipe to given device (session must be already 288 * started). 300 * @param hc Open phone to host controller. 289 301 * @param matches Initialized list of match ids. 290 * @return Error code. 291 */ 292 int usb_device_create_match_ids(usb_endpoint_pipe_t *ctrl_pipe, 293 match_id_list_t *matches) 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) 294 307 { 295 308 int rc; 309 296 310 /* 297 311 * Retrieve device descriptor and add matches from it. … … 299 313 usb_standard_device_descriptor_t device_descriptor; 300 314 301 rc = usb_request_get_device_descriptor(ctrl_pipe, &device_descriptor); 315 rc = usb_drv_req_get_device_descriptor(hc, address, 316 &device_descriptor); 302 317 if (rc != EOK) { 303 318 return rc; 304 319 } 305 306 rc = usb_d evice_create_match_ids_from_device_descriptor(307 &device_descriptor , matches);320 321 rc = usb_drv_create_match_ids_from_device_descriptor(matches, 322 &device_descriptor); 308 323 if (rc != EOK) { 309 324 return rc; 310 325 } 326 327 /* 328 * Go through all configurations and add matches 329 * 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 } 311 344 312 345 return EOK; 313 346 } 314 347 348 315 349 /** Probe for device kind and register it in devman. 316 350 * 351 * @param[in] hc Open phone to the host controller. 352 * @param[in] parent Parent device. 317 353 * @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 354 * @param[out] child_handle Handle of the child device. 321 355 * @return Error code. 322 356 */ 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) 327 { 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; 357 int usb_drv_register_child_in_devman(int hc, device_t *parent, 358 usb_address_t address, devman_handle_t *child_handle) 359 { 360 static size_t device_name_index = 0; 361 362 device_t *child = NULL; 336 363 char *child_name = NULL; 337 364 int rc; 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) { 365 366 child = create_device(); 367 if (child == NULL) { 368 rc = ENOMEM; 349 369 goto failure; 350 370 } … … 354 374 * naming etc., something more descriptive could be created. 355 375 */ 356 rc = asprintf(&child_name, "usbdev%02zu", this_device_name_index);376 rc = asprintf(&child_name, "usbdev%02zu", device_name_index); 357 377 if (rc < 0) { 358 378 goto failure; 359 379 } 360 361 child = ddf_fun_create(parent, fun_inner, child_name); 362 if (child == NULL) { 363 rc = ENOMEM; 364 goto failure; 365 } 366 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); 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); 391 390 if (rc != EOK) { 392 391 goto failure; … … 396 395 *child_handle = child->handle; 397 396 } 398 399 if (child_fun != NULL) { 400 *child_fun = child; 401 } 397 398 device_name_index++; 402 399 403 400 return EOK; … … 407 404 child->name = NULL; 408 405 /* This takes care of match_id deallocation as well. */ 409 d df_fun_destroy(child);406 delete_device(child); 410 407 } 411 408 if (child_name != NULL) { … … 414 411 415 412 return rc; 413 416 414 } 417 415
Note:
See TracChangeset
for help on using the changeset viewer.