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
is_usb_node(di_node_t node)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 *
get_usb_devlink(char * devfs_path,const char * dir_name)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 *
devinfo_usb_add(HalDevice * parent,di_node_t node,char * devfs_path,char * device_type)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
set_usb_properties(HalDevice * d,di_node_t node,gchar * devfs_path,char * driver_name)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 *
parse_usb_if_descr(di_node_t node,int ifnum)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 *
devinfo_usb_if_add(HalDevice * parent,di_node_t node,gchar * devfs_path,gchar * if_devfs_path,int ifnum)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
get_dev_link_path(di_node_t node,char * nodetype,char * re,char ** devlink,char ** minor_path,char ** minor_name)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) && (re != 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 *
devinfo_usb_video4linux_add(HalDevice * usbd,di_node_t node)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[0-9]+", &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 *
devinfo_usb_input_add(HalDevice * usbd,di_node_t node)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[0-9]+", &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 *
devinfo_usb_scsa2usb_add(HalDevice * usbd,di_node_t node)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",
633 "^usb/mass-storage[0-9]+", &devlink, &minor_path, &minor_name);
634
635 if ((devlink == NULL) || (minor_path == NULL)) {
636 goto out;
637 }
638
639 d = hal_device_new ();
640
641 devinfo_set_default_properties (d, usbd, node, minor_path);
642 hal_device_property_set_string (d, "scsi_host.solaris.device", devlink);
643 hal_device_property_set_string (d, "info.category", "scsi_host");
644 hal_device_property_set_int (d, "scsi_host.host", 0);
645
646 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
647 "%s/scsi_host%d", hal_device_get_udi (usbd),
648 hal_device_property_get_int (d, "scsi_host.host"));
649 hal_device_set_udi (d, udi);
650 hal_device_property_set_string (d, "info.udi", udi);
651 hal_device_property_set_string (d, "info.product", "SCSI Host Adapter");
652
653 devinfo_add_enqueue (d, minor_path, &devinfo_usb_handler);
654
655 out:
656 if (devlink) {
657 free(devlink);
658 }
659 if (minor_path) {
660 di_devfs_path_free (minor_path);
661 }
662
663 return (d);
664 }
665
666 static HalDevice *
devinfo_usb_printer_add(HalDevice * parent,di_node_t node)667 devinfo_usb_printer_add(HalDevice *parent, di_node_t node)
668 {
669 char *properties[] = { "vendor", "product", "serial", NULL };
670 int i;
671 HalDevice *d = NULL;
672 char udi[HAL_PATH_MAX];
673 char *s;
674 char *devlink = NULL, *minor_path = NULL, *minor_name = NULL;
675 const char *subsystem;
676
677 get_dev_link_path(node, "ddi_printer", "printers/.+", &devlink, &minor_path, &minor_name);
678
679 if ((devlink == NULL) || (minor_path == NULL)) {
680 goto out;
681 }
682
683 d = hal_device_new ();
684
685 devinfo_set_default_properties (d, parent, node, minor_path);
686 hal_device_property_set_string (d, "info.category", "printer");
687 hal_device_add_capability (d, "printer");
688
689 /* add printer properties */
690 hal_device_property_set_string (d, "printer.device", devlink);
691
692 /* copy parent's selected usb* properties to printer properties */
693 subsystem = hal_device_property_get_string (parent, "info.subsystem");
694 for (i = 0; properties[i] != NULL; i++) {
695 char src[32], dst[32]; /* "subsystem.property" names */
696
697 snprintf(src, sizeof (src), "%s.%s", subsystem, properties[i]);
698 snprintf(dst, sizeof (dst), "printer.%s", properties[i]);
699 hal_device_copy_property(parent, src, d, dst);
700 }
701
702 devinfo_add_enqueue (d, minor_path, &devinfo_usb_printer_handler);
703
704 out:
705 if (devlink) {
706 free(devlink);
707 }
708 if (minor_path) {
709 di_devfs_path_free (minor_path);
710 }
711
712 return (d);
713 }
714
715 const gchar *
devinfo_printer_prnio_get_prober(HalDevice * d,int * timeout)716 devinfo_printer_prnio_get_prober (HalDevice *d, int *timeout)
717 {
718 *timeout = 5 * 1000; /* 5 second timeout */
719 return ("hald-probe-printer");
720 }
721
722 const gchar *
devinfo_keyboard_get_prober(HalDevice * d,int * timeout)723 devinfo_keyboard_get_prober(HalDevice *d, int *timeout)
724 {
725 *timeout = 5 * 1000; /* 5 second timeout */
726 return ("hald-probe-xkb");
727 }
728