00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035 #include <sys/types.h>
00036 #include <fibril_synch.h>
00037 #include <usb/dev/pipes.h>
00038 #include <usb/dev/recognise.h>
00039 #include <usb/ddfiface.h>
00040 #include <usb/dev/request.h>
00041 #include <usb/classes/classes.h>
00042 #include <stdio.h>
00043 #include <errno.h>
00044 #include <assert.h>
00045
00047 static size_t device_name_index = 0;
00049 static FIBRIL_MUTEX_INITIALIZE(device_name_index_mutex);
00050
00052 ddf_dev_ops_t child_ops = {
00053 .interfaces[USB_DEV_IFACE] = &usb_iface_hub_child_impl
00054 };
00055
00057 #define BCD_INT(a) (((unsigned int)(a)) / 256)
00058
00059 #define BCD_FRAC(a) (((unsigned int)(a)) % 256)
00060
00062 #define BCD_FMT "%x.%x"
00063
00064 #define BCD_ARGS(a) BCD_INT((a)), BCD_FRAC((a))
00065
00066
00067 #define MATCH_STRING_MAX 256
00068
00076 static int usb_add_match_id(match_id_list_t *matches, int score,
00077 const char *format, ...)
00078 {
00079 char *match_str = NULL;
00080 match_id_t *match_id = NULL;
00081 int rc;
00082
00083 match_str = malloc(MATCH_STRING_MAX + 1);
00084 if (match_str == NULL) {
00085 rc = ENOMEM;
00086 goto failure;
00087 }
00088
00089
00090
00091
00092 va_list args;
00093 va_start(args, format );
00094 vsnprintf(match_str, MATCH_STRING_MAX, format, args);
00095 match_str[MATCH_STRING_MAX] = 0;
00096 va_end(args);
00097
00098 match_id = create_match_id();
00099 if (match_id == NULL) {
00100 rc = ENOMEM;
00101 goto failure;
00102 }
00103
00104 match_id->id = match_str;
00105 match_id->score = score;
00106 add_match_id(matches, match_id);
00107
00108 return EOK;
00109
00110 failure:
00111 if (match_str != NULL) {
00112 free(match_str);
00113 }
00114 if (match_id != NULL) {
00115 match_id->id = NULL;
00116 delete_match_id(match_id);
00117 }
00118
00119 return rc;
00120 }
00121
00129 #define ADD_MATCHID_OR_RETURN(match_ids, score, format, ...) \
00130 do { \
00131 int __rc = usb_add_match_id((match_ids), (score), \
00132 format, ##__VA_ARGS__); \
00133 if (__rc != EOK) { \
00134 return __rc; \
00135 } \
00136 } while (0)
00137
00147 int usb_device_create_match_ids_from_interface(
00148 const usb_standard_device_descriptor_t *desc_device,
00149 const usb_standard_interface_descriptor_t *desc_interface,
00150 match_id_list_t *matches)
00151 {
00152 if (desc_interface == NULL) {
00153 return EINVAL;
00154 }
00155 if (matches == NULL) {
00156 return EINVAL;
00157 }
00158
00159 if (desc_interface->interface_class == USB_CLASS_USE_INTERFACE) {
00160 return ENOENT;
00161 }
00162
00163 const char *classname = usb_str_class(desc_interface->interface_class);
00164 assert(classname != NULL);
00165
00166 #define IFACE_PROTOCOL_FMT "interface&class=%s&subclass=0x%02x&protocol=0x%02x"
00167 #define IFACE_PROTOCOL_ARGS classname, desc_interface->interface_subclass, \
00168 desc_interface->interface_protocol
00169
00170 #define IFACE_SUBCLASS_FMT "interface&class=%s&subclass=0x%02x"
00171 #define IFACE_SUBCLASS_ARGS classname, desc_interface->interface_subclass
00172
00173 #define IFACE_CLASS_FMT "interface&class=%s"
00174 #define IFACE_CLASS_ARGS classname
00175
00176 #define VENDOR_RELEASE_FMT "vendor=0x%04x&product=0x%04x&release=" BCD_FMT
00177 #define VENDOR_RELEASE_ARGS desc_device->vendor_id, desc_device->product_id, \
00178 BCD_ARGS(desc_device->device_version)
00179
00180 #define VENDOR_PRODUCT_FMT "vendor=0x%04x&product=0x%04x"
00181 #define VENDOR_PRODUCT_ARGS desc_device->vendor_id, desc_device->product_id
00182
00183 #define VENDOR_ONLY_FMT "vendor=0x%04x"
00184 #define VENDOR_ONLY_ARGS desc_device->vendor_id
00185
00186
00187
00188
00189
00190
00191 if ((desc_device != NULL) && (desc_device->vendor_id != 0)) {
00192
00193 ADD_MATCHID_OR_RETURN(matches, 250,
00194 "usb&" VENDOR_RELEASE_FMT "&" IFACE_PROTOCOL_FMT,
00195 VENDOR_RELEASE_ARGS, IFACE_PROTOCOL_ARGS);
00196 ADD_MATCHID_OR_RETURN(matches, 240,
00197 "usb&" VENDOR_RELEASE_FMT "&" IFACE_SUBCLASS_FMT,
00198 VENDOR_RELEASE_ARGS, IFACE_SUBCLASS_ARGS);
00199 ADD_MATCHID_OR_RETURN(matches, 230,
00200 "usb&" VENDOR_RELEASE_FMT "&" IFACE_CLASS_FMT,
00201 VENDOR_RELEASE_ARGS, IFACE_CLASS_ARGS);
00202
00203
00204 ADD_MATCHID_OR_RETURN(matches, 220,
00205 "usb&" VENDOR_PRODUCT_FMT "&" IFACE_PROTOCOL_FMT,
00206 VENDOR_PRODUCT_ARGS, IFACE_PROTOCOL_ARGS);
00207 ADD_MATCHID_OR_RETURN(matches, 210,
00208 "usb&" VENDOR_PRODUCT_FMT "&" IFACE_SUBCLASS_FMT,
00209 VENDOR_PRODUCT_ARGS, IFACE_SUBCLASS_ARGS);
00210 ADD_MATCHID_OR_RETURN(matches, 200,
00211 "usb&" VENDOR_PRODUCT_FMT "&" IFACE_CLASS_FMT,
00212 VENDOR_PRODUCT_ARGS, IFACE_CLASS_ARGS);
00213
00214
00215 ADD_MATCHID_OR_RETURN(matches, 190,
00216 "usb&" VENDOR_ONLY_FMT "&" IFACE_PROTOCOL_FMT,
00217 VENDOR_ONLY_ARGS, IFACE_PROTOCOL_ARGS);
00218 ADD_MATCHID_OR_RETURN(matches, 180,
00219 "usb&" VENDOR_ONLY_FMT "&" IFACE_SUBCLASS_FMT,
00220 VENDOR_ONLY_ARGS, IFACE_SUBCLASS_ARGS);
00221 ADD_MATCHID_OR_RETURN(matches, 170,
00222 "usb&" VENDOR_ONLY_FMT "&" IFACE_CLASS_FMT,
00223 VENDOR_ONLY_ARGS, IFACE_CLASS_ARGS);
00224 }
00225
00226
00227 ADD_MATCHID_OR_RETURN(matches, 160,
00228 "usb&" IFACE_PROTOCOL_FMT,
00229 IFACE_PROTOCOL_ARGS);
00230 ADD_MATCHID_OR_RETURN(matches, 150,
00231 "usb&" IFACE_SUBCLASS_FMT,
00232 IFACE_SUBCLASS_ARGS);
00233 ADD_MATCHID_OR_RETURN(matches, 140,
00234 "usb&" IFACE_CLASS_FMT,
00235 IFACE_CLASS_ARGS);
00236
00237 #undef IFACE_PROTOCOL_FMT
00238 #undef IFACE_PROTOCOL_ARGS
00239 #undef IFACE_SUBCLASS_FMT
00240 #undef IFACE_SUBCLASS_ARGS
00241 #undef IFACE_CLASS_FMT
00242 #undef IFACE_CLASS_ARGS
00243 #undef VENDOR_RELEASE_FMT
00244 #undef VENDOR_RELEASE_ARGS
00245 #undef VENDOR_PRODUCT_FMT
00246 #undef VENDOR_PRODUCT_ARGS
00247 #undef VENDOR_ONLY_FMT
00248 #undef VENDOR_ONLY_ARGS
00249
00250
00251 ADD_MATCHID_OR_RETURN(matches, 10, "usb&interface&fallback");
00252
00253 return EOK;
00254 }
00255
00262 int usb_device_create_match_ids_from_device_descriptor(
00263 const usb_standard_device_descriptor_t *device_descriptor,
00264 match_id_list_t *matches)
00265 {
00266
00267
00268
00269
00270 if (device_descriptor->vendor_id != 0) {
00271
00272 ADD_MATCHID_OR_RETURN(matches, 100,
00273 "usb&vendor=0x%04x&product=0x%04x&release=" BCD_FMT,
00274 (int) device_descriptor->vendor_id,
00275 (int) device_descriptor->product_id,
00276 BCD_ARGS(device_descriptor->device_version));
00277
00278
00279 ADD_MATCHID_OR_RETURN(matches, 90,
00280 "usb&vendor=0x%04x&product=0x%04x",
00281 (int) device_descriptor->vendor_id,
00282 (int) device_descriptor->product_id);
00283 }
00284
00285
00286
00287
00288
00289 if (device_descriptor->device_class != USB_CLASS_USE_INTERFACE) {
00290 ADD_MATCHID_OR_RETURN(matches, 50, "usb&class=%s",
00291 usb_str_class(device_descriptor->device_class));
00292 } else {
00293 ADD_MATCHID_OR_RETURN(matches, 50, "usb&mid");
00294 }
00295
00296
00297 ADD_MATCHID_OR_RETURN(matches, 10, "usb&fallback");
00298
00299 return EOK;
00300 }
00301
00302
00313 int usb_device_create_match_ids(usb_pipe_t *ctrl_pipe,
00314 match_id_list_t *matches)
00315 {
00316 int rc;
00317
00318
00319
00320 usb_standard_device_descriptor_t device_descriptor;
00321
00322 rc = usb_request_get_device_descriptor(ctrl_pipe, &device_descriptor);
00323 if (rc != EOK) {
00324 return rc;
00325 }
00326
00327 rc = usb_device_create_match_ids_from_device_descriptor(
00328 &device_descriptor, matches);
00329 if (rc != EOK) {
00330 return rc;
00331 }
00332
00333 return EOK;
00334 }
00335
00349 int usb_device_register_child_in_devman(usb_address_t address,
00350 devman_handle_t hc_handle,
00351 ddf_dev_t *parent, devman_handle_t *child_handle,
00352 ddf_dev_ops_t *dev_ops, void *dev_data, ddf_fun_t **child_fun)
00353 {
00354 size_t this_device_name_index;
00355
00356 fibril_mutex_lock(&device_name_index_mutex);
00357 this_device_name_index = device_name_index;
00358 device_name_index++;
00359 fibril_mutex_unlock(&device_name_index_mutex);
00360
00361 ddf_fun_t *child = NULL;
00362 char *child_name = NULL;
00363 int rc;
00364 usb_device_connection_t dev_connection;
00365 usb_pipe_t ctrl_pipe;
00366
00367 rc = usb_device_connection_initialize(&dev_connection, hc_handle, address);
00368 if (rc != EOK) {
00369 goto failure;
00370 }
00371
00372 rc = usb_pipe_initialize_default_control(&ctrl_pipe,
00373 &dev_connection);
00374 if (rc != EOK) {
00375 goto failure;
00376 }
00377 rc = usb_pipe_probe_default_control(&ctrl_pipe);
00378 if (rc != EOK) {
00379 goto failure;
00380 }
00381
00382
00383
00384
00385
00386 rc = asprintf(&child_name, "usb%02zu_a%d",
00387 this_device_name_index, address);
00388 if (rc < 0) {
00389 goto failure;
00390 }
00391
00392 child = ddf_fun_create(parent, fun_inner, child_name);
00393 if (child == NULL) {
00394 rc = ENOMEM;
00395 goto failure;
00396 }
00397
00398 if (dev_ops != NULL) {
00399 child->ops = dev_ops;
00400 } else {
00401 child->ops = &child_ops;
00402 }
00403
00404 child->driver_data = dev_data;
00405
00406 rc = usb_device_create_match_ids(&ctrl_pipe, &child->match_ids);
00407 if (rc != EOK) {
00408 goto failure;
00409 }
00410
00411 rc = ddf_fun_bind(child);
00412 if (rc != EOK) {
00413 goto failure;
00414 }
00415
00416 if (child_handle != NULL) {
00417 *child_handle = child->handle;
00418 }
00419
00420 if (child_fun != NULL) {
00421 *child_fun = child;
00422 }
00423
00424 return EOK;
00425
00426 failure:
00427 if (child != NULL) {
00428 child->name = NULL;
00429
00430 ddf_fun_destroy(child);
00431 }
00432 if (child_name != NULL) {
00433 free(child_name);
00434 }
00435
00436 return rc;
00437 }
00438
00439