diff --git a/commands/Makefile b/commands/Makefile index 5ce879f29..0a133ab6f 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -8,7 +8,7 @@ SUBDIR= add_route arp ash at awk \ cawf cd cdprobe checkhier cpp \ chmod chown ci cksum cleantmp clear cmp co \ comm compress cp crc cron crontab cut \ - dd decomp16 DESCRIBE dev2name devsize df dhcpd \ + dd decomp16 DESCRIBE dev2name devmand devsize df dhcpd \ dhrystone diff dirname diskctl dumpcore \ eject elvis env expand factor fbdctl \ find finger fingerd fix fold format fortune fsck.mfs \ diff --git a/commands/devmand/Makefile b/commands/devmand/Makefile new file mode 100644 index 000000000..2f405296d --- /dev/null +++ b/commands/devmand/Makefile @@ -0,0 +1,15 @@ +PROG = devmand + +SRCS = main.c lex.yy.c y.tab.c + +lex.yy.c: usb_scan.l y.tab.h + ${LEX} usb_scan.l + +y.tab.c y.tab.h: usb.y + ${YACC} -d usb.y + +CLEANFILES = y.tab.c y.tab.h *.d lex.yy.c lex.yy.o main.o y.tab.o +MAN = +.include + + diff --git a/commands/devmand/devmand.cfg b/commands/devmand/devmand.cfg new file mode 100644 index 000000000..714ce6ed7 --- /dev/null +++ b/commands/devmand/devmand.cfg @@ -0,0 +1,45 @@ +usb_driver usb_storage +{ + binary = /usr/sbin/usb_storage; + id { + bInterfaceClass = 0x08; + } + devprefix = usbstor; + upscript = /etc/devmand/scripts/block; + downscript = /etc/devmand/scripts/block; +} + +usb_driver usb_keyboard +{ + binary = /usr/sbin/usb_hid; + id { + bInterfaceClass = 0x3; + bInterfaceProtocol = 0x1; + } + upscript = /etc/devmand/scripts/singlechar; + downscript = /etc/devmand/scripts/singlechar; + devprefix = usb_keyboard; +} + +usb_driver usb_mouse +{ + binary = /usr/sbin/usb_hid; + id { + bInterfaceClass = 0x3; + bInterfaceProtocol = 0x2; + } + upscript = /etc/devmand/scripts/singlechar; + downscript = /etc/devmand/scripts/singlechar; + devprefix = usb_mouse; +} + +usb_driver usb_hid +{ + binary = /usr/sbin/usb_hid; + id { + bInterfaceClass = 0x3; + } + upscript = /etc/devmand/scripts/singlechar; + downscript = /etc/devmand/scripts/singlechar; + devprefix = usb_keyboard; +} diff --git a/commands/devmand/main.c b/commands/devmand/main.c new file mode 100644 index 000000000..baa24a68d --- /dev/null +++ b/commands/devmand/main.c @@ -0,0 +1,847 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "usb_driver.h" +#include "proto.h" + +#define CONTROL_FIFO_PATH "/var/tmp/devmand_control" +#define SERVICE_BINARY "/bin/service" + + +#define DEVMAN_TYPE_NAME "dev_type" +#define PATH_LEN 256 +#define INVAL_MAJOR -1 + +static void main_loop(); +static void handle_event(); +static void cleanup(); +static void parse_config(); +static void display_usage(); +static enum dev_type determine_type(char *path); +static int get_major(); +static void create_pid_file(); +static void put_major(int major); +static struct devmand_usb_driver* match_usb_driver(struct usb_device_id *id); +static struct devmand_driver_instance *find_instance(int dev_id); + +#define dbg(fmt, ... ) \ + if (args.verbose) \ + printf("%8s:%4d: %13s()| "fmt"\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__ ) + +static LIST_HEAD(usb_driver_head, devmand_usb_driver) drivers = + LIST_HEAD_INITIALIZER(drivers); +static LIST_HEAD(usb_driver_inst_head, devmand_driver_instance) instances = + LIST_HEAD_INITIALIZER(instances); + + +static int _run = 1; +struct global_args { + int deamonize; + char *path; + char *config; + int major_offset; + int verbose; +}; + +enum dev_type { + DEV_TYPE_USB_DEVICE, + DEV_TYPE_USB_INTF, + DEV_TYPE_UNKOWN +}; + +extern FILE *yyin; + +static struct global_args args = {0,NULL,NULL,25, 0}; + +static struct option options[] = +{ + {"deamonize", no_argument, NULL, 'd'}, + {"path", required_argument, NULL, 'p'}, + {"config", required_argument, NULL, 'c'}, + {"verbose", required_argument, NULL, 'v'}, + {0,0,0,0} /* terminating entry */ +}; + +static char major_bitmap[16]; /* can store up to 128 major number states */ + + +/*===========================================================================* + * run_upscript * + *===========================================================================*/ +int run_upscript(struct devmand_driver_instance *inst) +{ + char cmdl[1024]; + cmdl[0] = 0; + int ret; + + snprintf(cmdl, 1024, "%s up %s %d %d", + inst->drv->upscript, inst->label, inst->major, inst->dev_id); + dbg("Running Upscript: \"%s\"", cmdl); + ret = system(cmdl); + if (ret != 0) { + return EINVAL; + } + return 0; +} + +/*===========================================================================* + * run_cleanscript * + *===========================================================================*/ +int run_cleanscript(struct devmand_usb_driver *drv) +{ + char cmdl[1024]; + cmdl[0] = 0; + int ret; + + snprintf(cmdl, 1024, "%s clean %s ", + drv->upscript, drv->devprefix); + dbg("Running Upscript: \"%s\"", cmdl); + ret = system(cmdl); + + if (ret != 0) { + return EINVAL; + } + + return 0; +} + + +/*===========================================================================* + * run_downscript * + *===========================================================================*/ +int run_downscript(struct devmand_driver_instance *inst) +{ + char cmdl[1024]; + cmdl[0] = 0; + int ret; + + snprintf(cmdl, 1024, "%s down %s %d", + inst->drv->downscript, inst->label, inst->major); + + dbg("Running Upscript: \"%s\"", cmdl); + + ret = system(cmdl); + + if (ret != 0) { + return EINVAL; + } + + return 0; +} + + +/*===========================================================================* + * stop_driver * + *===========================================================================*/ +int stop_driver(struct devmand_driver_instance *inst) +{ + char cmdl[1024]; + cmdl[0] = 0; + int ret; + + snprintf(cmdl, 1024, "%s down %s %d", + SERVICE_BINARY, inst->label, inst->dev_id); + dbg("executing service: \"%s\"", cmdl); + ret = system(cmdl); + if (ret != 0) + { + return EINVAL; + } + printf("Stopped driver %s with label %s for device %d.\n", + inst->drv->binary, inst->label, inst->dev_id); + + return 0; +} + + +/*===========================================================================* + * start_driver * + *===========================================================================*/ +int start_driver(struct devmand_driver_instance *inst) +{ + char cmdl[1024]; + cmdl[0] = 0; + int ret; + + /* generate label */ + ret = snprintf(inst->label, 32, "%s%d", inst->drv->devprefix, + inst->dev_id); + if (ret < 0 || ret > DEVMAND_DRIVER_LABEL_LEN) { + dbg("label too long"); + return ENOMEM; + } + + snprintf(cmdl, 1024, "%s up %s -major %d -devid %d -label %s", + SERVICE_BINARY, inst->drv->binary, inst->major, inst->dev_id, + inst->label); + dbg("executing service: \"%s\"", cmdl); + + ret = system(cmdl); + + if (ret != 0) { + return EINVAL; + } + + printf("Started driver %s with label %s for device %d.\n", + inst->drv->binary, inst->label, inst->dev_id); + + return 0; +} + +/*===========================================================================* + * find_instance * + *===========================================================================*/ +static struct devmand_driver_instance * +find_instance(int dev_id) +{ + struct devmand_driver_instance *inst; + + LIST_FOREACH(inst, &instances, list) { + if (inst->dev_id == dev_id) { + return inst; + } + } + return NULL; +} + +/*===========================================================================* + * match_usb_driver * + *===========================================================================*/ +static int +match_usb_id(struct devmand_usb_match_id *mid, struct usb_device_id *id) +{ + int res = 1; + unsigned long match = mid->match_flags; + struct usb_device_id *_id = &mid->match_id; + + if (match & USB_MATCH_ID_VENDOR) + if (id->idVendor != _id->idVendor) res = 0; + if (match & USB_MATCH_ID_PRODUCT) + if (id->idProduct != _id->idProduct) res = 0; + if (match & USB_MATCH_BCD_DEVICE) + if (id->bcdDevice != _id->bcdDevice) res = 0; + if (match & USB_MATCH_DEVICE_PROTOCOL) + if (id->bDeviceProtocol != _id->bDeviceProtocol) res = 0; + if (match & USB_MATCH_DEVICE_SUBCLASS) + if (id->bDeviceSubClass != _id->bDeviceSubClass) res = 0; + if (match & USB_MATCH_DEVICE_PROTOCOL) + if (id->bDeviceProtocol != _id->bDeviceProtocol) res = 0; + if (match & USB_MATCH_INTERFACE_CLASS) + if (id->bInterfaceClass != _id->bInterfaceClass) res = 0; + if (match & USB_MATCH_INTERFACE_SUBCLASS) + if (id->bInterfaceSubClass != _id->bInterfaceSubClass) res = 0; + if (match & USB_MATCH_INTERFACE_PROTOCOL) + if (id->bInterfaceProtocol != _id->bInterfaceProtocol) res = 0; + + if (match == 0UL) { + res = 0; + } + + return res; +} + +/*===========================================================================* + * match_usb_driver * + *===========================================================================*/ +static struct devmand_usb_driver* +match_usb_driver(struct usb_device_id *id) +{ + struct devmand_usb_driver *driver; + struct devmand_usb_match_id *mid; + + LIST_FOREACH(driver, &drivers, list) { + LIST_FOREACH(mid, &driver->ids, list) { + if (match_usb_id(mid, id)) { + return driver; + } + } + } + return NULL; +} + +/*===========================================================================* + * add_usb_match_id * + *===========================================================================*/ +struct devmand_usb_driver * add_usb_driver(char *name) +{ + struct devmand_usb_driver *udrv = (struct devmand_usb_driver*) + malloc(sizeof(struct devmand_usb_driver)); + + LIST_INSERT_HEAD(&drivers, udrv, list); + LIST_INIT(&udrv->ids); + + udrv->name = name; + return udrv; +} + +/*===========================================================================* + * add_usb_match_id * + *===========================================================================*/ +struct devmand_usb_match_id * +add_usb_match_id +(struct devmand_usb_driver *drv) +{ + struct devmand_usb_match_id *id = (struct devmand_usb_match_id*) + malloc(sizeof(struct devmand_usb_match_id)); + + memset(id, 0, sizeof(struct devmand_usb_match_id)); + + LIST_INSERT_HEAD(&drv->ids, id, list); + + return id; +} + + +/*===========================================================================* + * parse_config * + *===========================================================================*/ +static void parse_config() +{ + yyin = fopen(args.config, "r"); + + if (yyin < 0) { + printf("Can not open config file: %d.\n", errno); + } + dbg("Parsing configfile... "); + yyparse(); + dbg("Done."); + + fclose(yyin); +} + +/*===========================================================================* + * cleanup * + *===========================================================================*/ +static void cleanup() { + int res; + struct devmand_driver_instance *inst; + /* destroy fifo */ + dbg("cleaning up... "); + /* quit all running drivers */ + LIST_FOREACH(inst, &instances, list) { + dbg("stopping driver %s", inst->label); + run_downscript (inst); + stop_driver(inst); + } + res = remove(CONTROL_FIFO_PATH); + if (res != 0) { + fprintf(stderr, "WARNING: could not remove control fifo"); + } + unlink("/var/run/devmand.pid"); +} + +static void sig_int(int sig) { + dbg("devman: Received SIGINT... cleaning up."); + _run = 0; +} + +/*===========================================================================* + * create_pid_file * + *===========================================================================*/ +void create_pid_file() +{ + FILE *fd; + + fd = fopen("/var/run/devmand.pid", "r"); + if(fd) { + fprintf(stderr, "devmand: /var/run/devmand.pid exists... " + "another devmand running?\n"); + fclose(fd); + exit(1); + } else { + fd = fopen("/var/run/devmand.pid","w"); + fprintf(fd, "%d", getpid()); + fclose(fd); + } +} + +/*===========================================================================* + * main * + *===========================================================================*/ +int main(int argc, char *argv[]) +{ + int opt, optindex, res; + struct devmand_usb_driver *driver; + + create_pid_file(); + + /* get command line arguments */ + while ((opt = getopt_long(argc, argv, "vdc:p:h?", options, &optindex)) + != -1) { + switch (opt) { + case 'd': + args.deamonize = 1; + break; + case 'p': + args.path = optarg; + break; + case 'c': + args.config = optarg; + break; + case 'v': + args.verbose = 1; + break; + case 'h': + case '?': + default: + display_usage(argv[0]); + return 0; + } + } + + /* is path set? */ + if (args.path == NULL) { + args.path = "/sys/"; + } + + /* is path set? */ + if (args.config == NULL) { + args.config = "/etc/devmand/devmand.cfg"; + } + + dbg("Options: deamonize: %s, path: %s", + args.deamonize?"true":"false", args.path); + + /* create control socket if not exists */ + res = mkfifo(CONTROL_FIFO_PATH, S_IWRITE); + + if ( !((res == 0) || (res == EEXIST)) ) { + fprintf(stderr, "Could not create control FIFO (%d)\n", res); + exit(1); + } + + parse_config(); + LIST_FOREACH(driver, &drivers, list) { + run_cleanscript(driver); + } + + signal(SIGINT, sig_int); + + main_loop(); + + cleanup(); + + return 0; +} + +/*===========================================================================* + * determine_type * + *===========================================================================*/ +static enum dev_type determine_type (char *path) +{ + FILE * fd; + char *mypath; + char buf[256]; + int res; + + mypath = (char *) calloc(1, strlen(path)+strlen(DEVMAN_TYPE_NAME)+1); + + if (mypath == NULL) { + fprintf(stderr, "ERROR: out of mem\n"); + exit(1); + } + + strcat(mypath, path); + strcat(mypath, DEVMAN_TYPE_NAME); + + fd = fopen(mypath, "r"); + free(mypath); + + if (fd == NULL) { + fprintf(stderr, "WARN: could not open %s\n", mypath); + return DEV_TYPE_UNKOWN; + } + + res = fscanf(fd , "%s\n", buf); + fclose(fd); + + if (res != 1) { + fprintf(stderr, "WARN: could not parse %s\n", mypath); + return DEV_TYPE_UNKOWN; + } + + if (strcmp(buf, "USB_DEV") == 0) { + return DEV_TYPE_USB_DEVICE; + } else if (strcmp(buf, "USB_INTF") == 0) { + return DEV_TYPE_USB_INTF; + } + + return DEV_TYPE_UNKOWN; +} + +/*===========================================================================* + * read_hex_uint * + *===========================================================================*/ +static int read_hex_uint(char *base_path, char *name, unsigned int* val ) +{ + char my_path[PATH_LEN]; + FILE *fd; + memset(my_path,0,PATH_LEN); + int ret = 0; + + strcat(my_path, base_path); + strcat(my_path, name); + + fd = fopen(my_path, "r"); + + if (fd == NULL) { + fprintf(stderr, "WARN: could not open %s\n", my_path); + return EEXIST; + } else if (fscanf(fd, "0x%x\n", val ) != 1) { + fprintf(stderr, "WARN: could not parse %s\n", my_path); + ret = EINVAL; + } + fclose(fd); + + return ret; +} + +/*===========================================================================* + * get_major * + *===========================================================================*/ +static int get_major() { + int i, ret = args.major_offset; + + for (i=0; i < 16; i++) { + int j; + for (j = 0; j < 8; j++ ) { + if ((major_bitmap[i] & (1 << j))) { + major_bitmap[i] &= !(1 << j); + return ret; + } + ret++; + } + } + return INVAL_MAJOR; +} + +/*===========================================================================* + * put_major * + *===========================================================================*/ +static void put_major(int major) { + int i; + major -= args.major_offset; + assert(major >= 0); + + for (i=0; i < 16; i++) { + int j; + for (j = 0; j < 8; j++ ) { + if (major==0) { + assert(!(major_bitmap[i] & (1 <idVendor = val; + + res = read_hex_uint(path, "../idProduct", &val); + if (res) goto err; + ret->idProduct = val; +#if 0 + res = read_hex_uint(path, "../bcdDevice", &val); + if (res) goto err; + ret->bcdDevice = val; +#endif + res = read_hex_uint(path, "../bDeviceClass", &val); + if (res) goto err; + ret->bDeviceClass = val; + + res = read_hex_uint(path, "../bDeviceSubClass", &val); + if (res) goto err; + ret->bDeviceSubClass = val; + + res = read_hex_uint(path, "../bDeviceProtocol", &val); + if (res) goto err; + ret->bDeviceProtocol = val; + + res = read_hex_uint(path, "/bInterfaceClass", &val); + if (res) goto err; + ret->bInterfaceClass = val; + + res = read_hex_uint(path, "/bInterfaceSubClass", &val); + if (res) goto err; + ret->bInterfaceSubClass = val; + + res = read_hex_uint(path, "/bInterfaceProtocol", &val); + if (res) goto err; + ret->bInterfaceProtocol = val; + } + + return ret; + +err: + free(ret); + return NULL; +} + +/*===========================================================================* + * usb_intf_add_even * + *===========================================================================*/ +static void usb_intf_add_event(char *path, int dev_id) +{ + struct usb_device_id *id; + struct devmand_usb_driver *drv; + struct devmand_driver_instance *drv_inst; + int major, ret; + + /* generate usb_match_id */ + id = generate_usb_device_id(path,TRUE); + if (id == NULL) { + fprintf(stderr, "WARN: could not create usb_device id...\n" + " ommiting event\n"); + free(id); + return; + } + + /* find suitable driver */ + drv = match_usb_driver(id); + free (id); + + if (drv == NULL) { + dbg("INFO: could not find a suitable driver for %s", path); + return; + } + + /* create instance */ + drv_inst = (struct devmand_driver_instance *) + calloc(1,sizeof(struct devmand_driver_instance)); + + if (drv_inst == NULL) { + fprintf(stderr, "ERROR: out of memory"); + return; /* maybe better quit here. */ + } + + + /* allocate inode number, if device files needed */ + major = get_major(); + if (major == INVAL_MAJOR) { + fprintf(stderr, "WARN: ran out of major numbers\n" + " cannot start driver %s for %s\n", + drv->name, path); + return; + } + + drv_inst->major = major; + drv_inst->drv = drv; + drv_inst->dev_id = dev_id; + + + /* start driver (invoke service) */ + start_driver(drv_inst); + + /* + * run the up action + * + * An up action can be any executable. Before running it devmand + * will set certain environment variables so the script can configure + * the device (or generate device files, etc). See up_action() for that. + */ + if (drv->upscript) { + ret = run_upscript(drv_inst); + if (ret) { + stop_driver(drv_inst); + fprintf(stderr, "devmand: warning, could not run up_action\n"); + free(drv_inst); + return; + } + } + + LIST_INSERT_HEAD(&instances,drv_inst,list); +} + +/*===========================================================================* + * usb_intf_remove_event * + *===========================================================================*/ +static void usb_intf_remove_event(char *path, int dev_id) +{ + struct devmand_driver_instance *inst; + struct devmand_usb_driver *drv; + int ret; + + /* find the driver instance */ + inst = find_instance(dev_id); + + if (inst == NULL) { + dbg("No driver running for id: %d", dev_id); + return; + } + drv = inst->drv; + + /* run the down script */ + if (drv->downscript) { + ret = run_downscript(inst); + if (ret) { + fprintf(stderr, "WARN: error running up_action"); + } + } + + /* stop the driver */ + stop_driver(inst); + + /* free major */ + put_major(inst->major); + + /* free instance */ + LIST_REMOVE(inst,list); + free(inst); +} + +/*===========================================================================* + * handle_event * + *===========================================================================*/ +static void handle_event(char *event) +{ + enum dev_type type; + char path[PATH_LEN]; + char tmp_path[PATH_LEN]; + int dev_id, res; + + path[0]=0; + + if (strncmp("ADD ", event, 4) == 0) { + + /* read data from event */ + res = sscanf(event, "ADD %s 0x%x", tmp_path, &dev_id); + + if (res != 2) { + fprintf(stderr, "WARN: could not parse event: %s", event); + fprintf(stderr, "WARN: omitting event: %s", event); + } + + strcpy(path, args.path); + strcat(path, tmp_path); + + /* what kind of device is added? */ + type = determine_type(path); + + switch (type) { + case DEV_TYPE_USB_DEVICE: + dbg("USB device added: ommited...."); + /* ommit usb devices for now */ + break; + case DEV_TYPE_USB_INTF: + dbg("USB interface added: (%s, devid: = %d)",path, dev_id); + usb_intf_add_event(path, dev_id); + return; + default: + dbg("default"); + fprintf(stderr, "WARN: ommiting event\n"); + } + } else if (strncmp("REMOVE ", event, 7) == 0) { + + /* read data from event */ + res = sscanf(event,"REMOVE %s 0x%x", tmp_path, &dev_id); + + if (res != 2) { + fprintf(stderr, "WARN: could not parse event: %s", event); + fprintf(stderr, "WARN: omitting event: %s", event); + } + + usb_intf_remove_event(path, dev_id); + +#if 0 + strcpy(path, args.path); + strcat(path, tmp_path); + + /* what kind of device is added? */ + type = determine_type(path); + + switch (type) { + case DEV_TYPE_USB_DEVICE: + /* ommit usb devices for now */ + break; + case DEV_TYPE_USB_INTF: + usb_intf_remove_event(path, dev_id); + return; + default: + fprintf(stderr, "WARN: ommiting event\n"); + } +#endif + + } +} + +/*===========================================================================* + * main_loop * + *===========================================================================*/ +static void main_loop() +{ + char ev_path[128]; + char buf[256]; + int len; + + FILE* fd; + len = strlen(args.path); + + /* init major numbers */ + + memset(&major_bitmap, 0xff, 16); + + if (len > 128 - 7 /*len of "events" */) { + fprintf(stderr, "pathname to long\n"); + exit(1); + } + + strcpy(ev_path, args.path); + strcat(ev_path, "events"); + + + while (_run) { + + char *res; + + fd = fopen(ev_path, "r"); + if (fd == NULL) { + fprintf(stderr, "ERROR: could not open event file...\n"); + exit(1); + } + + res = fgets(buf, 256, fd); + fclose(fd); + + if (res == NULL) { + /* TODO: wait for control events */ + usleep(50000); + continue; + } + dbg("handle_event: %s", buf); + handle_event(buf); + } +} + +/*===========================================================================* + * display_usage * + *===========================================================================*/ +static void display_usage(const char *name) +{ + printf("Usage: %s [-d|--deamonize] [{-p|--pathname} PATH_TO_SYS}" + " [{-c|--config} CONFIG_FILE]\n", name); +} + diff --git a/commands/devmand/proto.h b/commands/devmand/proto.h new file mode 100644 index 000000000..8a1903488 --- /dev/null +++ b/commands/devmand/proto.h @@ -0,0 +1,11 @@ +#ifndef _DEVMAND_PROTO_H +#define _DEVMAND_PROTO_H + +/* main.c */ +struct devmand_usb_driver * add_usb_driver(char *name); +struct devmand_usb_match_id * add_usb_match_id(); + +/* y.tab.c */ +int yyparse(); + +#endif diff --git a/commands/devmand/usb.y b/commands/devmand/usb.y new file mode 100644 index 000000000..dcb381939 --- /dev/null +++ b/commands/devmand/usb.y @@ -0,0 +1,134 @@ +%{ +#include +#include +#include +#include "usb_driver.h" +#define YY_NO_INPUT +static struct devmand_usb_driver *current_drv; +static struct devmand_usb_match_id *current_id; + +int yylex(void); + +void yyerror(char *s) +{ + fprintf(stderr,"parsing error: %s\n",s); +} + +int yywrap() +{ + return 1; +} +%} + +%union { + char *string; +} + +%start drivers +%token USB_DRIVER DEV_PREFIX BINARY INTERFACE_CLASS INTERFACE_SUB_CLASS EQUALS DEV_TYPE BLOCK_DEV CHAR_DEV UPSCRIPT DOWNSCRIPT +SEMICOLON BRACKET_OPEN BRACKET_CLOSE STRING ID INTERFACE_PROTOCOL + +%% +drivers : + driver + { + } + | drivers driver + { + }; + +driver : + USB_DRIVER STRING {current_drv = add_usb_driver($2);} + BRACKET_OPEN + usb_driver_statements BRACKET_CLOSE + { + }; + +usb_driver_statements: + usb_driver_statement + { + } + | usb_driver_statements usb_driver_statement + { + }; + +usb_driver_statement: + {current_id = add_usb_match_id(current_drv);} + ID BRACKET_OPEN usb_device_id_statements BRACKET_CLOSE + { + } + | BINARY EQUALS STRING SEMICOLON + { + current_drv->binary = $3; + } + | DEV_PREFIX EQUALS STRING SEMICOLON + { + current_drv->devprefix = $3; + } + | DEV_TYPE EQUALS BLOCK_DEV SEMICOLON + { + current_drv->dev_type = block_dev; + } + | DEV_TYPE EQUALS CHAR_DEV SEMICOLON + { + current_drv->dev_type = char_dev; + } + | UPSCRIPT EQUALS STRING SEMICOLON + { + current_drv->upscript = $3; + } + | DOWNSCRIPT EQUALS STRING SEMICOLON + { + current_drv->downscript = $3; + }; + + +usb_device_id_statements: + usb_device_id_statement + { + } + |usb_device_id_statements usb_device_id_statement + { + }; + + +usb_device_id_statement: + INTERFACE_CLASS EQUALS STRING SEMICOLON + { + int res; + unsigned int num; + current_id->match_flags |= USB_MATCH_INTERFACE_CLASS; + res = sscanf($3, "0x%x", &num); + if (res != 1) { + fprintf(stderr, "ERROR"); + exit(1); + } + current_id->match_id.bInterfaceClass = num; + } + | INTERFACE_SUB_CLASS EQUALS STRING SEMICOLON + { + int res; + unsigned int num; + current_id->match_flags |= USB_MATCH_INTERFACE_SUBCLASS; + res = sscanf($3, "0x%x", &num); + if (res != 1) { + fprintf(stderr, "ERROR"); + exit(1); + } + current_id->match_id.bInterfaceSubClass = num; + + } + | INTERFACE_PROTOCOL EQUALS STRING SEMICOLON + { + int res; + unsigned int num; + current_id->match_flags |= USB_MATCH_INTERFACE_PROTOCOL; + res = sscanf($3, "0x%x", &num); + if (res != 1) { + fprintf(stderr, "ERROR"); + exit(1); + } + current_id->match_id.bInterfaceProtocol = num; + + }; +%% diff --git a/commands/devmand/usb_driver.h b/commands/devmand/usb_driver.h new file mode 100644 index 000000000..e7ed2053d --- /dev/null +++ b/commands/devmand/usb_driver.h @@ -0,0 +1,52 @@ +#ifndef DEVMAN_USB_DRIVER +#define DEVMAN_USB_DRIVER + +#include +#include + +#define USB_MATCH_ID_VENDOR (1 << 0) +#define USB_MATCH_ID_PRODUCT (1 << 1) +#define USB_MATCH_BCD_DEVICE (1 << 2) +#define USB_MATCH_DEVICE_CLASS (1 << 3) +#define USB_MATCH_DEVICE_SUBCLASS (1 << 4) +#define USB_MATCH_DEVICE_PROTOCOL (1 << 5) +#define USB_MATCH_INTERFACE_CLASS (1 << 6) +#define USB_MATCH_INTERFACE_SUBCLASS (1 << 7) +#define USB_MATCH_INTERFACE_PROTOCOL (1 << 8) + +enum devmand_device_type { + char_dev, + block_dev +}; + +struct devmand_usb_match_id { + unsigned match_flags; + struct usb_device_id match_id; + LIST_ENTRY(devmand_usb_match_id) list; +}; + +#define DEVMAND_DRIVER_LABEL_LEN 32 + +struct devmand_driver_instance { + int dev_id; + int major; + char label[DEVMAND_DRIVER_LABEL_LEN]; + struct devmand_usb_driver *drv; + LIST_ENTRY(devmand_driver_instance) list; +}; + +struct devmand_usb_driver { + char *name; + char *devprefix; + char *binary; + char *upscript; + char *downscript; + enum devmand_device_type dev_type; + LIST_HEAD(devid_head, devmand_usb_match_id) ids; + LIST_ENTRY(devmand_usb_driver) list; +}; + +struct devmand_usb_driver * add_usb_driver(char *name); +struct devmand_usb_match_id *add_usb_match_id(struct devmand_usb_driver *drv); + +#endif diff --git a/commands/devmand/usb_scan.l b/commands/devmand/usb_scan.l new file mode 100644 index 000000000..0c77f2d49 --- /dev/null +++ b/commands/devmand/usb_scan.l @@ -0,0 +1,43 @@ +/* -*- indented-text -*- */ +%option noinput +%option nounput +%{ +#include "y.tab.h" +#include + + +#if 0 +#define ECHO fwrite(yytext, yyleng, 1, yyout) +#else +#define ECHO +#endif +%} +BO [{] +BC [}] +NL [\n] +SC [;] +CHAR [0-9a-zA-Z_/\-\*\.] +EQ [=] +SPACE [\032] +%% + +usb_driver { ECHO; return USB_DRIVER;} +devprefix { ECHO; return DEV_PREFIX;} +devtype { ECHO; return DEV_TYPE;} +char { ECHO; return BLOCK_DEV;} +block { ECHO; return CHAR_DEV;} +binary { ECHO; return BINARY;} +bInterfaceClass { ECHO; return INTERFACE_CLASS;} +bInterfaceSubClass { ECHO; return INTERFACE_SUB_CLASS;} +bInterfaceProtocol { ECHO; return INTERFACE_PROTOCOL;} +id { ECHO; return ID;} +upscript { ECHO; return UPSCRIPT;} +downscript { ECHO; return DOWNSCRIPT;} +{EQ} { ECHO; return EQUALS;} +{SC} { ECHO; return SEMICOLON;} +{BO} { ECHO; return BRACKET_OPEN;} +{BC} { ECHO; return BRACKET_CLOSE;} +{CHAR}+ { ECHO; yylval.string = (char *)strdup(yytext); return STRING;} +. ; +%% + diff --git a/include/ddekit/minix/msg_queue.h b/include/ddekit/minix/msg_queue.h index f7c7e05ad..8042ce566 100644 --- a/include/ddekit/minix/msg_queue.h +++ b/include/ddekit/minix/msg_queue.h @@ -7,9 +7,10 @@ struct ddekit_minix_msg_q; -void ddekit_minix_queue_msg(message *m); +void ddekit_minix_queue_msg(message *m, int ipc_status); -void ddekit_minix_rcv(struct ddekit_minix_msg_q * mq, message *m); +void ddekit_minix_rcv + (struct ddekit_minix_msg_q * mq, message *m, int *ipc_status); struct ddekit_minix_msg_q *ddekit_minix_create_msg_q(unsigned from, unsigned to); diff --git a/include/ddekit/resources.h b/include/ddekit/resources.h index e9cec49ec..dab30bb05 100644 --- a/include/ddekit/resources.h +++ b/include/ddekit/resources.h @@ -32,7 +32,7 @@ int ddekit_release_mem(ddekit_addr_t start, ddekit_addr_t count); * * \return value read from port */ -unsigned char dde_kit_inb(ddekit_addr_t port); +unsigned char ddekit_inb(ddekit_addr_t port); /** * Read I/O port (2-byte) @@ -41,7 +41,7 @@ unsigned char dde_kit_inb(ddekit_addr_t port); * * \return value read from port */ -unsigned short dde_kit_inw(ddekit_addr_t port); +unsigned short ddekit_inw(ddekit_addr_t port); /** * Read I/O port (4-byte) @@ -50,7 +50,7 @@ unsigned short dde_kit_inw(ddekit_addr_t port); * * \return value read from port */ -unsigned long dde_kit_inl(ddekit_addr_t port); +unsigned long ddekit_inl(ddekit_addr_t port); /** * Write I/O port (byte) @@ -58,7 +58,7 @@ unsigned long dde_kit_inl(ddekit_addr_t port); * \param port port to write * \param val value to write */ -void dde_kit_outb(ddekit_addr_t port, unsigned char val); +void ddekit_outb(ddekit_addr_t port, unsigned char val); /** * Write I/O port (2-byte) @@ -66,7 +66,7 @@ void dde_kit_outb(ddekit_addr_t port, unsigned char val); * \param port port to write * \param val value to write */ -void dde_kit_outw(ddekit_addr_t port, unsigned short val); +void ddekit_outw(ddekit_addr_t port, unsigned short val); /** * Write I/O port (4-byte) @@ -74,7 +74,7 @@ void dde_kit_outw(ddekit_addr_t port, unsigned short val); * \param port port to write * \param val value to write */ -void dde_kit_outl(ddekit_addr_t port, unsigned long val); +void ddekit_outl(ddekit_addr_t port, unsigned long val); #endif diff --git a/include/minix/sys_config.h b/include/minix/sys_config.h index 168923cab..06598762d 100644 --- a/include/minix/sys_config.h +++ b/include/minix/sys_config.h @@ -58,3 +58,8 @@ error "_MINIX_MACHINE has incorrect value (0)" #define DEFAULT_STACK_LIMIT (64 * 1024 * 1024) #endif /* _MINIX_SYS_CONFIG_H */ + +/* Added by release script */ +#ifndef _VCS_REVISION +#define _VCS_REVISION "116fcea" +#endif diff --git a/lib/libddekit/src/dde.c b/lib/libddekit/src/dde.c index 500cb1e07..8fc7fd473 100644 --- a/lib/libddekit/src/dde.c +++ b/lib/libddekit/src/dde.c @@ -30,7 +30,7 @@ static void ddekit_dispatcher_thread_init(void); /****************************************************************************/ static void dispatcher_thread(void *unused) { - /* + /* * Gets all messages and dispatches them. * * NOTE: this thread runs only when no other ddekit is @@ -40,6 +40,7 @@ static void dispatcher_thread(void *unused) { message m; int r; int i; + int ipc_status; _ddekit_thread_set_myprio(0); @@ -47,17 +48,17 @@ static void dispatcher_thread(void *unused) { /* Trigger a timer interrupt at each loop iteration */ _ddekit_timer_update(); - + /* Wait for messages */ - if ((r = sef_receive(ANY, &m)) != 0) { + if ((r = sef_receive_status(ANY, &m, &ipc_status)) != 0) { ddekit_panic("ddekit", "sef_receive failed", r); } - + _ddekit_timer_interrupt(); - + _ddekit_thread_wakeup_sleeping(); - + if (is_notify(m.m_type)) { switch (_ENDPOINT_P(m.m_source)) { case HARDWARE: @@ -77,15 +78,15 @@ static void dispatcher_thread(void *unused) { } } else { - - /* + + /* * I don't know how to handle this msg, * but maybe we have a msg queue which can * handle this msg. */ - ddekit_minix_queue_msg(&m); - } + ddekit_minix_queue_msg(&m, ipc_status); + } } } @@ -114,9 +115,9 @@ void ddekit_init(void) ddekit_init_irqs(); ddekit_init_timers(); - + ddekit_dispatcher_thread_init(); - + exit_sem = ddekit_sem_init(0); } diff --git a/lib/libddekit/src/initcall.c b/lib/libddekit/src/initcall.c index 07d2088cb..70a053829 100644 --- a/lib/libddekit/src/initcall.c +++ b/lib/libddekit/src/initcall.c @@ -8,7 +8,7 @@ #define DDEBUG DDEKIT_DEBUG_INITCALL #endif -#include "debug.h" +#include "debug.h" static struct __ddekit_initcall_s head = {0,0,0}; diff --git a/lib/libddekit/src/msg_queue.c b/lib/libddekit/src/msg_queue.c index 57e1dbcfd..3ea82708b 100644 --- a/lib/libddekit/src/msg_queue.c +++ b/lib/libddekit/src/msg_queue.c @@ -19,6 +19,7 @@ struct ddekit_minix_msg_q { unsigned from, to; message messages[MESSAGE_QUEUE_SIZE]; + int ipc_status[MESSAGE_QUEUE_SIZE]; ddekit_sem_t *msg_w_sem, *msg_r_sem; int msg_r_pos, msg_w_pos; @@ -26,8 +27,8 @@ struct ddekit_minix_msg_q { }; static struct ddekit_minix_msg_q * _list = NULL; -static void _ddekit_minix_queue_msg(struct ddekit_minix_msg_q *mq, - message *m); +static void _ddekit_minix_queue_msg + (struct ddekit_minix_msg_q *mq, message *m, int ipc_status); /***************************************************************************** * ddekit_minix_create_msg_q * @@ -37,7 +38,7 @@ ddekit_minix_create_msg_q(unsigned from, unsigned to) { struct ddekit_minix_msg_q *mq = (struct ddekit_minix_msg_q *) ddekit_simple_malloc(sizeof(struct ddekit_minix_msg_q)); - + mq->from = from; mq->to = to; mq->msg_w_pos = 0; @@ -49,10 +50,10 @@ ddekit_minix_create_msg_q(unsigned from, unsigned to) /* TODO: check for overlapping message ranges */ mq->next = _list; _list = mq; - + DDEBUG_MSG_VERBOSE("created msg_q from %x to %x\n", from , to); - return mq; + return mq; } /***************************************************************************** @@ -81,8 +82,12 @@ void ddekit_minix_deregister_msg_q(struct ddekit_minix_msg_q *mq) /***************************************************************************** * _ddekit_minix_queue_msg * ****************************************************************************/ -static void -_ddekit_minix_queue_msg(struct ddekit_minix_msg_q *mq, message *m) +static void +_ddekit_minix_queue_msg ( + struct ddekit_minix_msg_q *mq, + message *m, + int ipc_status +) { int full; full = ddekit_sem_down_try(mq->msg_w_sem); @@ -95,7 +100,7 @@ _ddekit_minix_queue_msg(struct ddekit_minix_msg_q *mq, message *m) m->m_type = TASK_REPLY; m->REP_STATUS = EAGAIN; result = asynsend(m->m_source, m); - + if (result != 0) { ddekit_panic("unable to send reply to %d: %d\n", m->m_source, result); @@ -104,7 +109,7 @@ _ddekit_minix_queue_msg(struct ddekit_minix_msg_q *mq, message *m) } else { /* queue the message */ memcpy(&mq->messages[mq->msg_w_pos], m, sizeof(message)); - + mq->ipc_status[mq->msg_w_pos] = ipc_status; if (++mq->msg_w_pos == MESSAGE_QUEUE_SIZE) { mq->msg_w_pos = 0; } @@ -117,10 +122,10 @@ _ddekit_minix_queue_msg(struct ddekit_minix_msg_q *mq, message *m) /***************************************************************************** * ddekit_minix_queue_msg * ****************************************************************************/ -void ddekit_minix_queue_msg(message *m) +void ddekit_minix_queue_msg(message *m, int ipc_status) { struct ddekit_minix_msg_q *it, *mq = NULL; - + for (it = _list; it !=NULL ; it = it->next) { if (m->m_type >= it->from && m->m_type <= it->to) { mq = it; @@ -131,25 +136,29 @@ void ddekit_minix_queue_msg(message *m) DDEBUG_MSG_VERBOSE("no q for msgtype %x\n", m->m_type); return; } - _ddekit_minix_queue_msg(mq,m); + _ddekit_minix_queue_msg(mq, m, ipc_status); } /***************************************************************************** * ddekit_minix_rcv * ****************************************************************************/ -void ddekit_minix_rcv(struct ddekit_minix_msg_q *mq, message *m) +void ddekit_minix_rcv ( + struct ddekit_minix_msg_q *mq, + message *m, + int *ipc_status +) { DDEBUG_MSG_VERBOSE("waiting for message"); - + ddekit_sem_down(mq->msg_r_sem); memcpy(m, &mq->messages[mq->msg_r_pos], sizeof(message)); - + *ipc_status = mq->ipc_status[mq->msg_r_pos]; if (++mq->msg_r_pos == MESSAGE_QUEUE_SIZE) { mq->msg_r_pos = 0; } - + DDEBUG_MSG_VERBOSE("unqueing message"); - + ddekit_sem_up(mq->msg_w_sem); } diff --git a/lib/libddekit/src/usb_client.c b/lib/libddekit/src/usb_client.c index eaac5d90e..c232e953e 100644 --- a/lib/libddekit/src/usb_client.c +++ b/lib/libddekit/src/usb_client.c @@ -52,18 +52,17 @@ static void _ddekit_usb_completion(struct usb_urb *mx_urb) if (mx_urb->type == USB_TRANSFER_ISO) { d_urb->start_frame = mx_urb->start_frame; - + memcpy(d_urb->iso_desc, mx_urb->buffer + d_urb->size, d_urb->number_of_packets * sizeof(struct usb_iso_packet_desc)); } - + memcpy(d_urb->data, mx_urb->buffer, d_urb->size); - + /* free mx_urb */ ddekit_simple_free(mx_urb); /* 'give back' URB */ - d_usb_driver->completion(d_urb->priv); } @@ -139,11 +138,9 @@ int ddekit_usb_submit_urb(struct ddekit_usb_urb *d_urb) { int res; unsigned urb_size = USB_URBSIZE(d_urb->size, d_urb->number_of_packets); - /* create mx urb out of d_urb */ struct usb_urb *mx_urb = (struct usb_urb*) ddekit_simple_malloc(urb_size); - mx_urb->urb_size = urb_size; mx_urb->dev_id = d_urb->dev->id; @@ -162,18 +159,15 @@ int ddekit_usb_submit_urb(struct ddekit_usb_urb *d_urb) if (mx_urb->type == USB_TRANSFER_ISO) { mx_urb->number_of_packets = d_urb->number_of_packets; mx_urb->start_frame = d_urb->start_frame; - memcpy(mx_urb->buffer + d_urb->size, d_urb->iso_desc, d_urb->number_of_packets * sizeof(struct usb_iso_packet_desc)); } - memcpy(mx_urb->buffer, d_urb->data, d_urb->size); d_urb->ddekit_priv = mx_urb; /* submit mx_urb */ res = usb_send_urb(mx_urb); - return res; } @@ -197,14 +191,15 @@ static void _ddekit_usb_thread() struct ddekit_minix_msg_q *mq = ddekit_minix_create_msg_q(USB_BASE, USB_BASE + 0x1000); message m; + int ipc_status; while (1) { - ddekit_minix_rcv(mq, &m); - usb_handle_msg(&mx_usb_driver,&m); + ddekit_minix_rcv(mq, &m, &ipc_status); + usb_handle_msg(&mx_usb_driver, &m); } } - + /***************************************************************************** * ddekit_usb_init * ****************************************************************************/ @@ -213,7 +208,6 @@ int ddekit_usb_init ddekit_usb_malloc_fn *unused, ddekit_usb_free_fn *_unused) { - /* start usb_thread */ d_usb_driver = drv; usb_init("dde"); diff --git a/lib/libddekit/src/usb_server.c b/lib/libddekit/src/usb_server.c index 1a0389b5c..88bfdaa77 100644 --- a/lib/libddekit/src/usb_server.c +++ b/lib/libddekit/src/usb_server.c @@ -415,7 +415,7 @@ static void cancle_urb(message *msg) endpoint_t ep = msg->m_source; struct minix_usb_driver *drv; - + msg->USB_RESULT = -1; msg->m_type = USB_REPLY; @@ -425,7 +425,7 @@ static void cancle_urb(message *msg) return; } else { struct ddekit_usb_urb *d_urb = NULL; - + d_urb = find_pending_urb(drv, msg->USB_URB_ID); if (d_urb != NULL) { @@ -436,7 +436,7 @@ static void cancle_urb(message *msg) msg->USB_RESULT = ENODEV; } } - + send(ep, msg); } @@ -468,9 +468,9 @@ static void completion_callback(void *priv) mx_urb->actual_length = d_urb->actual_length; mx_urb->error_count = d_urb->error_count; mx_urb->transfer_flags = d_urb->transfer_flags; - + remove_from_pending_urbs(drv, d_urb); - + /* copy out URB */ res = sys_safecopyto(drv->ep, ctx->gid, 0, (vir_bytes) ((char*)mx_urb) + sizeof(void*), @@ -486,7 +486,7 @@ static void completion_callback(void *priv) msg.m_type = USB_COMPLETE_URB; msg.USB_URB_ID = ctx->urb_id; asynsend3(drv->ep, &msg, AMF_NOREPLY); - + /* free stuff */ my_free(ctx); my_free(mx_urb); @@ -725,10 +725,10 @@ static void devman_thread(void *unused) { struct ddekit_minix_msg_q *mq = ddekit_minix_create_msg_q(DEVMAN_BASE, DEVMAN_BASE + 0xff); - + int ipc_status; message m; while (1) { - ddekit_minix_rcv(mq, &m); + ddekit_minix_rcv(mq, &m, &ipc_status); devman_handle_msg(&m); } } @@ -742,6 +742,7 @@ static void _ddekit_usb_thread(void * unused) USB_BASE + 0xff); message m; + int ipc_status; /* create devman thread */ ddekit_thread_t * dmth; @@ -749,7 +750,7 @@ static void _ddekit_usb_thread(void * unused) dmth = ddekit_thread_create(devman_thread, NULL, "devman_thread"); while (1) { - ddekit_minix_rcv(mq, &m); + ddekit_minix_rcv(mq, &m, &ipc_status); handle_msg(&m); } }