]>
Commit | Line | Data |
---|---|---|
93afd047 MT |
1 | #include <stdio.h> |
2 | #include <stdlib.h> | |
3 | #include <string.h> | |
4 | #include <unistd.h> | |
5 | #include <fcntl.h> | |
6 | #include <errno.h> | |
7 | #include <sys/stat.h> | |
8 | #include <sys/types.h> | |
9 | #include <sys/ioctl.h> | |
10 | ||
11 | #include "hd.h" | |
12 | #include "hd_int.h" | |
13 | #include "hddb.h" | |
14 | #include "usb.h" | |
15 | ||
16 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
17 | * usb | |
18 | * | |
19 | * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
20 | */ | |
21 | ||
22 | #define IOCNR_GET_DEVICE_ID 1 | |
23 | #define IOCNR_GET_BUS_ADDRESS 5 | |
24 | #define IOCNR_GET_VID_PID 6 | |
25 | ||
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) | |
32 | ||
33 | ||
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); | |
40 | ||
41 | void hd_scan_sysfs_usb(hd_data_t *hd_data) | |
42 | { | |
43 | if(!hd_probe_feature(hd_data, pr_usb)) return; | |
44 | ||
45 | hd_data->module = mod_usb; | |
46 | ||
47 | /* some clean-up */ | |
48 | remove_hd_entries(hd_data); | |
49 | hd_data->proc_usb = free_str_list(hd_data->proc_usb); | |
50 | hd_data->usb = NULL; | |
51 | ||
52 | PROGRESS(1, 0, "sysfs drivers"); | |
53 | ||
54 | hd_sysfs_driver_list(hd_data); | |
55 | ||
56 | PROGRESS(2, 0, "usb"); | |
57 | ||
58 | get_usb_devs(hd_data); | |
59 | ||
60 | PROGRESS(3, 1, "joydev mod"); | |
61 | load_module(hd_data, "joydev"); | |
62 | ||
63 | PROGRESS(3, 2, "evdev mod"); | |
64 | load_module(hd_data, "evdev"); | |
65 | ||
66 | PROGRESS(3, 3, "input"); | |
67 | get_input_devs(hd_data); | |
68 | ||
69 | PROGRESS(3, 4, "lp"); | |
70 | get_printer_devs(hd_data); | |
71 | ||
72 | PROGRESS(3, 5, "serial"); | |
73 | get_serial_devs(hd_data); | |
74 | ||
75 | } | |
76 | ||
77 | ||
78 | void get_usb_devs(hd_data_t *hd_data) | |
79 | { | |
80 | uint64_t ul0; | |
81 | unsigned u1, u2, u3; | |
82 | hd_t *hd, *hd1; | |
83 | usb_t *usb; | |
84 | str_list_t *sl, *usb_devs = NULL; | |
85 | char *s, *s1, *t; | |
86 | hd_res_t *res; | |
87 | size_t l; | |
88 | ||
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; | |
93 | ||
94 | sf_bus = sysfs_open_bus("usb"); | |
95 | ||
96 | if(!sf_bus) { | |
97 | ADD2LOG("sysfs: no such bus: usb\n"); | |
98 | return; | |
99 | } | |
100 | ||
101 | sf_dev_list = sysfs_get_bus_devices(sf_bus); | |
102 | ||
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)); | |
107 | } | |
108 | } | |
109 | ||
110 | if(sf_dev_list) dlist_for_each_data(sf_dev_list, sf_dev, struct sysfs_device) { | |
111 | ADD2LOG( | |
112 | " usb device: name = %s, bus_id = %s, bus = %s\n path = %s\n", | |
113 | sf_dev->name, | |
114 | sf_dev->bus_id, | |
115 | sf_dev->bus, | |
116 | hd_sysfs_id(sf_dev->path) | |
117 | ); | |
118 | ||
119 | if( | |
120 | hd_attr_uint(sysfs_get_device_attr(sf_dev, "bInterfaceNumber"), &ul0, 16) | |
121 | ) { | |
122 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
123 | ||
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); | |
127 | ||
128 | hd->sysfs_id = new_str(hd_sysfs_id(sf_dev->path)); | |
129 | hd->sysfs_bus_id = new_str(sf_dev->bus_id); | |
130 | ||
131 | hd->bus.id = bus_usb; | |
132 | hd->func = ul0; | |
133 | ||
134 | usb->ifdescr = ul0; | |
135 | ||
136 | ADD2LOG(" bInterfaceNumber = %u\n", hd->func); | |
137 | ||
138 | if(hd_attr_uint(sysfs_get_device_attr(sf_dev, "bInterfaceClass"), &ul0, 16)) { | |
139 | usb->i_cls = ul0; | |
140 | ADD2LOG(" bInterfaceClass = %u\n", usb->i_cls); | |
141 | } | |
142 | ||
143 | if(hd_attr_uint(sysfs_get_device_attr(sf_dev, "bInterfaceSubClass"), &ul0, 16)) { | |
144 | usb->i_sub = ul0; | |
145 | ADD2LOG(" bInterfaceSubClass = %u\n", usb->i_sub); | |
146 | } | |
147 | ||
148 | if(hd_attr_uint(sysfs_get_device_attr(sf_dev, "bInterfaceProtocol"), &ul0, 16)) { | |
149 | usb->i_prot = ul0; | |
150 | ADD2LOG(" bInterfaceProtocol = %u\n", usb->i_prot); | |
151 | } | |
152 | ||
153 | /* device has longest matching sysfs id */ | |
154 | u2 = strlen(sf_dev->path); | |
155 | s = NULL; | |
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)) { | |
159 | u3 = u1; | |
160 | s = sl->str; | |
161 | } | |
162 | } | |
163 | ||
164 | if(s) { | |
165 | ADD2LOG(" if: %s @ %s\n", hd->sysfs_bus_id, hd_sysfs_id(s)); | |
166 | sf_dev_2 = sysfs_open_device_path(s); | |
167 | if(sf_dev_2) { | |
168 | ||
169 | if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2, "bDeviceClass"), &ul0, 16)) { | |
170 | usb->d_cls = ul0; | |
171 | ADD2LOG(" bDeviceClass = %u\n", usb->d_cls); | |
172 | } | |
173 | ||
174 | if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2, "bDeviceSubClass"), &ul0, 16)) { | |
175 | usb->d_sub = ul0; | |
176 | ADD2LOG(" bDeviceSubClass = %u\n", usb->d_sub); | |
177 | } | |
178 | ||
179 | if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2, "bDeviceProtocol"), &ul0, 16)) { | |
180 | usb->d_prot = ul0; | |
181 | ADD2LOG(" bDeviceProtocol = %u\n", usb->d_prot); | |
182 | } | |
183 | ||
184 | if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2, "idVendor"), &ul0, 16)) { | |
185 | usb->vendor = ul0; | |
186 | ADD2LOG(" idVendor = 0x%04x\n", usb->vendor); | |
187 | } | |
188 | ||
189 | if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2, "idProduct"), &ul0, 16)) { | |
190 | usb->device = ul0; | |
191 | ADD2LOG(" idProduct = 0x%04x\n", usb->device); | |
192 | } | |
193 | ||
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); | |
197 | } | |
198 | ||
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); | |
202 | } | |
203 | ||
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); | |
207 | } | |
208 | ||
209 | if(hd_attr_uint(sysfs_get_device_attr(sf_dev_2, "bcdDevice"), &ul0, 16)) { | |
210 | usb->rev = ul0; | |
211 | ADD2LOG(" bcdDevice = %04x\n", usb->rev); | |
212 | } | |
213 | ||
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); | |
220 | s = free_mem(s); | |
221 | } | |
222 | ||
223 | sysfs_close_device(sf_dev_2); | |
224 | } | |
225 | } | |
226 | ||
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); | |
230 | } | |
231 | ||
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); | |
235 | ||
236 | if(usb->rev) str_printf(&hd->revision.name, 0, "%x.%02x", usb->rev >> 8, usb->rev & 0xff); | |
237 | ||
238 | if(usb->speed) { | |
239 | res = add_res_entry(&hd->res, new_mem(sizeof *res)); | |
240 | res->baud.type = res_baud; | |
241 | res->baud.speed = usb->speed; | |
242 | } | |
243 | ||
244 | s = hd_sysfs_find_driver(hd_data, hd->sysfs_id, 1); | |
245 | if(s) add_str_list(&hd->drivers, s); | |
246 | ||
247 | set_class_entries(hd_data, hd, usb); | |
248 | ||
249 | if(!hd_data->scanner_db) { | |
250 | hd_data->scanner_db = hd_module_list(hd_data, 1); | |
251 | } | |
252 | ||
253 | if( | |
254 | hd->drivers && | |
255 | search_str_list(hd_data->scanner_db, hd->drivers->str) | |
256 | ) { | |
257 | hd->base_class.id = bc_scanner; | |
258 | } | |
259 | ||
260 | // ###### FIXME | |
261 | if(hd->base_class.id == bc_modem) { | |
262 | hd->unix_dev_name = new_str("/dev/ttyACM0"); | |
263 | } | |
264 | ||
265 | } | |
266 | } | |
267 | ||
268 | sysfs_close_bus(sf_bus); | |
269 | ||
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) { | |
273 | ||
274 | s = new_str(hd->sysfs_id); | |
275 | t = strrchr(s, '/'); | |
276 | if(t) *t = 0; | |
277 | ||
278 | /* parent has longest matching sysfs id */ | |
279 | u2 = strlen(s); | |
280 | for(u3 = 0, hd1 = hd_data->hd; hd1; hd1 = hd1->next) { | |
281 | if(hd1->sysfs_id) { | |
282 | s1 = new_str(hd1->sysfs_id); | |
283 | ||
284 | if(hd1->module == hd_data->module) { | |
285 | t = strrchr(s1, ':'); | |
286 | if(t) *t = 0; | |
287 | l = strlen(s1); | |
288 | if(l > 2 && s1[l-2] == '-' && s1[l-1] == '0') { | |
289 | /* root hub */ | |
290 | s1[l-2] = 0 ; | |
291 | } | |
292 | } | |
293 | ||
294 | u1 = strlen(s1); | |
295 | if(u1 > u3 && u1 <= u2 && !strncmp(s, s1, u1)) { | |
296 | u3 = u1; | |
297 | hd->attached_to = hd1->idx; | |
298 | } | |
299 | ||
300 | s1 = free_mem(s1); | |
301 | } | |
302 | } | |
303 | ||
304 | s = free_mem(s); | |
305 | } | |
306 | } | |
307 | ||
308 | /* remove some entries */ | |
309 | for(hd = hd_data->hd; hd; hd = hd->next) { | |
310 | if( | |
311 | hd->module == hd_data->module && | |
312 | hd->sysfs_id && | |
313 | !hd->tag.remove | |
314 | ) { | |
315 | ||
316 | s = new_str(hd->sysfs_id); | |
317 | t = strrchr(s, ':'); | |
318 | if(t) *t = 0; | |
319 | ||
320 | for(hd1 = hd_data->hd; hd1; hd1 = hd1->next) { | |
321 | if( | |
322 | hd1 != hd && | |
323 | hd1->module == hd_data->module && | |
324 | hd1->sysfs_id && | |
325 | !hd1->tag.remove && | |
326 | hd1->base_class.id == hd->base_class.id | |
327 | ) { | |
328 | ||
329 | s1 = new_str(hd1->sysfs_id); | |
330 | t = strrchr(s1, ':'); | |
331 | if(t) *t = 0; | |
332 | ||
333 | /* same usb device */ | |
334 | if(!strcmp(s, s1)) { | |
335 | hd1->tag.remove = 1; | |
336 | ADD2LOG("removed: %s\n", hd1->sysfs_id); | |
337 | } | |
338 | ||
339 | s1 = free_mem(s1); | |
340 | } | |
341 | } | |
342 | ||
343 | s = free_mem(s); | |
344 | } | |
345 | } | |
346 | ||
347 | remove_tagged_hd_entries(hd_data); | |
348 | ||
349 | ||
350 | } | |
351 | ||
352 | ||
353 | void set_class_entries(hd_data_t *hd_data, hd_t *hd, usb_t *usb) | |
354 | { | |
355 | int cls, sub, prot; | |
356 | unsigned u; | |
357 | ||
358 | if(usb->d_cls) { | |
359 | cls = usb->d_cls; sub = usb->d_sub; prot = usb->d_prot; | |
360 | } | |
361 | else { | |
362 | cls = usb->i_cls; sub = usb->i_sub; prot = usb->i_prot; | |
363 | } | |
364 | ||
365 | switch(cls) { | |
366 | case 2: | |
367 | if(usb->i_sub == 6 && usb->i_prot == 0) { | |
368 | hd->base_class.id = bc_network; | |
369 | hd->sub_class.id = 0x91; | |
370 | } | |
371 | else if(usb->i_sub == 2 && usb->i_prot >= 1 && usb->i_prot <= 6) { | |
372 | hd->base_class.id = bc_modem; | |
373 | } | |
374 | break; | |
375 | ||
376 | case 3: | |
377 | if(sub == 1 && prot == 1) { | |
378 | hd->base_class.id = bc_keyboard; | |
379 | hd->sub_class.id = sc_keyboard_kbd; | |
380 | break; | |
381 | } | |
382 | if(sub == 1 && prot == 2) { | |
383 | if(!( | |
384 | (usb->vendor == 0x056a && usb->device == 0x0022) /* Wacom Tablet */ | |
385 | // || (usb->vendor == 0x08ca && usb->device == 0x0020) /* AIPTEK APT-6000U tablet */ | |
386 | )) { | |
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); | |
391 | } | |
392 | break; | |
393 | } | |
394 | break; | |
395 | ||
396 | case 6: | |
397 | if(sub == 1 && prot == 1) { /* PTP camera */ | |
398 | hd->base_class.id = bc_camera; | |
399 | hd->sub_class.id = sc_camera_digital; | |
400 | break; | |
401 | } | |
402 | break; | |
403 | ||
404 | case 7: | |
405 | hd->base_class.id = bc_printer; | |
406 | break; | |
407 | ||
408 | case 8: | |
409 | hd->base_class.id = bc_storage_device; | |
410 | switch(sub) { | |
411 | case 1: /* flash devices & removable media */ | |
412 | case 5: | |
413 | case 6: | |
414 | hd->sub_class.id = sc_sdev_disk; | |
415 | break; | |
416 | case 2: | |
417 | hd->sub_class.id = sc_sdev_cdrom; | |
418 | break; | |
419 | case 3: | |
420 | hd->sub_class.id = sc_sdev_tape; | |
421 | break; | |
422 | case 4: | |
423 | hd->sub_class.id = sc_sdev_floppy; | |
424 | break; | |
425 | default: | |
426 | hd->sub_class.id = sc_sdev_other; | |
427 | } | |
428 | break; | |
429 | ||
430 | case 9: | |
431 | hd->base_class.id = bc_hub; | |
432 | break; | |
433 | ||
434 | case 0xe0: | |
435 | if(sub == 1 && prot == 1) { | |
436 | hd->base_class.id = bc_bluetooth; | |
437 | hd->sub_class.id = 0; | |
438 | } | |
439 | break; | |
440 | ||
441 | case 0xff: | |
442 | /* hp psc 2100, 2200, 2150, officejet 6100 */ | |
443 | if( | |
444 | sub == 0xcc && | |
445 | ( | |
446 | usb->vendor == 0x03f0 && | |
447 | ( | |
448 | usb->device == 0x2811 || | |
449 | usb->device == 0x2911 || | |
450 | usb->device == 0x2a11 || | |
451 | usb->device == 0x2d11 | |
452 | ) | |
453 | ) | |
454 | ) { | |
455 | hd->base_class.id = bc_scanner; | |
456 | hd->sub_class.id = 1; | |
457 | } | |
458 | break; | |
459 | } | |
460 | ||
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; | |
464 | } | |
465 | ||
466 | /* FIXME: hack for bt isdn box */ | |
467 | if( | |
468 | hd->vendor.id == MAKE_ID(TAG_USB, 0x057c) && | |
469 | hd->device.id == MAKE_ID(TAG_USB, 0x2200) | |
470 | ) { | |
471 | hd_set_hw_class(hd, hw_bluetooth); | |
472 | } | |
473 | ||
474 | } | |
475 | ||
476 | ||
477 | void get_input_devs(hd_data_t *hd_data) | |
478 | { | |
479 | hd_t *hd; | |
480 | char *s, *t; | |
481 | hd_dev_num_t dev_num; | |
482 | unsigned u1, u2; | |
483 | ||
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; | |
488 | ||
489 | sf_class = sysfs_open_class("input"); | |
490 | ||
491 | if(!sf_class) { | |
492 | ADD2LOG("sysfs: no such class: input\n"); | |
493 | return; | |
494 | } | |
495 | ||
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) { | |
498 | ADD2LOG( | |
499 | " input: name = %s, path = %s\n", | |
500 | sf_cdev->name, | |
501 | hd_sysfs_id(sf_cdev->path) | |
502 | ); | |
503 | ||
504 | if((s = hd_attr_str(sysfs_get_classdev_attr(sf_cdev, "dev")))) { | |
505 | if(sscanf(s, "%u:%u", &u1, &u2) == 2) { | |
506 | dev_num.type = 'c'; | |
507 | dev_num.major = u1; | |
508 | dev_num.minor = u2; | |
509 | dev_num.range = 1; | |
510 | } | |
511 | ADD2LOG(" dev = %u:%u\n", u1, u2); | |
512 | } | |
513 | ||
514 | sf_dev = sysfs_get_classdev_device(sf_cdev); | |
515 | if(sf_dev) { | |
516 | s = hd_sysfs_id(sf_dev->path); | |
517 | ||
518 | ADD2LOG( | |
519 | " input device: bus = %s, bus_id = %s driver = %s\n path = %s\n", | |
520 | sf_dev->bus, | |
521 | sf_dev->bus_id, | |
522 | sf_dev->driver_name, | |
523 | s | |
524 | ); | |
525 | ||
526 | for(hd = hd_data->hd; hd; hd = hd->next) { | |
527 | if( | |
528 | hd->module == hd_data->module && | |
529 | hd->sysfs_id && | |
530 | s && | |
531 | !strcmp(s, hd->sysfs_id) | |
532 | ) { | |
533 | t = NULL; | |
534 | str_printf(&t, 0, "/dev/input/%s", sf_cdev->name); | |
535 | ||
536 | if(strncmp(sf_cdev->name, "mouse", sizeof "mouse" - 1)) { | |
537 | hd->unix_dev_name = t; | |
538 | hd->unix_dev_num = dev_num; | |
539 | } | |
540 | else { | |
541 | hd->unix_dev_name2 = t; | |
542 | hd->unix_dev_num2 = dev_num; | |
543 | ||
544 | dev_num.major = 13; | |
545 | dev_num.minor = 63; | |
546 | hd->unix_dev_name = new_str(DEV_MICE); | |
547 | hd->unix_dev_num = dev_num; | |
548 | } | |
549 | } | |
550 | } | |
551 | } | |
552 | } | |
553 | ||
554 | sysfs_close_class(sf_class); | |
555 | } | |
556 | ||
557 | ||
558 | void get_printer_devs(hd_data_t *hd_data) | |
559 | { | |
560 | hd_t *hd; | |
561 | char *s, *t; | |
562 | hd_dev_num_t dev_num; | |
563 | unsigned u1, u2; | |
564 | ||
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; | |
569 | ||
570 | sf_class = sysfs_open_class("usb"); | |
571 | ||
572 | if(!sf_class) { | |
573 | ADD2LOG("sysfs: no such class: usb\n"); | |
574 | return; | |
575 | } | |
576 | ||
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; | |
580 | ||
581 | ADD2LOG( | |
582 | " usb: name = %s, path = %s\n", | |
583 | sf_cdev->name, | |
584 | hd_sysfs_id(sf_cdev->path) | |
585 | ); | |
586 | ||
587 | if((s = hd_attr_str(sysfs_get_classdev_attr(sf_cdev, "dev")))) { | |
588 | if(sscanf(s, "%u:%u", &u1, &u2) == 2) { | |
589 | dev_num.type = 'c'; | |
590 | dev_num.major = u1; | |
591 | dev_num.minor = u2; | |
592 | dev_num.range = 1; | |
593 | } | |
594 | ADD2LOG(" dev = %u:%u\n", u1, u2); | |
595 | } | |
596 | ||
597 | sf_dev = sysfs_get_classdev_device(sf_cdev); | |
598 | if(sf_dev) { | |
599 | s = hd_sysfs_id(sf_dev->path); | |
600 | ||
601 | ADD2LOG( | |
602 | " usb device: bus = %s, bus_id = %s driver = %s\n path = %s\n", | |
603 | sf_dev->bus, | |
604 | sf_dev->bus_id, | |
605 | sf_dev->driver_name, | |
606 | s | |
607 | ); | |
608 | ||
609 | for(hd = hd_data->hd; hd; hd = hd->next) { | |
610 | if( | |
611 | hd->module == hd_data->module && | |
612 | hd->sysfs_id && | |
613 | s && | |
614 | !strcmp(s, hd->sysfs_id) | |
615 | ) { | |
616 | t = NULL; | |
617 | str_printf(&t, 0, "/dev/usb/%s", sf_cdev->name); | |
618 | ||
619 | hd->unix_dev_name = t; | |
620 | hd->unix_dev_num = dev_num; | |
621 | ||
622 | read_usb_lp(hd_data, hd); | |
623 | } | |
624 | } | |
625 | } | |
626 | } | |
627 | ||
628 | sysfs_close_class(sf_class); | |
629 | } | |
630 | ||
631 | ||
632 | #define MATCH_FIELD(field, var) \ | |
633 | if(!strncasecmp(sl->str, field, sizeof field - 1)) var = sl->str + sizeof field - 1 | |
634 | ||
635 | /* | |
636 | * assign /dev/usb/lp* to usb printers. | |
637 | */ | |
638 | void read_usb_lp(hd_data_t *hd_data, hd_t *hd) | |
639 | { | |
640 | char *s; | |
641 | char buf[1024]; | |
642 | int fd, two_ints[2]; | |
643 | unsigned bus; | |
644 | str_list_t *sl0, *sl; | |
645 | char *vend, *prod, *serial, *descr; | |
646 | ||
647 | if((fd = open(hd->unix_dev_name, O_RDWR)) < 0) return; | |
648 | ||
649 | if(ioctl(fd, LPIOC_GET_BUS_ADDRESS(sizeof two_ints), two_ints) == -1) { | |
650 | close(fd); | |
651 | return; | |
652 | } | |
653 | ||
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); | |
656 | ||
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]); | |
660 | } | |
661 | ||
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); | |
668 | free_mem(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); | |
679 | } | |
680 | ADD2LOG( | |
681 | " usb/lp: vend = %s, prod = %s, descr = %s, serial = %s\n", | |
682 | vend ?: "", prod ?: "", descr ?: "", serial ?: "" | |
683 | ); | |
684 | if(descr) { | |
685 | str_printf(&hd->model, 0, "%s", descr); | |
686 | } | |
687 | if(vend && prod) { | |
688 | str_printf(&hd->sub_vendor.name, 0, "%s", vend); | |
689 | str_printf(&hd->sub_device.name, 0, "%s", prod); | |
690 | } | |
691 | if(serial && !hd->serial) { | |
692 | hd->serial = new_str(serial); | |
693 | } | |
694 | ||
695 | free_str_list(sl0); | |
696 | } | |
697 | ||
698 | close(fd); | |
699 | } | |
700 | #undef MATCH_FIELD | |
701 | ||
702 | ||
703 | void get_serial_devs(hd_data_t *hd_data) | |
704 | { | |
705 | hd_t *hd; | |
706 | char *s, *t; | |
707 | hd_dev_num_t dev_num; | |
708 | unsigned u1, u2; | |
709 | ||
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; | |
714 | ||
715 | sf_class = sysfs_open_class("tty"); | |
716 | ||
717 | if(!sf_class) { | |
718 | ADD2LOG("sysfs: no such class: tty\n"); | |
719 | return; | |
720 | } | |
721 | ||
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; | |
725 | ||
726 | ADD2LOG( | |
727 | " usb: name = %s, path = %s\n", | |
728 | sf_cdev->name, | |
729 | hd_sysfs_id(sf_cdev->path) | |
730 | ); | |
731 | ||
732 | if((s = hd_attr_str(sysfs_get_classdev_attr(sf_cdev, "dev")))) { | |
733 | if(sscanf(s, "%u:%u", &u1, &u2) == 2) { | |
734 | dev_num.type = 'c'; | |
735 | dev_num.major = u1; | |
736 | dev_num.minor = u2; | |
737 | dev_num.range = 1; | |
738 | } | |
739 | ADD2LOG(" dev = %u:%u\n", u1, u2); | |
740 | } | |
741 | ||
742 | sf_dev = sysfs_get_classdev_device(sf_cdev); | |
743 | if(sf_dev) { | |
744 | s = hd_sysfs_id(sf_dev->path); | |
745 | ||
746 | if((t = strrchr(s, '/')) && !strncmp(t + 1, "ttyUSB", sizeof "ttyUSB" - 1)) *t =0; | |
747 | ||
748 | ADD2LOG( | |
749 | " usb device: bus = %s, bus_id = %s driver = %s\n path = %s\n", | |
750 | sf_dev->bus, | |
751 | sf_dev->bus_id, | |
752 | sf_dev->driver_name, | |
753 | s | |
754 | ); | |
755 | ||
756 | for(hd = hd_data->hd; hd; hd = hd->next) { | |
757 | if( | |
758 | hd->module == hd_data->module && | |
759 | hd->sysfs_id && | |
760 | s && | |
761 | !strcmp(s, hd->sysfs_id) | |
762 | ) { | |
763 | t = NULL; | |
764 | str_printf(&t, 0, "/dev/%s", sf_cdev->name); | |
765 | ||
766 | hd->unix_dev_name = t; | |
767 | hd->unix_dev_num = dev_num; | |
768 | ||
769 | hd->base_class.id = bc_comm; | |
770 | hd->sub_class.id = sc_com_ser; | |
771 | hd->prog_if.id = 0x80; | |
772 | } | |
773 | } | |
774 | } | |
775 | } | |
776 | ||
777 | sysfs_close_class(sf_class); | |
778 | } | |
779 | ||
780 |