]>
git.ipfire.org Git - ipfire-2.x.git/blob - src/hwinfo/src/hd/usb.c
16 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
19 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22 #define IOCNR_GET_DEVICE_ID 1
23 #define IOCNR_GET_BUS_ADDRESS 5
24 #define IOCNR_GET_VID_PID 6
26 /* Get device_id string: */
27 #define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
28 /* Get two-int array: [0]=bus number, [1]=device address: */
29 #define LPIOC_GET_BUS_ADDRESS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_BUS_ADDRESS, len)
30 /* Get two-int array: [0]=vendor ID, [1]=product ID: */
31 #define LPIOC_GET_VID_PID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_VID_PID, len)
34 static void get_usb_devs(hd_data_t
*hd_data
);
35 static void set_class_entries(hd_data_t
*hd_data
, hd_t
*hd
, usb_t
*usb
);
36 static void get_input_devs(hd_data_t
*hd_data
);
37 static void get_printer_devs(hd_data_t
*hd_data
);
38 static void read_usb_lp(hd_data_t
*hd_data
, hd_t
*hd
);
39 static void get_serial_devs(hd_data_t
*hd_data
);
41 void hd_scan_sysfs_usb(hd_data_t
*hd_data
)
43 if(!hd_probe_feature(hd_data
, pr_usb
)) return;
45 hd_data
->module
= mod_usb
;
48 remove_hd_entries(hd_data
);
49 hd_data
->proc_usb
= free_str_list(hd_data
->proc_usb
);
52 PROGRESS(1, 0, "sysfs drivers");
54 hd_sysfs_driver_list(hd_data
);
56 PROGRESS(2, 0, "usb");
58 get_usb_devs(hd_data
);
60 PROGRESS(3, 1, "joydev mod");
61 load_module(hd_data
, "joydev");
63 PROGRESS(3, 2, "evdev mod");
64 load_module(hd_data
, "evdev");
66 PROGRESS(3, 3, "input");
67 get_input_devs(hd_data
);
70 get_printer_devs(hd_data
);
72 PROGRESS(3, 5, "serial");
73 get_serial_devs(hd_data
);
78 void get_usb_devs(hd_data_t
*hd_data
)
84 str_list_t
*sl
, *usb_devs
= NULL
;
89 struct sysfs_bus
*sf_bus
;
90 struct dlist
*sf_dev_list
;
91 struct sysfs_device
*sf_dev
;
92 struct sysfs_device
*sf_dev_2
;
94 sf_bus
= sysfs_open_bus("usb");
97 ADD2LOG("sysfs: no such bus: usb\n");
101 sf_dev_list
= sysfs_get_bus_devices(sf_bus
);
103 if(sf_dev_list
) dlist_for_each_data(sf_dev_list
, sf_dev
, struct sysfs_device
) {
104 if(hd_attr_uint(sysfs_get_device_attr(sf_dev
, "bNumInterfaces"), &ul0
, 0)) {
105 add_str_list(&usb_devs
, sf_dev
->path
);
106 ADD2LOG(" usb dev: %s\n", hd_sysfs_id(sf_dev
->path
));
110 if(sf_dev_list
) dlist_for_each_data(sf_dev_list
, sf_dev
, struct sysfs_device
) {
112 " usb device: name = %s, bus_id = %s, bus = %s\n path = %s\n",
116 hd_sysfs_id(sf_dev
->path
)
120 hd_attr_uint(sysfs_get_device_attr(sf_dev
, "bInterfaceNumber"), &ul0
, 16)
122 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
124 hd
->detail
= new_mem(sizeof *hd
->detail
);
125 hd
->detail
->type
= hd_detail_usb
;
126 hd
->detail
->usb
.data
= usb
= new_mem(sizeof *usb
);
128 hd
->sysfs_id
= new_str(hd_sysfs_id(sf_dev
->path
));
129 hd
->sysfs_bus_id
= new_str(sf_dev
->bus_id
);
131 hd
->bus
.id
= bus_usb
;
136 ADD2LOG(" bInterfaceNumber = %u\n", hd
->func
);
138 if(hd_attr_uint(sysfs_get_device_attr(sf_dev
, "bInterfaceClass"), &ul0
, 16)) {
140 ADD2LOG(" bInterfaceClass = %u\n", usb
->i_cls
);
143 if(hd_attr_uint(sysfs_get_device_attr(sf_dev
, "bInterfaceSubClass"), &ul0
, 16)) {
145 ADD2LOG(" bInterfaceSubClass = %u\n", usb
->i_sub
);
148 if(hd_attr_uint(sysfs_get_device_attr(sf_dev
, "bInterfaceProtocol"), &ul0
, 16)) {
150 ADD2LOG(" bInterfaceProtocol = %u\n", usb
->i_prot
);
153 /* device has longest matching sysfs id */
154 u2
= strlen(sf_dev
->path
);
156 for(u3
= 0, sl
= usb_devs
; sl
; sl
= sl
->next
) {
157 u1
= strlen(sl
->str
);
158 if(u1
> u3
&& u1
<= u2
&& !strncmp(sf_dev
->path
, sl
->str
, u1
)) {
165 ADD2LOG(" if: %s @ %s\n", hd
->sysfs_bus_id
, hd_sysfs_id(s
));
166 sf_dev_2
= sysfs_open_device_path(s
);
169 if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2
, "bDeviceClass"), &ul0
, 16)) {
171 ADD2LOG(" bDeviceClass = %u\n", usb
->d_cls
);
174 if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2
, "bDeviceSubClass"), &ul0
, 16)) {
176 ADD2LOG(" bDeviceSubClass = %u\n", usb
->d_sub
);
179 if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2
, "bDeviceProtocol"), &ul0
, 16)) {
181 ADD2LOG(" bDeviceProtocol = %u\n", usb
->d_prot
);
184 if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2
, "idVendor"), &ul0
, 16)) {
186 ADD2LOG(" idVendor = 0x%04x\n", usb
->vendor
);
189 if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2
, "idProduct"), &ul0
, 16)) {
191 ADD2LOG(" idProduct = 0x%04x\n", usb
->device
);
194 if((s
= hd_attr_str(sysfs_get_device_attr(sf_dev_2
, "manufacturer")))) {
195 usb
->manufact
= canon_str(s
, strlen(s
));
196 ADD2LOG(" manufacturer = \"%s\"\n", usb
->manufact
);
199 if((s
= hd_attr_str(sysfs_get_device_attr(sf_dev_2
, "product")))) {
200 usb
->product
= canon_str(s
, strlen(s
));
201 ADD2LOG(" product = \"%s\"\n", usb
->product
);
204 if((s
= hd_attr_str(sysfs_get_device_attr(sf_dev_2
, "serial")))) {
205 usb
->serial
= canon_str(s
, strlen(s
));
206 ADD2LOG(" serial = \"%s\"\n", usb
->serial
);
209 if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2
, "bcdDevice"), &ul0
, 16)) {
211 ADD2LOG(" bcdDevice = %04x\n", usb
->rev
);
214 if((s
= hd_attr_str(sysfs_get_device_attr(sf_dev_2
, "speed")))) {
215 s
= canon_str(s
, strlen(s
));
216 if(strcmp(s
, "1.5")) usb
->speed
= 15*100000;
217 else if(strcmp(s
, "12")) usb
->speed
= 12*1000000;
218 else if(strcmp(s
, "240")) usb
->speed
= 240*1000000;
219 ADD2LOG(" speed = \"%s\"\n", s
);
223 sysfs_close_device(sf_dev_2
);
227 if(usb
->vendor
|| usb
->device
) {
228 hd
->vendor
.id
= MAKE_ID(TAG_USB
, usb
->vendor
);
229 hd
->device
.id
= MAKE_ID(TAG_USB
, usb
->device
);
232 if(usb
->manufact
) hd
->vendor
.name
= new_str(usb
->manufact
);
233 if(usb
->product
) hd
->device
.name
= new_str(usb
->product
);
234 if(usb
->serial
) hd
->serial
= new_str(usb
->serial
);
236 if(usb
->rev
) str_printf(&hd
->revision
.name
, 0, "%x.%02x", usb
->rev
>> 8, usb
->rev
& 0xff);
239 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
240 res
->baud
.type
= res_baud
;
241 res
->baud
.speed
= usb
->speed
;
244 s
= hd_sysfs_find_driver(hd_data
, hd
->sysfs_id
, 1);
245 if(s
) add_str_list(&hd
->drivers
, s
);
247 set_class_entries(hd_data
, hd
, usb
);
249 if(!hd_data
->scanner_db
) {
250 hd_data
->scanner_db
= hd_module_list(hd_data
, 1);
255 search_str_list(hd_data
->scanner_db
, hd
->drivers
->str
)
257 hd
->base_class
.id
= bc_scanner
;
261 if(hd
->base_class
.id
== bc_modem
) {
262 hd
->unix_dev_name
= new_str("/dev/ttyACM0");
268 sysfs_close_bus(sf_bus
);
270 /* connect usb devices to each other */
271 for(hd
= hd_data
->hd
; hd
; hd
= hd
->next
) {
272 if(hd
->module
== hd_data
->module
&& hd
->sysfs_id
) {
274 s
= new_str(hd
->sysfs_id
);
278 /* parent has longest matching sysfs id */
280 for(u3
= 0, hd1
= hd_data
->hd
; hd1
; hd1
= hd1
->next
) {
282 s1
= new_str(hd1
->sysfs_id
);
284 if(hd1
->module
== hd_data
->module
) {
285 t
= strrchr(s1
, ':');
288 if(l
> 2 && s1
[l
-2] == '-' && s1
[l
-1] == '0') {
295 if(u1
> u3
&& u1
<= u2
&& !strncmp(s
, s1
, u1
)) {
297 hd
->attached_to
= hd1
->idx
;
308 /* remove some entries */
309 for(hd
= hd_data
->hd
; hd
; hd
= hd
->next
) {
311 hd
->module
== hd_data
->module
&&
316 s
= new_str(hd
->sysfs_id
);
320 for(hd1
= hd_data
->hd
; hd1
; hd1
= hd1
->next
) {
323 hd1
->module
== hd_data
->module
&&
326 hd1
->base_class
.id
== hd
->base_class
.id
329 s1
= new_str(hd1
->sysfs_id
);
330 t
= strrchr(s1
, ':');
333 /* same usb device */
336 ADD2LOG("removed: %s\n", hd1
->sysfs_id
);
347 remove_tagged_hd_entries(hd_data
);
353 void set_class_entries(hd_data_t
*hd_data
, hd_t
*hd
, usb_t
*usb
)
359 cls
= usb
->d_cls
; sub
= usb
->d_sub
; prot
= usb
->d_prot
;
362 cls
= usb
->i_cls
; sub
= usb
->i_sub
; prot
= usb
->i_prot
;
367 if(usb
->i_sub
== 6 && usb
->i_prot
== 0) {
368 hd
->base_class
.id
= bc_network
;
369 hd
->sub_class
.id
= 0x91;
371 else if(usb
->i_sub
== 2 && usb
->i_prot
>= 1 && usb
->i_prot
<= 6) {
372 hd
->base_class
.id
= bc_modem
;
377 if(sub
== 1 && prot
== 1) {
378 hd
->base_class
.id
= bc_keyboard
;
379 hd
->sub_class
.id
= sc_keyboard_kbd
;
382 if(sub
== 1 && prot
== 2) {
384 (usb
->vendor
== 0x056a && usb
->device
== 0x0022) /* Wacom Tablet */
385 // || (usb->vendor == 0x08ca && usb->device == 0x0020) /* AIPTEK APT-6000U tablet */
387 hd
->base_class
.id
= bc_mouse
;
388 hd
->sub_class
.id
= sc_mou_usb
;
389 hd
->compat_vendor
.id
= MAKE_ID(TAG_SPECIAL
, 0x0200);
390 hd
->compat_device
.id
= MAKE_ID(TAG_SPECIAL
, 0x001);
397 if(sub
== 1 && prot
== 1) { /* PTP camera */
398 hd
->base_class
.id
= bc_camera
;
399 hd
->sub_class
.id
= sc_camera_digital
;
405 hd
->base_class
.id
= bc_printer
;
409 hd
->base_class
.id
= bc_storage_device
;
411 case 1: /* flash devices & removable media */
414 hd
->sub_class
.id
= sc_sdev_disk
;
417 hd
->sub_class
.id
= sc_sdev_cdrom
;
420 hd
->sub_class
.id
= sc_sdev_tape
;
423 hd
->sub_class
.id
= sc_sdev_floppy
;
426 hd
->sub_class
.id
= sc_sdev_other
;
431 hd
->base_class
.id
= bc_hub
;
435 if(sub
== 1 && prot
== 1) {
436 hd
->base_class
.id
= bc_bluetooth
;
437 hd
->sub_class
.id
= 0;
442 /* hp psc 2100, 2200, 2150, officejet 6100 */
446 usb
->vendor
== 0x03f0 &&
448 usb
->device
== 0x2811 ||
449 usb
->device
== 0x2911 ||
450 usb
->device
== 0x2a11 ||
451 usb
->device
== 0x2d11
455 hd
->base_class
.id
= bc_scanner
;
456 hd
->sub_class
.id
= 1;
461 if((u
= device_class(hd_data
, hd
->vendor
.id
, hd
->device
.id
))) {
462 hd
->base_class
.id
= u
>> 8;
463 hd
->sub_class
.id
= u
& 0xff;
466 /* FIXME: hack for bt isdn box */
468 hd
->vendor
.id
== MAKE_ID(TAG_USB
, 0x057c) &&
469 hd
->device
.id
== MAKE_ID(TAG_USB
, 0x2200)
471 hd_set_hw_class(hd
, hw_bluetooth
);
477 void get_input_devs(hd_data_t
*hd_data
)
481 hd_dev_num_t dev_num
;
484 struct sysfs_class
*sf_class
;
485 struct sysfs_class_device
*sf_cdev
;
486 struct sysfs_device
*sf_dev
;
487 struct dlist
*sf_cdev_list
;
489 sf_class
= sysfs_open_class("input");
492 ADD2LOG("sysfs: no such class: input\n");
496 sf_cdev_list
= sysfs_get_class_devices(sf_class
);
497 if(sf_cdev_list
) dlist_for_each_data(sf_cdev_list
, sf_cdev
, struct sysfs_class_device
) {
499 " input: name = %s, path = %s\n",
501 hd_sysfs_id(sf_cdev
->path
)
504 if((s
= hd_attr_str(sysfs_get_classdev_attr(sf_cdev
, "dev")))) {
505 if(sscanf(s
, "%u:%u", &u1
, &u2
) == 2) {
511 ADD2LOG(" dev = %u:%u\n", u1
, u2
);
514 sf_dev
= sysfs_get_classdev_device(sf_cdev
);
516 s
= hd_sysfs_id(sf_dev
->path
);
519 " input device: bus = %s, bus_id = %s driver = %s\n path = %s\n",
526 for(hd
= hd_data
->hd
; hd
; hd
= hd
->next
) {
528 hd
->module
== hd_data
->module
&&
531 !strcmp(s
, hd
->sysfs_id
)
534 str_printf(&t
, 0, "/dev/input/%s", sf_cdev
->name
);
536 if(strncmp(sf_cdev
->name
, "mouse", sizeof "mouse" - 1)) {
537 hd
->unix_dev_name
= t
;
538 hd
->unix_dev_num
= dev_num
;
541 hd
->unix_dev_name2
= t
;
542 hd
->unix_dev_num2
= dev_num
;
546 hd
->unix_dev_name
= new_str(DEV_MICE
);
547 hd
->unix_dev_num
= dev_num
;
554 sysfs_close_class(sf_class
);
558 void get_printer_devs(hd_data_t
*hd_data
)
562 hd_dev_num_t dev_num
;
565 struct sysfs_class
*sf_class
;
566 struct sysfs_class_device
*sf_cdev
;
567 struct sysfs_device
*sf_dev
;
568 struct dlist
*sf_cdev_list
;
570 sf_class
= sysfs_open_class("usb");
573 ADD2LOG("sysfs: no such class: usb\n");
577 sf_cdev_list
= sysfs_get_class_devices(sf_class
);
578 if(sf_cdev_list
) dlist_for_each_data(sf_cdev_list
, sf_cdev
, struct sysfs_class_device
) {
579 if(strncmp(sf_cdev
->name
, "lp", 2)) continue;
582 " usb: name = %s, path = %s\n",
584 hd_sysfs_id(sf_cdev
->path
)
587 if((s
= hd_attr_str(sysfs_get_classdev_attr(sf_cdev
, "dev")))) {
588 if(sscanf(s
, "%u:%u", &u1
, &u2
) == 2) {
594 ADD2LOG(" dev = %u:%u\n", u1
, u2
);
597 sf_dev
= sysfs_get_classdev_device(sf_cdev
);
599 s
= hd_sysfs_id(sf_dev
->path
);
602 " usb device: bus = %s, bus_id = %s driver = %s\n path = %s\n",
609 for(hd
= hd_data
->hd
; hd
; hd
= hd
->next
) {
611 hd
->module
== hd_data
->module
&&
614 !strcmp(s
, hd
->sysfs_id
)
617 str_printf(&t
, 0, "/dev/usb/%s", sf_cdev
->name
);
619 hd
->unix_dev_name
= t
;
620 hd
->unix_dev_num
= dev_num
;
622 read_usb_lp(hd_data
, hd
);
628 sysfs_close_class(sf_class
);
632 #define MATCH_FIELD(field, var) \
633 if(!strncasecmp(sl->str, field, sizeof field - 1)) var = sl->str + sizeof field - 1
636 * assign /dev/usb/lp* to usb printers.
638 void read_usb_lp(hd_data_t
*hd_data
, hd_t
*hd
)
644 str_list_t
*sl0
, *sl
;
645 char *vend
, *prod
, *serial
, *descr
;
647 if((fd
= open(hd
->unix_dev_name
, O_RDWR
)) < 0) return;
649 if(ioctl(fd
, LPIOC_GET_BUS_ADDRESS(sizeof two_ints
), two_ints
) == -1) {
654 ADD2LOG(" usb/lp: bus = %d, dev_nr = %d\n", two_ints
[0], two_ints
[1]);
655 bus
= ((two_ints
[0] & 0xff) << 8) + (two_ints
[1] & 0xff);
657 if(ioctl(fd
, LPIOC_GET_VID_PID(sizeof two_ints
), two_ints
) != -1) {
658 /* just for the record */
659 ADD2LOG(" usb/lp: vend = 0x%04x, prod = 0x%04x\n", two_ints
[0], two_ints
[1]);
662 memset(buf
, 0, sizeof buf
);
663 if(!ioctl(fd
, LPIOC_GET_DEVICE_ID(sizeof buf
), buf
)) {
664 buf
[sizeof buf
- 1] = 0;
665 s
= canon_str(buf
+ 2, sizeof buf
- 3);
666 ADD2LOG(" usb/lp: \"%s\"\n", s
);
667 sl0
= hd_split(';', s
);
669 vend
= prod
= serial
= descr
= NULL
;
670 for(sl
= sl0
; sl
; sl
= sl
->next
) {
671 MATCH_FIELD("MFG:", vend
);
672 MATCH_FIELD("MANUFACTURER:", vend
);
673 MATCH_FIELD("MDL:", prod
);
674 MATCH_FIELD("MODEL:", prod
);
675 MATCH_FIELD("DES:", descr
);
676 MATCH_FIELD("DESCRIPTION:", descr
);
677 MATCH_FIELD("SERN:", serial
);
678 MATCH_FIELD("SERIALNUMBER:", serial
);
681 " usb/lp: vend = %s, prod = %s, descr = %s, serial = %s\n",
682 vend
?: "", prod
?: "", descr
?: "", serial
?: ""
685 str_printf(&hd
->model
, 0, "%s", descr
);
688 str_printf(&hd
->sub_vendor
.name
, 0, "%s", vend
);
689 str_printf(&hd
->sub_device
.name
, 0, "%s", prod
);
691 if(serial
&& !hd
->serial
) {
692 hd
->serial
= new_str(serial
);
703 void get_serial_devs(hd_data_t
*hd_data
)
707 hd_dev_num_t dev_num
;
710 struct sysfs_class
*sf_class
;
711 struct sysfs_class_device
*sf_cdev
;
712 struct sysfs_device
*sf_dev
;
713 struct dlist
*sf_cdev_list
;
715 sf_class
= sysfs_open_class("tty");
718 ADD2LOG("sysfs: no such class: tty\n");
722 sf_cdev_list
= sysfs_get_class_devices(sf_class
);
723 if(sf_cdev_list
) dlist_for_each_data(sf_cdev_list
, sf_cdev
, struct sysfs_class_device
) {
724 if(strncmp(sf_cdev
->name
, "ttyUSB", 6)) continue;
727 " usb: name = %s, path = %s\n",
729 hd_sysfs_id(sf_cdev
->path
)
732 if((s
= hd_attr_str(sysfs_get_classdev_attr(sf_cdev
, "dev")))) {
733 if(sscanf(s
, "%u:%u", &u1
, &u2
) == 2) {
739 ADD2LOG(" dev = %u:%u\n", u1
, u2
);
742 sf_dev
= sysfs_get_classdev_device(sf_cdev
);
744 s
= hd_sysfs_id(sf_dev
->path
);
746 if((t
= strrchr(s
, '/')) && !strncmp(t
+ 1, "ttyUSB", sizeof "ttyUSB" - 1)) *t
=0;
749 " usb device: bus = %s, bus_id = %s driver = %s\n path = %s\n",
756 for(hd
= hd_data
->hd
; hd
; hd
= hd
->next
) {
758 hd
->module
== hd_data
->module
&&
761 !strcmp(s
, hd
->sysfs_id
)
764 str_printf(&t
, 0, "/dev/%s", sf_cdev
->name
);
766 hd
->unix_dev_name
= t
;
767 hd
->unix_dev_num
= dev_num
;
769 hd
->base_class
.id
= bc_comm
;
770 hd
->sub_class
.id
= sc_com_ser
;
771 hd
->prog_if
.id
= 0x80;
777 sysfs_close_class(sf_class
);