1 /*************************************************************************** 2 * 3 * devinfo_usb.h : USB devices 4 * 5 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 6 * Use is subject to license terms. 7 * 8 * Licensed under the Academic Free License version 2.1 9 * 10 **************************************************************************/ 11 12 #ifdef HAVE_CONFIG_H 13 # include <config.h> 14 #endif 15 16 #include <stdio.h> 17 #include <string.h> 18 #include <libdevinfo.h> 19 #include <unistd.h> 20 #include <dirent.h> 21 #include <sys/types.h> 22 #include <sys/mkdev.h> 23 #include <sys/stat.h> 24 #include <sys/usb/usbai.h> 25 26 #include "../osspec.h" 27 #include "../logger.h" 28 #include "../hald.h" 29 #include "../hald_dbus.h" 30 #include "../device_info.h" 31 #include "../util.h" 32 #include "../ids.h" 33 #include "hotplug.h" 34 #include "devinfo.h" 35 #include "devinfo_usb.h" 36 37 static HalDevice *devinfo_usb_if_add(HalDevice *d, di_node_t node, gchar *devfs_path, 38 gchar *if_devfs_path, int ifnum); 39 static HalDevice *devinfo_usb_scsa2usb_add(HalDevice *d, di_node_t node); 40 static HalDevice *devinfo_usb_printer_add(HalDevice *usbd, di_node_t node); 41 static HalDevice *devinfo_usb_input_add(HalDevice *usbd, di_node_t node); 42 static HalDevice *devinfo_usb_video4linux_add(HalDevice *usbd, di_node_t node); 43 const gchar *devinfo_printer_prnio_get_prober(HalDevice *d, int *timeout); 44 const gchar *devinfo_keyboard_get_prober(HalDevice *d, int *timeout); 45 static void set_usb_properties(HalDevice *d, di_node_t node, gchar *devfs_path, char *driver_name); 46 47 DevinfoDevHandler devinfo_usb_handler = { 48 devinfo_usb_add, 49 NULL, 50 NULL, 51 NULL, 52 NULL, 53 NULL 54 }; 55 56 DevinfoDevHandler devinfo_usb_printer_handler = { 57 devinfo_usb_add, 58 NULL, 59 NULL, 60 NULL, 61 NULL, 62 devinfo_printer_prnio_get_prober 63 }; 64 65 DevinfoDevHandler devinfo_usb_keyboard_handler = { 66 devinfo_usb_add, 67 NULL, 68 NULL, 69 NULL, 70 NULL, 71 devinfo_keyboard_get_prober 72 }; 73 74 static gboolean 75 is_usb_node(di_node_t node) 76 { 77 int rc; 78 char *s; 79 80 /* 81 * USB device nodes will have "compatible" propety values that 82 * begins with "usb". 83 */ 84 rc = di_prop_lookup_strings(DDI_DEV_T_ANY, node, "compatible", &s); 85 while (rc-- > 0) { 86 if (strncmp(s, "usb", 3) == 0) { 87 return (TRUE); 88 } 89 s += (strlen(s) + 1); 90 } 91 92 return (FALSE); 93 } 94 95 static char * 96 get_usb_devlink(char *devfs_path, const char *dir_name) 97 { 98 char *result = NULL; 99 DIR *dp; 100 101 if ((dp = opendir(dir_name)) != NULL) { 102 struct dirent *ep; 103 104 while ((ep = readdir(dp)) != NULL) { 105 char path[MAXPATHLEN], lpath[MAXPATHLEN]; 106 107 strncpy(path, dir_name, strlen(dir_name)); 108 strncat(path, ep->d_name, strlen(ep->d_name)); 109 memset(lpath, 0, sizeof (lpath)); 110 if ((readlink(path, lpath, sizeof (lpath)) > 0) && 111 (strstr(lpath, devfs_path) != NULL)) { 112 result = strdup(path); 113 break; 114 } 115 memset(path, 0, sizeof (path)); 116 } 117 closedir(dp); 118 } 119 120 return (result); 121 } 122 123 HalDevice * 124 devinfo_usb_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type) 125 { 126 HalDevice *d, *nd = NULL; 127 char *s; 128 int *i; 129 char *driver_name, *binding_name; 130 char if_devfs_path[HAL_PATH_MAX]; 131 di_devlink_handle_t hdl; 132 double k; 133 134 if (is_usb_node(node) == FALSE) { 135 return (NULL); 136 } 137 138 driver_name = di_driver_name (node); 139 140 if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "interface", &i) < 0) { 141 /* It is a USB device node. */ 142 143 d = hal_device_new (); 144 145 devinfo_set_default_properties (d, parent, node, devfs_path); 146 hal_device_property_set_string (d, "info.subsystem", "usb_device"); 147 PROP_STR(d, node, s, "usb-product-name", "info.product"); 148 PROP_STR(d, node, s, "usb-product-name", "usb_device.product"); 149 PROP_STR(d, node, s, "usb-vendor-name", "usb_device.vendor"); 150 PROP_INT(d, node, i, "usb-vendor-id", "usb_device.vendor_id"); 151 PROP_INT(d, node, i, "usb-product-id", "usb_device.product_id"); 152 PROP_INT(d, node, i, "usb-revision-id", "usb_device.device_revision_bcd"); 153 PROP_STR(d, node, s, "usb-serialno", "usb_device.serial"); 154 PROP_INT(d, node, i, "usb-port-count", "usb_device.num_ports"); 155 PROP_INT(d, node, i, "usb-num-configs", "usb_device.num_configurations"); 156 PROP_INT(d, node, i, "assigned-address", "usb_device.bus_number"); 157 158 if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "usb-release", &i) > 0) { 159 k = (double)bcd(*i); 160 hal_device_property_set_double (d, "usb_device.version", k / 100); 161 } 162 163 if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "low-speed", &i) >= 0) { 164 k = 1.5; 165 } else if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "high-speed", &i) >= 0) { 166 k = 480.0; 167 } else { 168 /* It is the full speed device. */ 169 k = 12.0; 170 } 171 hal_device_property_set_double (d, "usb_device.speed", k); 172 173 set_usb_properties (d, node, devfs_path, driver_name); 174 175 /* wait for the ugen node's creation */ 176 if ((driver_name != NULL) && (strcmp (driver_name, "usb_mid") == 0)) { 177 if (hdl = di_devlink_init (devfs_path, DI_MAKE_LINK)) { 178 di_devlink_fini (&hdl); 179 } 180 } 181 182 devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler); 183 184 /* add to TDL so preprobing callouts and prober can access it */ 185 hal_device_store_add (hald_get_tdl (), d); 186 187 if (((binding_name = di_binding_name (node)) != NULL) && 188 (strncmp (binding_name, "usbif,", sizeof ("usbif,") - 1) == 0)) { 189 190 snprintf (if_devfs_path, sizeof (if_devfs_path), "%s:if%d", 191 devfs_path, 0); 192 if ((nd = devinfo_usb_if_add (d, node, if_devfs_path, 193 if_devfs_path, 0)) != NULL) { 194 d = nd; 195 nd = NULL; 196 devfs_path = if_devfs_path; 197 } 198 } 199 } else { 200 /* It is a USB interface node or IA node. */ 201 int *j; 202 203 if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "interface-count", &j) > 0) { 204 /* 205 * The USB IA node properties are not defined in 206 * HAL spec so far. So IA node udi has "ia" sign 207 * now, different from the IF node udi with "if". 208 */ 209 snprintf (if_devfs_path, sizeof (if_devfs_path), 210 "%s:ia%d", devfs_path, *i); 211 } else { 212 snprintf (if_devfs_path, sizeof (if_devfs_path), 213 "%s:if%d", devfs_path, *i); 214 } 215 216 d = devinfo_usb_if_add (parent, node, devfs_path, if_devfs_path, *i); 217 } 218 219 /* driver specific */ 220 if (driver_name != NULL) { 221 if (strcmp (driver_name, "scsa2usb") == 0) { 222 nd = devinfo_usb_scsa2usb_add (d, node); 223 } else if (strcmp (driver_name, "usbprn") == 0) { 224 nd = devinfo_usb_printer_add (d, node); 225 } else if (strcmp(driver_name, "hid") == 0) { 226 if (hdl = di_devlink_init(devfs_path, DI_MAKE_LINK)) { 227 di_devlink_fini(&hdl); 228 } 229 nd = devinfo_usb_input_add(d, node); 230 } else if (strcmp(driver_name, "usbvc") == 0) { 231 if (hdl = di_devlink_init(devfs_path, DI_MAKE_LINK)) { 232 di_devlink_fini(&hdl); 233 } 234 nd = devinfo_usb_video4linux_add(d, node); 235 } 236 } 237 238 out: 239 if (nd != NULL) { 240 return (nd); 241 } else { 242 return (d); 243 } 244 } 245 246 247 static void 248 set_usb_properties(HalDevice *d, di_node_t node, gchar *devfs_path, char *driver_name) 249 { 250 usb_dev_descr_t *dev_descrp = NULL; /* device descriptor */ 251 usb_cfg_descr_t *cfg_descrp = NULL; /* configuration descriptor */ 252 unsigned char *rdata = NULL; 253 char *p; 254 int i = 0; 255 256 hal_device_property_set_int (d, "usb_device.port_number", 257 atoi (devfs_path + strlen (devfs_path) -1)); 258 259 if (di_prop_lookup_bytes (DDI_DEV_T_ANY, node, "usb-dev-descriptor", 260 &rdata) > 0) { 261 dev_descrp = (usb_dev_descr_t *)rdata; 262 263 if (dev_descrp != NULL) { 264 hal_device_property_set_int (d, "usb_device.device_class", 265 dev_descrp->bDeviceClass); 266 hal_device_property_set_int (d, "usb_device.device_subclass", 267 dev_descrp->bDeviceSubClass); 268 hal_device_property_set_int (d, "usb_device.device_protocol", 269 dev_descrp->bDeviceProtocol); 270 } 271 } 272 273 if (di_prop_lookup_bytes (DDI_DEV_T_ANY, node, "usb-raw-cfg-descriptors", 274 &rdata) > 0) { 275 cfg_descrp = (usb_cfg_descr_t *)(rdata); 276 277 if (cfg_descrp != NULL) { 278 hal_device_property_set_int (d, "usb_device.configuration_value", 279 cfg_descrp->bConfigurationValue); 280 hal_device_property_set_int (d, "usb_device.max_power", 281 cfg_descrp->bMaxPower); 282 hal_device_property_set_int (d, "usb_device.num_interfaces", 283 cfg_descrp->bNumInterfaces); 284 hal_device_property_set_bool (d, "usb_device.can_wake_up", 285 (cfg_descrp->bmAttributes & 0x20) ? TRUE : FALSE); 286 hal_device_property_set_bool (d, "usb_device.is_self_powered", 287 (cfg_descrp->bmAttributes & 0x40) ? TRUE : FALSE); 288 } 289 } 290 291 /* get the node's usb tree level by counting hub numbers */ 292 do { 293 if (p = strstr (devfs_path, "/hub@")) { 294 devfs_path = p + strlen ("/hub@"); 295 i ++; 296 } 297 } while (p != NULL); 298 299 if ((driver_name != NULL) && (strcmp (driver_name, "hubd") == 0) && (i > 0)) 300 i --; 301 302 hal_device_property_set_int (d, "usb_device.level_number", i); 303 } 304 305 306 static usb_if_descr_t * 307 parse_usb_if_descr(di_node_t node, int ifnum) 308 { 309 unsigned char *rdata = NULL; 310 usb_if_descr_t *if_descrp=NULL; /* interface descriptor */ 311 di_node_t tmp_node = DI_NODE_NIL; 312 uint8_t num, length, type; 313 int rlen; 314 gchar *devpath = NULL; 315 316 if ((rlen = di_prop_lookup_bytes (DDI_DEV_T_ANY, node, 317 "usb-raw-cfg-descriptors", &rdata)) < 0) { 318 319 char *p; 320 int i; 321 322 if ((devpath = di_devfs_path (node)) == NULL) 323 goto out; 324 325 /* Look up its parent that may be a USB IA or USB mid. */ 326 for (i = 0; i < 2; i++) { 327 p = strrchr (devpath, '/'); 328 if (p == NULL) 329 goto out; 330 *p = '\0'; 331 332 if ((tmp_node = di_init (devpath, DINFOCPYALL)) == DI_NODE_NIL) 333 goto out; 334 335 if ((rlen = di_prop_lookup_bytes (DDI_DEV_T_ANY, tmp_node, 336 "usb-raw-cfg-descriptors", &rdata)) > 0) 337 break; 338 339 di_fini (tmp_node); 340 } 341 } 342 343 if (rdata == NULL) 344 goto out; 345 346 do { 347 length = (uint8_t)*rdata; 348 type = (uint8_t)*(rdata + 1); 349 if (type == USB_DESCR_TYPE_IF) { 350 num = (uint8_t)*(rdata + 2); 351 if (num == ifnum) { 352 if_descrp = (usb_if_descr_t *)rdata; 353 break; 354 } 355 } 356 rdata += length; 357 rlen -= length; 358 } while ((length > 0 ) && (rlen > 0)); 359 360 out: 361 if (devpath != NULL) 362 di_devfs_path_free (devpath); 363 if (tmp_node != DI_NODE_NIL) 364 di_fini (tmp_node); 365 return (if_descrp); 366 } 367 368 369 static HalDevice * 370 devinfo_usb_if_add(HalDevice *parent, di_node_t node, gchar *devfs_path, 371 gchar *if_devfs_path, int ifnum) 372 { 373 HalDevice *d = NULL; 374 char udi[HAL_PATH_MAX]; 375 const char *parent_info; 376 usb_if_descr_t *if_descrp=NULL; /* interface descriptor */ 377 378 d = hal_device_new (); 379 380 devinfo_set_default_properties (d, parent, node, if_devfs_path); 381 382 /* Set the existed physical device path. */ 383 hal_device_property_set_string (d, "solaris.devfs_path", devfs_path); 384 hal_device_property_set_string (d, "info.subsystem", "usb"); 385 hal_device_property_set_string (d, "info.product", "USB Device Interface"); 386 387 /* Set usb interface properties to interface node. */ 388 if (strstr (if_devfs_path, ":ia") == NULL) { 389 if_descrp = parse_usb_if_descr (node, ifnum); 390 391 if (if_descrp != NULL) { 392 hal_device_property_set_int (d, "usb.interface.class", 393 if_descrp->bInterfaceClass); 394 hal_device_property_set_int (d, "usb.interface.subclass", 395 if_descrp->bInterfaceSubClass); 396 hal_device_property_set_int (d, "usb.interface.protocol", 397 if_descrp->bInterfaceProtocol); 398 hal_device_property_set_int (d, "usb.interface.number", 399 if_descrp->bInterfaceNumber); 400 } 401 } 402 403 /* copy parent's usb_device.* properties */ 404 parent_info = hal_device_property_get_string (parent, "info.subsystem"); 405 if (parent_info != NULL) { 406 if (strcmp (parent_info, "usb_device") == 0) { 407 hal_device_merge_with_rewrite (d, parent, "usb.", "usb_device."); 408 } else if (strcmp (parent_info, "usb") == 0) { 409 /* for the case that the parent is IA node */ 410 hal_device_merge_with_rewrite (d, parent, "usb.", "usb."); 411 } 412 } 413 414 devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler); 415 416 /* add to TDL so preprobing callouts and prober can access it */ 417 hal_device_store_add (hald_get_tdl (), d); 418 419 return (d); 420 } 421 422 423 static void 424 get_dev_link_path(di_node_t node, char *nodetype, char *re, char **devlink, char **minor_path, char **minor_name) 425 { 426 di_devlink_handle_t devlink_hdl; 427 int major; 428 di_minor_t minor; 429 dev_t devt; 430 431 *devlink = NULL; 432 *minor_path = NULL; 433 *minor_name = NULL; 434 435 if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) { 436 return; 437 } 438 439 major = di_driver_major(node); 440 minor = DI_MINOR_NIL; 441 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 442 devt = di_minor_devt(minor); 443 if (major != major(devt)) { 444 continue; 445 } 446 447 if (di_minor_type(minor) != DDM_MINOR) { 448 continue; 449 } 450 451 if ((*minor_path = di_devfs_minor_path(minor)) == NULL) { 452 continue; 453 } 454 455 if (strcmp(di_minor_nodetype(minor), nodetype) == 0) { 456 *devlink = get_devlink(devlink_hdl, re, *minor_path); 457 /* 458 * During hotplugging, devlink could be NULL for usb 459 * devices due to devlink database has not yet been 460 * updated when hal try to read from it although the 461 * actually dev link path has been created. In such a 462 * situation, we will read the devlink name from 463 * /dev/usb directory. 464 */ 465 if ((*devlink == NULL) && 466 ((strstr(re, "hid") != NULL) || (strstr(re, "video") != NULL))) { 467 *devlink = get_usb_devlink(*minor_path, "/dev/usb/"); 468 } 469 470 if (*devlink != NULL) { 471 *minor_name = di_minor_name(minor); 472 break; 473 } 474 } 475 476 di_devfs_path_free (*minor_path); 477 *minor_path = NULL; 478 } 479 di_devlink_fini (&devlink_hdl); 480 } 481 482 static HalDevice * 483 devinfo_usb_video4linux_add(HalDevice *usbd, di_node_t node) 484 { 485 HalDevice *d = NULL; 486 int major; 487 di_minor_t minor; 488 dev_t devt; 489 char *devlink = NULL; 490 char *dev_videolink = NULL; 491 char *minor_path = NULL; 492 char *minor_name = NULL; 493 char udi[HAL_PATH_MAX]; 494 char *s; 495 496 get_dev_link_path(node, "usb_video", 497 "^usb/video+", &devlink, &minor_path, &minor_name); 498 499 if ((minor_path == NULL) || (devlink == NULL)) { 500 501 goto out; 502 } 503 504 HAL_DEBUG(("devlink %s, minor_name %s", devlink, minor_name)); 505 if (strcmp(minor_name, "usbvc") != 0) { 506 507 goto out; 508 } 509 510 d = hal_device_new(); 511 512 devinfo_set_default_properties(d, usbd, node, minor_path); 513 hal_device_property_set_string(d, "info.subsystem", "video4linux"); 514 hal_device_property_set_string(d, "info.category", "video4linux"); 515 516 hal_device_add_capability(d, "video4linux"); 517 518 /* Get logic link under /dev (/dev/video+) */ 519 dev_videolink = get_usb_devlink(strstr(devlink, "usb"), "/dev/"); 520 521 hal_device_property_set_string(d, "video4linux.device", dev_videolink); 522 523 hal_util_compute_udi(hald_get_gdl(), udi, sizeof (udi), 524 "%s_video4linux", hal_device_get_udi(usbd)); 525 526 hal_device_set_udi(d, udi); 527 hal_device_property_set_string(d, "info.udi", udi); 528 PROP_STR(d, node, s, "usb-product-name", "info.product"); 529 530 devinfo_add_enqueue(d, minor_path, &devinfo_usb_handler); 531 532 533 out: 534 if (devlink) { 535 free(devlink); 536 } 537 538 if (minor_path) { 539 di_devfs_path_free(minor_path); 540 } 541 542 return (d); 543 } 544 545 static HalDevice * 546 devinfo_usb_input_add(HalDevice *usbd, di_node_t node) 547 { 548 HalDevice *d = NULL; 549 int major; 550 di_minor_t minor; 551 dev_t devt; 552 char *devlink = NULL; 553 char *minor_path = NULL; 554 char *minor_name = NULL; 555 char udi[HAL_PATH_MAX]; 556 557 get_dev_link_path(node, "ddi_pseudo", 558 "^usb/hid+", &devlink, &minor_path, &minor_name); 559 560 if ((minor_path == NULL) || (devlink == NULL)) { 561 562 goto out; 563 } 564 565 HAL_DEBUG(("devlink %s, minor_name %s", devlink, minor_name)); 566 if ((strcmp(minor_name, "keyboard") != 0) && 567 (strcmp(minor_name, "mouse") != 0)) { 568 569 goto out; 570 } 571 572 d = hal_device_new(); 573 574 devinfo_set_default_properties(d, usbd, node, minor_path); 575 hal_device_property_set_string(d, "info.subsystem", "input"); 576 hal_device_property_set_string(d, "info.category", "input"); 577 578 hal_device_add_capability(d, "input"); 579 580 if (strcmp(minor_name, "keyboard") == 0) { 581 hal_device_add_capability(d, "input.keyboard"); 582 hal_device_add_capability(d, "input.keys"); 583 hal_device_add_capability(d, "button"); 584 } else if (strcmp(minor_name, "mouse") == 0) { 585 hal_device_add_capability (d, "input.mouse"); 586 } 587 588 hal_device_property_set_string(d, "input.device", devlink); 589 hal_device_property_set_string(d, "input.originating_device", 590 hal_device_get_udi(usbd)); 591 592 hal_util_compute_udi(hald_get_gdl(), udi, sizeof (udi), 593 "%s_logicaldev_input", hal_device_get_udi(usbd)); 594 595 hal_device_set_udi(d, udi); 596 hal_device_property_set_string(d, "info.udi", udi); 597 598 if (strcmp(minor_name, "keyboard") == 0) { 599 devinfo_add_enqueue(d, minor_path, &devinfo_usb_keyboard_handler); 600 } else { 601 devinfo_add_enqueue(d, minor_path, &devinfo_usb_handler); 602 } 603 604 /* add to TDL so preprobing callouts and prober can access it */ 605 hal_device_store_add(hald_get_tdl(), d); 606 607 out: 608 if (devlink) { 609 free(devlink); 610 } 611 612 if (minor_path) { 613 di_devfs_path_free(minor_path); 614 } 615 616 return (d); 617 } 618 619 static HalDevice * 620 devinfo_usb_scsa2usb_add(HalDevice *usbd, di_node_t node) 621 { 622 HalDevice *d = NULL; 623 di_devlink_handle_t devlink_hdl; 624 int major; 625 di_minor_t minor; 626 dev_t devt; 627 char *minor_path = NULL; 628 char *minor_name = NULL; 629 char *devlink = NULL; 630 char udi[HAL_PATH_MAX]; 631 632 get_dev_link_path(node, "ddi_ctl:devctl:scsi", NULL, &devlink, &minor_path, &minor_name); 633 634 if ((devlink == NULL) || (minor_path == NULL)) { 635 goto out; 636 } 637 638 d = hal_device_new (); 639 640 devinfo_set_default_properties (d, usbd, node, minor_path); 641 hal_device_property_set_string (d, "scsi_host.solaris.device", devlink); 642 hal_device_property_set_string (d, "info.category", "scsi_host"); 643 hal_device_property_set_int (d, "scsi_host.host", 0); 644 645 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), 646 "%s/scsi_host%d", hal_device_get_udi (usbd), 647 hal_device_property_get_int (d, "scsi_host.host")); 648 hal_device_set_udi (d, udi); 649 hal_device_property_set_string (d, "info.udi", udi); 650 hal_device_property_set_string (d, "info.product", "SCSI Host Adapter"); 651 652 devinfo_add_enqueue (d, minor_path, &devinfo_usb_handler); 653 654 out: 655 if (devlink) { 656 free(devlink); 657 } 658 if (minor_path) { 659 di_devfs_path_free (minor_path); 660 } 661 662 return (d); 663 } 664 665 static HalDevice * 666 devinfo_usb_printer_add(HalDevice *parent, di_node_t node) 667 { 668 char *properties[] = { "vendor", "product", "serial", NULL }; 669 int i; 670 HalDevice *d = NULL; 671 char udi[HAL_PATH_MAX]; 672 char *s; 673 char *devlink = NULL, *minor_path = NULL, *minor_name = NULL; 674 const char *subsystem; 675 676 get_dev_link_path(node, "ddi_printer", "printers/.+", &devlink, &minor_path, &minor_name); 677 678 if ((devlink == NULL) || (minor_path == NULL)) { 679 goto out; 680 } 681 682 d = hal_device_new (); 683 684 devinfo_set_default_properties (d, parent, node, minor_path); 685 hal_device_property_set_string (d, "info.category", "printer"); 686 hal_device_add_capability (d, "printer"); 687 688 /* add printer properties */ 689 hal_device_property_set_string (d, "printer.device", devlink); 690 691 /* copy parent's selected usb* properties to printer properties */ 692 subsystem = hal_device_property_get_string (parent, "info.subsystem"); 693 for (i = 0; properties[i] != NULL; i++) { 694 char src[32], dst[32]; /* "subsystem.property" names */ 695 696 snprintf(src, sizeof (src), "%s.%s", subsystem, properties[i]); 697 snprintf(dst, sizeof (dst), "printer.%s", properties[i]); 698 hal_device_copy_property(parent, src, d, dst); 699 } 700 701 devinfo_add_enqueue (d, minor_path, &devinfo_usb_printer_handler); 702 703 out: 704 if (devlink) { 705 free(devlink); 706 } 707 if (minor_path) { 708 di_devfs_path_free (minor_path); 709 } 710 711 return (d); 712 } 713 714 const gchar * 715 devinfo_printer_prnio_get_prober (HalDevice *d, int *timeout) 716 { 717 *timeout = 5 * 1000; /* 5 second timeout */ 718 return ("hald-probe-printer"); 719 } 720 721 const gchar * 722 devinfo_keyboard_get_prober(HalDevice *d, int *timeout) 723 { 724 *timeout = 5 * 1000; /* 5 second timeout */ 725 return ("hald-probe-xkb"); 726 } 727