11 #include "usb_driver.h"
14 #define SERVICE_BINARY "/bin/service"
17 #define DEVMAN_TYPE_NAME "dev_type"
19 #define INVAL_MAJOR -1
20 #define MAX_CONFIG_DIRS 4
22 static void main_loop();
23 static void handle_event();
24 static void cleanup();
25 static void parse_config();
26 static void display_usage();
27 static enum dev_type
determine_type(char *path
);
28 static int get_major();
29 static void create_pid_file();
30 static void put_major(int major
);
31 static struct devmand_usb_driver
* match_usb_driver(struct usb_device_id
*id
);
32 static struct devmand_driver_instance
*find_instance(int dev_id
);
34 #define dbg(fmt, ... ) \
36 printf("%8s:%4d: %13s()| "fmt"\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__ )
38 static LIST_HEAD(usb_driver_head
, devmand_usb_driver
) drivers
=
39 LIST_HEAD_INITIALIZER(drivers
);
40 static LIST_HEAD(usb_driver_inst_head
, devmand_driver_instance
) instances
=
41 LIST_HEAD_INITIALIZER(instances
);
47 char *config_dirs
[MAX_CONFIG_DIRS
];
48 int config_dir_count
;
62 static struct global_args args
= {
64 .config_dirs
= {NULL
,NULL
,NULL
,NULL
},
65 .config_dir_count
= 0,
70 static struct option options
[] =
72 {"dir" , required_argument
, NULL
, 'd'},
73 {"path", required_argument
, NULL
, 'p'},
74 {"verbose", required_argument
, NULL
, 'v'},
75 {"check-config", no_argument
, NULL
, 'x'},
76 {0,0,0,0} /* terminating entry */
79 static char major_bitmap
[16]; /* can store up to 128 major number states */
82 /*===========================================================================*
84 *===========================================================================*/
85 int run_upscript(struct devmand_driver_instance
*inst
)
91 snprintf(cmdl
, 1024, "%s up %s %d %d",
92 inst
->drv
->upscript
, inst
->label
, inst
->major
, inst
->dev_id
);
93 dbg("Running Upscript: \"%s\"", cmdl
);
101 /*===========================================================================*
103 *===========================================================================*/
104 int run_cleanscript(struct devmand_usb_driver
*drv
)
110 snprintf(cmdl
, 1024, "%s clean %s ",
111 drv
->upscript
, drv
->devprefix
);
112 dbg("Running Upscript: \"%s\"", cmdl
);
123 /*===========================================================================*
125 *===========================================================================*/
126 int run_downscript(struct devmand_driver_instance
*inst
)
132 snprintf(cmdl
, 1024, "%s down %s %d",
133 inst
->drv
->downscript
, inst
->label
, inst
->major
);
135 dbg("Running Upscript: \"%s\"", cmdl
);
147 /*===========================================================================*
149 *===========================================================================*/
150 int stop_driver(struct devmand_driver_instance
*inst
)
156 snprintf(cmdl
, 1024, "%s down %s %d",
157 SERVICE_BINARY
, inst
->label
, inst
->dev_id
);
158 dbg("executing service: \"%s\"", cmdl
);
164 printf("Stopped driver %s with label %s for device %d.\n",
165 inst
->drv
->binary
, inst
->label
, inst
->dev_id
);
171 /*===========================================================================*
173 *===========================================================================*/
174 int start_driver(struct devmand_driver_instance
*inst
)
181 ret
= snprintf(inst
->label
, 32, "%s%d", inst
->drv
->devprefix
,
183 if (ret
< 0 || ret
> DEVMAND_DRIVER_LABEL_LEN
) {
184 dbg("label too long");
188 snprintf(cmdl
, 1024, "%s up %s -major %d -devid %d -label %s",
189 SERVICE_BINARY
, inst
->drv
->binary
, inst
->major
, inst
->dev_id
,
191 dbg("executing service: \"%s\"", cmdl
);
199 printf("Started driver %s with label %s for device %d.\n",
200 inst
->drv
->binary
, inst
->label
, inst
->dev_id
);
205 /*===========================================================================*
207 *===========================================================================*/
208 static struct devmand_driver_instance
*
209 find_instance(int dev_id
)
211 struct devmand_driver_instance
*inst
;
213 LIST_FOREACH(inst
, &instances
, list
) {
214 if (inst
->dev_id
== dev_id
) {
221 /*===========================================================================*
223 *===========================================================================*/
225 match_usb_id(struct devmand_usb_match_id
*mid
, struct usb_device_id
*id
)
228 unsigned long match
= mid
->match_flags
;
229 struct usb_device_id
*_id
= &mid
->match_id
;
231 if (match
& USB_MATCH_ID_VENDOR
)
232 if (id
->idVendor
!= _id
->idVendor
) res
= 0;
233 if (match
& USB_MATCH_ID_PRODUCT
)
234 if (id
->idProduct
!= _id
->idProduct
) res
= 0;
235 if (match
& USB_MATCH_BCD_DEVICE
)
236 if (id
->bcdDevice
!= _id
->bcdDevice
) res
= 0;
237 if (match
& USB_MATCH_DEVICE_PROTOCOL
)
238 if (id
->bDeviceProtocol
!= _id
->bDeviceProtocol
) res
= 0;
239 if (match
& USB_MATCH_DEVICE_SUBCLASS
)
240 if (id
->bDeviceSubClass
!= _id
->bDeviceSubClass
) res
= 0;
241 if (match
& USB_MATCH_DEVICE_PROTOCOL
)
242 if (id
->bDeviceProtocol
!= _id
->bDeviceProtocol
) res
= 0;
243 if (match
& USB_MATCH_INTERFACE_CLASS
)
244 if (id
->bInterfaceClass
!= _id
->bInterfaceClass
) res
= 0;
245 if (match
& USB_MATCH_INTERFACE_SUBCLASS
)
246 if (id
->bInterfaceSubClass
!= _id
->bInterfaceSubClass
) res
= 0;
247 if (match
& USB_MATCH_INTERFACE_PROTOCOL
)
248 if (id
->bInterfaceProtocol
!= _id
->bInterfaceProtocol
) res
= 0;
257 /*===========================================================================*
259 *===========================================================================*/
260 static struct devmand_usb_driver
*
261 match_usb_driver(struct usb_device_id
*id
)
263 struct devmand_usb_driver
*driver
;
264 struct devmand_usb_match_id
*mid
;
266 LIST_FOREACH(driver
, &drivers
, list
) {
267 LIST_FOREACH(mid
, &driver
->ids
, list
) {
268 if (match_usb_id(mid
, id
)) {
276 /*===========================================================================*
278 *===========================================================================*/
279 struct devmand_usb_driver
* add_usb_driver(char *name
)
281 struct devmand_usb_driver
*udrv
= (struct devmand_usb_driver
*)
282 malloc(sizeof(struct devmand_usb_driver
));
284 LIST_INSERT_HEAD(&drivers
, udrv
, list
);
285 LIST_INIT(&udrv
->ids
);
291 /*===========================================================================*
293 *===========================================================================*/
294 struct devmand_usb_match_id
*
296 (struct devmand_usb_driver
*drv
)
298 struct devmand_usb_match_id
*id
= (struct devmand_usb_match_id
*)
299 malloc(sizeof(struct devmand_usb_match_id
));
301 memset(id
, 0, sizeof(struct devmand_usb_match_id
));
303 LIST_INSERT_HEAD(&drv
->ids
, id
, list
);
309 /*===========================================================================*
311 *===========================================================================*/
312 static void parse_config()
314 int i
, status
, error
;
320 struct dirent
*result
;
321 char config_file
[PATH_MAX
];
323 dbg("Parsing configuration directories... ");
324 /* Next parse the configuration directories */
325 for(i
=0; i
< args
.config_dir_count
; i
++){
326 dirname
= args
.config_dirs
[i
];
327 dbg("Parsing config dir %s ", dirname
);
328 status
= stat(dirname
,&stats
);
331 dbg("Failed to read directory '%s':%s (skipping) \n",
332 dirname
,strerror(error
));
335 if (!S_ISDIR(stats
.st_mode
)){
336 dbg("Parse configuration skipping %s "
337 "(not a directory) \n",dirname
);
340 dir
= opendir(dirname
);
343 dbg("Parse configuration failed to read dir '%s'"
344 "(skipping) :%s\n",dirname
, strerror(error
));
347 while( (status
= readdir_r(dir
,&entry
,&result
)) == 0 ){
348 if (result
== NULL
){ /* last entry */
353 /* concatenate dir and file name to open it */
354 snprintf(config_file
,PATH_MAX
, "%s/%s",
355 dirname
,entry
.d_name
);
356 status
= stat(config_file
, &stats
);
359 dbg("Parse configuration Failed to stat file "
360 "'%s': %s (skipping)\n", config_file
,
363 if (S_ISREG(stats
.st_mode
)){
364 dbg("Parsing file %s",config_file
);
365 yyin
= fopen(config_file
, "r");
368 dbg("Can not open config file:"
377 dbg("Parsing configuration directories done... ");
381 /*===========================================================================*
383 *===========================================================================*/
384 static void cleanup() {
385 struct devmand_driver_instance
*inst
;
387 dbg("cleaning up... ");
388 /* quit all running drivers */
389 LIST_FOREACH(inst
, &instances
, list
) {
390 dbg("stopping driver %s", inst
->label
);
391 run_downscript (inst
);
394 unlink("/var/run/devmand.pid");
397 static void sig_int(int sig
) {
398 dbg("devman: Received SIGINT... cleaning up.");
402 /*===========================================================================*
404 *===========================================================================*/
405 void create_pid_file()
409 fd
= fopen("/var/run/devmand.pid", "r");
411 fprintf(stderr
, "devmand: /var/run/devmand.pid exists... "
412 "another devmand running?\n");
416 fd
= fopen("/var/run/devmand.pid","w");
417 fprintf(fd
, "%d", getpid());
422 /*===========================================================================*
424 *===========================================================================*/
425 int main(int argc
, char *argv
[])
428 struct devmand_usb_driver
*driver
;
431 /* get command line arguments */
432 while ((opt
= getopt_long(argc
, argv
, "d:p:vxh?", options
, &optindex
))
435 case 'd':/* config directory */
436 if (args
.config_dir_count
>= MAX_CONFIG_DIRS
){
437 fprintf(stderr
,"Parse arguments: Maximum"
438 " of %i configuration directories"
439 " reached skipping directory '%s'\n"
440 , MAX_CONFIG_DIRS
, optarg
);
443 args
.config_dirs
[args
.config_dir_count
] = optarg
;
444 args
.config_dir_count
++;
446 case 'p': /* sysfs path */
449 case 'v': /* verbose */
452 case 'x': /* check config */
453 args
.check_config
= 1;
458 display_usage(argv
[0]);
465 if (args
.path
== NULL
) {
469 /* is the configuration directory set? */
470 if (args
.config_dir_count
== 0) {
471 dbg("Using default configuration directory");
472 args
.config_dirs
[0] = "/etc/devmand";
473 args
.config_dir_count
= 1;
476 /* If we only check the configuration run and exit imediately */
477 if (args
.check_config
== 1){
478 fprintf(stdout
, "Only parsing configuration\n");
486 LIST_FOREACH(driver
, &drivers
, list
) {
487 run_cleanscript(driver
);
490 signal(SIGINT
, sig_int
);
499 /*===========================================================================*
501 *===========================================================================*/
502 static enum dev_type
determine_type (char *path
)
509 mypath
= (char *) calloc(1, strlen(path
)+strlen(DEVMAN_TYPE_NAME
)+1);
511 if (mypath
== NULL
) {
512 fprintf(stderr
, "ERROR: out of mem\n");
517 strcat(mypath
, path
);
518 strcat(mypath
, DEVMAN_TYPE_NAME
);
520 fd
= fopen(mypath
, "r");
524 fprintf(stderr
, "WARN: could not open %s\n", mypath
);
525 return DEV_TYPE_UNKOWN
;
528 res
= fscanf(fd
, "%s\n", buf
);
532 fprintf(stderr
, "WARN: could not parse %s\n", mypath
);
533 return DEV_TYPE_UNKOWN
;
536 if (strcmp(buf
, "USB_DEV") == 0) {
537 return DEV_TYPE_USB_DEVICE
;
538 } else if (strcmp(buf
, "USB_INTF") == 0) {
539 return DEV_TYPE_USB_INTF
;
542 return DEV_TYPE_UNKOWN
;
545 /*===========================================================================*
547 *===========================================================================*/
548 static int read_hex_uint(char *base_path
, char *name
, unsigned int* val
)
550 char my_path
[PATH_LEN
];
552 memset(my_path
,0,PATH_LEN
);
555 strcat(my_path
, base_path
);
556 strcat(my_path
, name
);
558 fd
= fopen(my_path
, "r");
561 fprintf(stderr
, "WARN: could not open %s\n", my_path
);
563 } else if (fscanf(fd
, "0x%x\n", val
) != 1) {
564 fprintf(stderr
, "WARN: could not parse %s\n", my_path
);
572 /*===========================================================================*
574 *===========================================================================*/
575 static int get_major() {
576 int i
, ret
= args
.major_offset
;
578 for (i
=0; i
< 16; i
++) {
580 for (j
= 0; j
< 8; j
++ ) {
581 if ((major_bitmap
[i
] & (1 << j
))) {
582 major_bitmap
[i
] &= !(1 << j
);
591 /*===========================================================================*
593 *===========================================================================*/
594 static void put_major(int major
) {
596 major
-= args
.major_offset
;
599 for (i
=0; i
< 16; i
++) {
601 for (j
= 0; j
< 8; j
++ ) {
603 assert(!(major_bitmap
[i
] & (1 <<j
)));
604 major_bitmap
[i
] |= (1 << j
);
612 /*===========================================================================*
613 * generate_usb_device_id *
614 *===========================================================================*/
615 static struct usb_device_id
*
616 generate_usb_device_id(char * path
, int is_interface
)
618 struct usb_device_id
*ret
;
622 ret
= (struct usb_device_id
*)
623 calloc(1,sizeof (struct usb_device_id
));
627 res
= read_hex_uint(path
, "../idVendor", &val
);
631 res
= read_hex_uint(path
, "../idProduct", &val
);
633 ret
->idProduct
= val
;
635 res
= read_hex_uint(path
, "../bcdDevice", &val
);
637 ret
->bcdDevice
= val
;
639 res
= read_hex_uint(path
, "../bDeviceClass", &val
);
641 ret
->bDeviceClass
= val
;
643 res
= read_hex_uint(path
, "../bDeviceSubClass", &val
);
645 ret
->bDeviceSubClass
= val
;
647 res
= read_hex_uint(path
, "../bDeviceProtocol", &val
);
649 ret
->bDeviceProtocol
= val
;
651 res
= read_hex_uint(path
, "/bInterfaceClass", &val
);
653 ret
->bInterfaceClass
= val
;
655 res
= read_hex_uint(path
, "/bInterfaceSubClass", &val
);
657 ret
->bInterfaceSubClass
= val
;
659 res
= read_hex_uint(path
, "/bInterfaceProtocol", &val
);
661 ret
->bInterfaceProtocol
= val
;
671 /*===========================================================================*
672 * usb_intf_add_even *
673 *===========================================================================*/
674 static void usb_intf_add_event(char *path
, int dev_id
)
676 struct usb_device_id
*id
;
677 struct devmand_usb_driver
*drv
;
678 struct devmand_driver_instance
*drv_inst
;
681 /* generate usb_match_id */
682 id
= generate_usb_device_id(path
,TRUE
);
684 fprintf(stderr
, "WARN: could not create usb_device id...\n"
685 " ommiting event\n");
690 /* find suitable driver */
691 drv
= match_usb_driver(id
);
695 dbg("INFO: could not find a suitable driver for %s", path
);
699 /* create instance */
700 drv_inst
= (struct devmand_driver_instance
*)
701 calloc(1,sizeof(struct devmand_driver_instance
));
703 if (drv_inst
== NULL
) {
704 fprintf(stderr
, "ERROR: out of memory");
705 return; /* maybe better quit here. */
709 /* allocate inode number, if device files needed */
711 if (major
== INVAL_MAJOR
) {
712 fprintf(stderr
, "WARN: ran out of major numbers\n"
713 " cannot start driver %s for %s\n",
718 drv_inst
->major
= major
;
720 drv_inst
->dev_id
= dev_id
;
723 /* start driver (invoke service) */
724 start_driver(drv_inst
);
729 * An up action can be any executable. Before running it devmand
730 * will set certain environment variables so the script can configure
731 * the device (or generate device files, etc). See up_action() for that.
734 ret
= run_upscript(drv_inst
);
736 stop_driver(drv_inst
);
737 fprintf(stderr
, "devmand: warning, could not run up_action\n");
743 LIST_INSERT_HEAD(&instances
,drv_inst
,list
);
746 /*===========================================================================*
747 * usb_intf_remove_event *
748 *===========================================================================*/
749 static void usb_intf_remove_event(char *path
, int dev_id
)
751 struct devmand_driver_instance
*inst
;
752 struct devmand_usb_driver
*drv
;
755 /* find the driver instance */
756 inst
= find_instance(dev_id
);
759 dbg("No driver running for id: %d", dev_id
);
764 /* run the down script */
765 if (drv
->downscript
) {
766 ret
= run_downscript(inst
);
768 fprintf(stderr
, "WARN: error running up_action");
772 /* stop the driver */
776 put_major(inst
->major
);
779 LIST_REMOVE(inst
,list
);
783 /*===========================================================================*
785 *===========================================================================*/
786 static void handle_event(char *event
)
790 char tmp_path
[PATH_LEN
];
795 if (strncmp("ADD ", event
, 4) == 0) {
797 /* read data from event */
798 res
= sscanf(event
, "ADD %s 0x%x", tmp_path
, &dev_id
);
801 fprintf(stderr
, "WARN: could not parse event: %s", event
);
802 fprintf(stderr
, "WARN: omitting event: %s", event
);
805 strcpy(path
, args
.path
);
806 strcat(path
, tmp_path
);
808 /* what kind of device is added? */
809 type
= determine_type(path
);
812 case DEV_TYPE_USB_DEVICE
:
813 dbg("USB device added: ommited....");
814 /* ommit usb devices for now */
816 case DEV_TYPE_USB_INTF
:
817 dbg("USB interface added: (%s, devid: = %d)",path
, dev_id
);
818 usb_intf_add_event(path
, dev_id
);
822 fprintf(stderr
, "WARN: ommiting event\n");
824 } else if (strncmp("REMOVE ", event
, 7) == 0) {
826 /* read data from event */
827 res
= sscanf(event
,"REMOVE %s 0x%x", tmp_path
, &dev_id
);
830 fprintf(stderr
, "WARN: could not parse event: %s", event
);
831 fprintf(stderr
, "WARN: omitting event: %s", event
);
834 usb_intf_remove_event(path
, dev_id
);
837 strcpy(path
, args
.path
);
838 strcat(path
, tmp_path
);
840 /* what kind of device is added? */
841 type
= determine_type(path
);
844 case DEV_TYPE_USB_DEVICE
:
845 /* ommit usb devices for now */
847 case DEV_TYPE_USB_INTF
:
848 usb_intf_remove_event(path
, dev_id
);
851 fprintf(stderr
, "WARN: ommiting event\n");
858 /*===========================================================================*
860 *===========================================================================*/
861 static void main_loop()
867 len
= strlen(args
.path
);
869 /* init major numbers */
871 memset(&major_bitmap
, 0xff, 16);
873 if (len
> 128 - 7 /*len of "events" */) {
874 fprintf(stderr
, "pathname to long\n");
879 strcpy(ev_path
, args
.path
);
880 strcat(ev_path
, "events");
887 fd
= fopen(ev_path
, "r");
889 fprintf(stderr
,"devmand error: could not open event "
890 "file %s bailing out\n", ev_path
);
895 res
= fgets(buf
, 256, fd
);
902 dbg("handle_event: %s", buf
);
907 /*===========================================================================*
909 *===========================================================================*/
910 static void display_usage(const char *name
)
912 printf("Usage: %s [{-p|--pathname} PATH_TO_SYS}"
913 " [{-d|--config-dir} CONFIG_DIR] [-v|--verbose]"
914 " [[x||--check-config]\n", name
);