11 #include <minix/dmap.h>
12 #include <minix/paths.h>
13 #include "usb_driver.h"
16 #define DEVMAN_TYPE_NAME "dev_type"
18 #define INVAL_MAJOR -1
19 #define MAX_CONFIG_DIRS 4
21 static void main_loop();
22 static void handle_event();
23 static void cleanup();
24 static void parse_config();
25 static void display_usage();
26 static enum dev_type
determine_type(char *path
);
27 static int get_major();
28 static void create_pid_file();
29 static void put_major(int major
);
30 static struct devmand_usb_driver
* match_usb_driver(struct usb_device_id
*id
);
31 static struct devmand_driver_instance
*find_instance(int dev_id
);
33 #define dbg(fmt, ... ) \
35 printf("%8s:%4d: %13s()| "fmt"\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__ )
37 static LIST_HEAD(usb_driver_head
, devmand_usb_driver
) drivers
=
38 LIST_HEAD_INITIALIZER(drivers
);
39 static LIST_HEAD(usb_driver_inst_head
, devmand_driver_instance
) instances
=
40 LIST_HEAD_INITIALIZER(instances
);
46 char *config_dirs
[MAX_CONFIG_DIRS
];
47 int config_dir_count
;
61 static struct global_args args
= {
63 .config_dirs
= {NULL
,NULL
,NULL
,NULL
},
64 .config_dir_count
= 0,
65 .major_offset
= USB_BASE_MAJOR
,
69 static struct option options
[] =
71 {"dir" , required_argument
, NULL
, 'd'},
72 {"path", required_argument
, NULL
, 'p'},
73 {"verbose", required_argument
, NULL
, 'v'},
74 {"check-config", no_argument
, NULL
, 'x'},
75 {0,0,0,0} /* terminating entry */
78 static char major_bitmap
[16]; /* can store up to 128 major number states */
81 /*===========================================================================*
83 *===========================================================================*/
84 int run_upscript(struct devmand_driver_instance
*inst
)
90 assert(inst
->drv
->upscript
);
93 snprintf(cmdl
, 1024, "%s up %s %d %d",
94 inst
->drv
->upscript
, inst
->label
, inst
->major
, inst
->dev_id
);
95 dbg("Running Upscript: \"%s\"", cmdl
);
103 /*===========================================================================*
105 *===========================================================================*/
106 int run_cleanscript(struct devmand_usb_driver
*drv
)
112 assert(drv
->upscript
);
113 assert(drv
->devprefix
);
115 snprintf(cmdl
, 1024, "%s clean %s ",
116 drv
->upscript
, drv
->devprefix
);
117 dbg("Running Upscript: \"%s\"", cmdl
);
128 /*===========================================================================*
130 *===========================================================================*/
131 int run_downscript(struct devmand_driver_instance
*inst
)
137 assert(inst
->drv
->downscript
);
140 snprintf(cmdl
, 1024, "%s down %s %d",
141 inst
->drv
->downscript
, inst
->label
, inst
->major
);
143 dbg("Running Upscript: \"%s\"", cmdl
);
155 /*===========================================================================*
157 *===========================================================================*/
158 int stop_driver(struct devmand_driver_instance
*inst
)
166 snprintf(cmdl
, 1024, "%s down %s %d",
167 _PATH_MINIX_SERVICE
, inst
->label
, inst
->dev_id
);
168 dbg("executing minix-service: \"%s\"", cmdl
);
174 printf("Stopped driver %s with label %s for device %d.\n",
175 inst
->drv
->binary
, inst
->label
, inst
->dev_id
);
181 /*===========================================================================*
183 *===========================================================================*/
184 int start_driver(struct devmand_driver_instance
*inst
)
191 ret
= snprintf(inst
->label
, 32, "%s%d", inst
->drv
->devprefix
,
193 if (ret
< 0 || ret
> DEVMAND_DRIVER_LABEL_LEN
) {
194 dbg("label too long");
198 assert(inst
->drv
->binary
);
201 snprintf(cmdl
, 1024, "%s up %s -major %d -devid %d -label %s",
202 _PATH_MINIX_SERVICE
, inst
->drv
->binary
, inst
->major
, inst
->dev_id
,
204 dbg("executing minix-service: \"%s\"", cmdl
);
212 printf("Started driver %s with label %s for device %d.\n",
213 inst
->drv
->binary
, inst
->label
, inst
->dev_id
);
218 /*===========================================================================*
220 *===========================================================================*/
221 static struct devmand_driver_instance
*
222 find_instance(int dev_id
)
224 struct devmand_driver_instance
*inst
;
226 LIST_FOREACH(inst
, &instances
, list
) {
227 if (inst
->dev_id
== dev_id
) {
234 /*===========================================================================*
236 *===========================================================================*/
238 match_usb_id(struct devmand_usb_match_id
*mid
, struct usb_device_id
*id
)
241 unsigned long match
= mid
->match_flags
;
242 struct usb_device_id
*_id
= &mid
->match_id
;
244 if (match
& USB_MATCH_ID_VENDOR
)
245 if (id
->idVendor
!= _id
->idVendor
) res
= 0;
246 if (match
& USB_MATCH_ID_PRODUCT
)
247 if (id
->idProduct
!= _id
->idProduct
) res
= 0;
248 if (match
& USB_MATCH_BCD_DEVICE
)
249 if (id
->bcdDevice
!= _id
->bcdDevice
) res
= 0;
250 if (match
& USB_MATCH_DEVICE_PROTOCOL
)
251 if (id
->bDeviceProtocol
!= _id
->bDeviceProtocol
) res
= 0;
252 if (match
& USB_MATCH_DEVICE_SUBCLASS
)
253 if (id
->bDeviceSubClass
!= _id
->bDeviceSubClass
) res
= 0;
254 if (match
& USB_MATCH_DEVICE_PROTOCOL
)
255 if (id
->bDeviceProtocol
!= _id
->bDeviceProtocol
) res
= 0;
256 if (match
& USB_MATCH_INTERFACE_CLASS
)
257 if (id
->bInterfaceClass
!= _id
->bInterfaceClass
) res
= 0;
258 if (match
& USB_MATCH_INTERFACE_SUBCLASS
)
259 if (id
->bInterfaceSubClass
!= _id
->bInterfaceSubClass
) res
= 0;
260 if (match
& USB_MATCH_INTERFACE_PROTOCOL
)
261 if (id
->bInterfaceProtocol
!= _id
->bInterfaceProtocol
) res
= 0;
270 /*===========================================================================*
272 *===========================================================================*/
273 static struct devmand_usb_driver
*
274 match_usb_driver(struct usb_device_id
*id
)
276 struct devmand_usb_driver
*driver
;
277 struct devmand_usb_match_id
*mid
;
279 LIST_FOREACH(driver
, &drivers
, list
) {
280 LIST_FOREACH(mid
, &driver
->ids
, list
) {
281 if (match_usb_id(mid
, id
)) {
289 /*===========================================================================*
291 *===========================================================================*/
292 struct devmand_usb_driver
* add_usb_driver(char *name
)
294 struct devmand_usb_driver
*udrv
= (struct devmand_usb_driver
*)
295 malloc(sizeof(struct devmand_usb_driver
));
297 LIST_INSERT_HEAD(&drivers
, udrv
, list
);
298 LIST_INIT(&udrv
->ids
);
304 /*===========================================================================*
306 *===========================================================================*/
307 struct devmand_usb_match_id
*
309 (struct devmand_usb_driver
*drv
)
311 struct devmand_usb_match_id
*id
= (struct devmand_usb_match_id
*)
312 malloc(sizeof(struct devmand_usb_match_id
));
314 memset(id
, 0, sizeof(struct devmand_usb_match_id
));
316 LIST_INSERT_HEAD(&drv
->ids
, id
, list
);
322 /*===========================================================================*
324 *===========================================================================*/
325 static void parse_config()
327 int i
, status
, error
;
333 struct dirent
*result
;
334 char config_file
[PATH_MAX
];
336 dbg("Parsing configuration directories... ");
337 /* Next parse the configuration directories */
338 for(i
=0; i
< args
.config_dir_count
; i
++){
339 dirname
= args
.config_dirs
[i
];
340 dbg("Parsing config dir %s ", dirname
);
341 status
= stat(dirname
,&stats
);
344 dbg("Failed to read directory '%s':%s (skipping) \n",
345 dirname
,strerror(error
));
348 if (!S_ISDIR(stats
.st_mode
)){
349 dbg("Parse configuration skipping %s "
350 "(not a directory) \n",dirname
);
353 dir
= opendir(dirname
);
356 dbg("Parse configuration failed to read dir '%s'"
357 "(skipping) :%s\n",dirname
, strerror(error
));
360 while( (status
= readdir_r(dir
,&entry
,&result
)) == 0 ){
361 if (result
== NULL
){ /* last entry */
366 /* concatenate dir and file name to open it */
367 snprintf(config_file
,PATH_MAX
, "%s/%s",
368 dirname
,entry
.d_name
);
369 status
= stat(config_file
, &stats
);
372 dbg("Parse configuration Failed to stat file "
373 "'%s': %s (skipping)\n", config_file
,
376 if (S_ISREG(stats
.st_mode
)){
377 dbg("Parsing file %s",config_file
);
378 yyin
= fopen(config_file
, "r");
381 dbg("Can not open config file:"
390 dbg("Parsing configuration directories done... ");
394 /*===========================================================================*
396 *===========================================================================*/
397 static void cleanup() {
398 struct devmand_driver_instance
*inst
;
400 dbg("cleaning up... ");
401 /* quit all running drivers */
402 LIST_FOREACH(inst
, &instances
, list
) {
403 dbg("stopping driver %s", inst
->label
);
404 if(inst
->drv
->downscript
) {
405 run_downscript (inst
);
409 unlink("/var/run/devmand.pid");
412 static void sig_int(int sig
) {
413 dbg("devman: Received SIGINT... cleaning up.");
417 /*===========================================================================*
419 *===========================================================================*/
420 void create_pid_file()
424 fd
= fopen("/var/run/devmand.pid", "r");
426 fprintf(stderr
, "devmand: /var/run/devmand.pid exists... "
427 "another devmand running?\n");
431 fd
= fopen("/var/run/devmand.pid","w");
432 fprintf(fd
, "%d", getpid());
437 /*===========================================================================*
439 *===========================================================================*/
440 int main(int argc
, char *argv
[])
443 struct devmand_usb_driver
*driver
;
446 /* get command line arguments */
447 while ((opt
= getopt_long(argc
, argv
, "d:p:vxh?", options
, &optindex
))
450 case 'd':/* config directory */
451 if (args
.config_dir_count
>= MAX_CONFIG_DIRS
){
452 fprintf(stderr
,"Parse arguments: Maximum"
453 " of %i configuration directories"
454 " reached skipping directory '%s'\n"
455 , MAX_CONFIG_DIRS
, optarg
);
458 args
.config_dirs
[args
.config_dir_count
] = optarg
;
459 args
.config_dir_count
++;
461 case 'p': /* sysfs path */
464 case 'v': /* verbose */
467 case 'x': /* check config */
468 args
.check_config
= 1;
473 display_usage(argv
[0]);
480 if (args
.path
== NULL
) {
484 /* is the configuration directory set? */
485 if (args
.config_dir_count
== 0) {
486 dbg("Using default configuration directory");
487 args
.config_dirs
[0] = "/etc/devmand";
488 args
.config_dir_count
= 1;
491 /* If we only check the configuration run and exit imediately */
492 if (args
.check_config
== 1){
493 fprintf(stdout
, "Only parsing configuration\n");
501 LIST_FOREACH(driver
, &drivers
, list
) {
502 if (driver
->upscript
) {
503 run_cleanscript(driver
);
507 signal(SIGINT
, sig_int
);
516 /*===========================================================================*
518 *===========================================================================*/
519 static enum dev_type
determine_type (char *path
)
526 mypath
= (char *) calloc(1, strlen(path
)+strlen(DEVMAN_TYPE_NAME
)+1);
528 if (mypath
== NULL
) {
529 fprintf(stderr
, "ERROR: out of mem\n");
534 strcat(mypath
, path
);
535 strcat(mypath
, DEVMAN_TYPE_NAME
);
537 fd
= fopen(mypath
, "r");
541 fprintf(stderr
, "WARN: could not open %s\n", mypath
);
542 return DEV_TYPE_UNKOWN
;
545 res
= fscanf(fd
, "%255s\n", buf
);
549 fprintf(stderr
, "WARN: could not parse %s\n", mypath
);
550 return DEV_TYPE_UNKOWN
;
553 if (strcmp(buf
, "USB_DEV") == 0) {
554 return DEV_TYPE_USB_DEVICE
;
555 } else if (strcmp(buf
, "USB_INTF") == 0) {
556 return DEV_TYPE_USB_INTF
;
559 return DEV_TYPE_UNKOWN
;
562 /*===========================================================================*
564 *===========================================================================*/
565 static int read_hex_uint(char *base_path
, char *name
, unsigned int* val
)
567 char my_path
[PATH_LEN
];
569 memset(my_path
,0,PATH_LEN
);
572 strcat(my_path
, base_path
);
573 strcat(my_path
, name
);
575 fd
= fopen(my_path
, "r");
578 fprintf(stderr
, "WARN: could not open %s\n", my_path
);
580 } else if (fscanf(fd
, "0x%x\n", val
) != 1) {
581 fprintf(stderr
, "WARN: could not parse %s\n", my_path
);
589 /*===========================================================================*
591 *===========================================================================*/
592 static int get_major() {
593 int i
, ret
= args
.major_offset
;
595 for (i
=0; i
< 16; i
++) {
597 for (j
= 0; j
< 8; j
++ ) {
598 if ((major_bitmap
[i
] & (1 << j
))) {
599 major_bitmap
[i
] &= !(1 << j
);
608 /*===========================================================================*
610 *===========================================================================*/
611 static void put_major(int major
) {
613 major
-= args
.major_offset
;
616 for (i
=0; i
< 16; i
++) {
618 for (j
= 0; j
< 8; j
++ ) {
620 assert(!(major_bitmap
[i
] & (1 <<j
)));
621 major_bitmap
[i
] |= (1 << j
);
629 /*===========================================================================*
630 * generate_usb_device_id *
631 *===========================================================================*/
632 static struct usb_device_id
*
633 generate_usb_device_id(char * path
, int is_interface
)
635 struct usb_device_id
*ret
;
639 ret
= (struct usb_device_id
*)
640 calloc(1,sizeof (struct usb_device_id
));
644 res
= read_hex_uint(path
, "../idVendor", &val
);
648 res
= read_hex_uint(path
, "../idProduct", &val
);
650 ret
->idProduct
= val
;
652 res
= read_hex_uint(path
, "../bcdDevice", &val
);
654 ret
->bcdDevice
= val
;
656 res
= read_hex_uint(path
, "../bDeviceClass", &val
);
658 ret
->bDeviceClass
= val
;
660 res
= read_hex_uint(path
, "../bDeviceSubClass", &val
);
662 ret
->bDeviceSubClass
= val
;
664 res
= read_hex_uint(path
, "../bDeviceProtocol", &val
);
666 ret
->bDeviceProtocol
= val
;
668 res
= read_hex_uint(path
, "/bInterfaceClass", &val
);
670 ret
->bInterfaceClass
= val
;
672 res
= read_hex_uint(path
, "/bInterfaceSubClass", &val
);
674 ret
->bInterfaceSubClass
= val
;
676 res
= read_hex_uint(path
, "/bInterfaceProtocol", &val
);
678 ret
->bInterfaceProtocol
= val
;
688 /*===========================================================================*
689 * usb_intf_add_even *
690 *===========================================================================*/
691 static void usb_intf_add_event(char *path
, int dev_id
)
693 struct usb_device_id
*id
;
694 struct devmand_usb_driver
*drv
;
695 struct devmand_driver_instance
*drv_inst
;
698 /* generate usb_match_id */
699 id
= generate_usb_device_id(path
,TRUE
);
701 fprintf(stderr
, "WARN: could not create usb_device id...\n"
702 " ommiting event\n");
707 /* find suitable driver */
708 drv
= match_usb_driver(id
);
712 dbg("INFO: could not find a suitable driver for %s", path
);
716 /* create instance */
717 drv_inst
= (struct devmand_driver_instance
*)
718 calloc(1,sizeof(struct devmand_driver_instance
));
720 if (drv_inst
== NULL
) {
721 fprintf(stderr
, "ERROR: out of memory");
722 return; /* maybe better quit here. */
726 /* allocate inode number, if device files needed */
728 if (major
== INVAL_MAJOR
) {
729 fprintf(stderr
, "WARN: ran out of major numbers\n"
730 " cannot start driver %s for %s\n",
735 drv_inst
->major
= major
;
737 drv_inst
->dev_id
= dev_id
;
740 /* start driver (invoke minix-service) */
741 start_driver(drv_inst
);
746 * An up action can be any executable. Before running it devmand
747 * will set certain environment variables so the script can configure
748 * the device (or generate device files, etc). See up_action() for that.
751 ret
= run_upscript(drv_inst
);
753 stop_driver(drv_inst
);
754 fprintf(stderr
, "devmand: warning, could not run up_action\n");
760 LIST_INSERT_HEAD(&instances
,drv_inst
,list
);
763 /*===========================================================================*
764 * usb_intf_remove_event *
765 *===========================================================================*/
766 static void usb_intf_remove_event(char *path
, int dev_id
)
768 struct devmand_driver_instance
*inst
;
769 struct devmand_usb_driver
*drv
;
772 /* find the driver instance */
773 inst
= find_instance(dev_id
);
776 dbg("No driver running for id: %d", dev_id
);
781 /* run the down script */
782 if (drv
->downscript
) {
783 ret
= run_downscript(inst
);
785 fprintf(stderr
, "WARN: error running up_action");
789 /* stop the driver */
793 put_major(inst
->major
);
796 LIST_REMOVE(inst
,list
);
800 /*===========================================================================*
802 *===========================================================================*/
803 static void handle_event(char *event
)
807 char tmp_path
[PATH_LEN
];
812 if (strncmp("ADD ", event
, 4) == 0) {
814 /* read data from event */
815 res
= sscanf(event
, "ADD %s 0x%x", tmp_path
, &dev_id
);
818 fprintf(stderr
, "WARN: could not parse event: %s", event
);
819 fprintf(stderr
, "WARN: omitting event: %s", event
);
822 strcpy(path
, args
.path
);
823 strcat(path
, tmp_path
);
825 /* what kind of device is added? */
826 type
= determine_type(path
);
829 case DEV_TYPE_USB_DEVICE
:
830 dbg("USB device added: ommited....");
831 /* ommit usb devices for now */
833 case DEV_TYPE_USB_INTF
:
834 dbg("USB interface added: (%s, devid: = %d)",path
, dev_id
);
835 usb_intf_add_event(path
, dev_id
);
839 fprintf(stderr
, "WARN: ommiting event\n");
841 } else if (strncmp("REMOVE ", event
, 7) == 0) {
843 /* read data from event */
844 res
= sscanf(event
,"REMOVE %s 0x%x", tmp_path
, &dev_id
);
847 fprintf(stderr
, "WARN: could not parse event: %s", event
);
848 fprintf(stderr
, "WARN: omitting event: %s", event
);
851 usb_intf_remove_event(path
, dev_id
);
854 strcpy(path
, args
.path
);
855 strcat(path
, tmp_path
);
857 /* what kind of device is added? */
858 type
= determine_type(path
);
861 case DEV_TYPE_USB_DEVICE
:
862 /* ommit usb devices for now */
864 case DEV_TYPE_USB_INTF
:
865 usb_intf_remove_event(path
, dev_id
);
868 fprintf(stderr
, "WARN: ommiting event\n");
875 /*===========================================================================*
877 *===========================================================================*/
878 static void main_loop()
884 len
= strlen(args
.path
);
886 /* init major numbers */
888 memset(&major_bitmap
, 0xff, 16);
890 if (len
> 128 - 7 /*len of "events" */) {
891 fprintf(stderr
, "pathname to long\n");
896 strcpy(ev_path
, args
.path
);
897 strcat(ev_path
, "events");
904 fd
= fopen(ev_path
, "r");
907 * ENFILE is a temporary failure, often caused by
908 * running the test set. Don't die from that..
910 if (errno
== ENFILE
) {
915 fprintf(stderr
,"devmand error: could not open event "
916 "file %s bailing out\n", ev_path
);
921 res
= fgets(buf
, 256, fd
);
928 dbg("handle_event: %s", buf
);
933 /*===========================================================================*
935 *===========================================================================*/
936 static void display_usage(const char *name
)
938 printf("Usage: %s [{-p|--pathname} PATH_TO_SYS}"
939 " [{-d|--config-dir} CONFIG_DIR] [-v|--verbose]"
940 " [[x||--check-config]\n", name
);