xref: /minix3/minix/commands/devmand/main.c (revision c58da9fbc35f86051ff0a75e6dd91e937d83cfff)
1433d6423SLionel Sambuc #include <stdio.h>
2433d6423SLionel Sambuc #include <stdlib.h>
3433d6423SLionel Sambuc #include <getopt.h>
4433d6423SLionel Sambuc #include <errno.h>
5433d6423SLionel Sambuc #include <string.h>
6433d6423SLionel Sambuc #include <lib.h>
7433d6423SLionel Sambuc #include <sys/stat.h>
8433d6423SLionel Sambuc #include <dirent.h>
9433d6423SLionel Sambuc #include <assert.h>
10433d6423SLionel Sambuc #include <signal.h>
11433d6423SLionel Sambuc #include <minix/dmap.h>
12*c58da9fbSDavid van Moolenbroek #include <minix/paths.h>
13433d6423SLionel Sambuc #include "usb_driver.h"
14433d6423SLionel Sambuc #include "proto.h"
15433d6423SLionel Sambuc 
16433d6423SLionel Sambuc #define DEVMAN_TYPE_NAME "dev_type"
17433d6423SLionel Sambuc #define PATH_LEN 256
18433d6423SLionel Sambuc #define INVAL_MAJOR -1
19433d6423SLionel Sambuc #define MAX_CONFIG_DIRS 4
20433d6423SLionel Sambuc 
21433d6423SLionel Sambuc static void main_loop();
22433d6423SLionel Sambuc static void handle_event();
23433d6423SLionel Sambuc static void cleanup();
24433d6423SLionel Sambuc static void parse_config();
25433d6423SLionel Sambuc static void display_usage();
26433d6423SLionel Sambuc static enum dev_type determine_type(char *path);
27433d6423SLionel Sambuc static int get_major();
28433d6423SLionel Sambuc static void create_pid_file();
29433d6423SLionel Sambuc static void put_major(int major);
30433d6423SLionel Sambuc static struct devmand_usb_driver* match_usb_driver(struct usb_device_id *id);
31433d6423SLionel Sambuc static struct devmand_driver_instance *find_instance(int dev_id);
32433d6423SLionel Sambuc 
33433d6423SLionel Sambuc #define dbg(fmt, ... ) \
34433d6423SLionel Sambuc 	if (args.verbose) \
35433d6423SLionel Sambuc 	printf("%8s:%4d: %13s()| "fmt"\n", __FILE__, __LINE__, __func__,  ##__VA_ARGS__ )
36433d6423SLionel Sambuc 
37433d6423SLionel Sambuc static LIST_HEAD(usb_driver_head, devmand_usb_driver) drivers =
38433d6423SLionel Sambuc     LIST_HEAD_INITIALIZER(drivers);
39433d6423SLionel Sambuc static LIST_HEAD(usb_driver_inst_head, devmand_driver_instance) instances =
40433d6423SLionel Sambuc     LIST_HEAD_INITIALIZER(instances);
41433d6423SLionel Sambuc 
42433d6423SLionel Sambuc 
43433d6423SLionel Sambuc static int _run = 1;
44433d6423SLionel Sambuc struct global_args {
45433d6423SLionel Sambuc 	char *path;
46433d6423SLionel Sambuc 	char *config_dirs[MAX_CONFIG_DIRS];
47433d6423SLionel Sambuc 	int config_dir_count ;
48433d6423SLionel Sambuc 	int major_offset;
49433d6423SLionel Sambuc 	int verbose;
50433d6423SLionel Sambuc 	int check_config;
51433d6423SLionel Sambuc };
52433d6423SLionel Sambuc 
53433d6423SLionel Sambuc enum dev_type {
54433d6423SLionel Sambuc 	DEV_TYPE_USB_DEVICE,
55433d6423SLionel Sambuc 	DEV_TYPE_USB_INTF,
56433d6423SLionel Sambuc 	DEV_TYPE_UNKOWN
57433d6423SLionel Sambuc };
58433d6423SLionel Sambuc 
59433d6423SLionel Sambuc extern FILE *yyin;
60433d6423SLionel Sambuc 
61433d6423SLionel Sambuc static struct global_args args = {
62433d6423SLionel Sambuc 	.path = NULL,
63433d6423SLionel Sambuc 	.config_dirs = {NULL,NULL,NULL,NULL},
64433d6423SLionel Sambuc 	.config_dir_count = 0,
65433d6423SLionel Sambuc 	.major_offset = USB_BASE_MAJOR,
66433d6423SLionel Sambuc 	.verbose = 0,
67433d6423SLionel Sambuc 	.check_config = 0};
68433d6423SLionel Sambuc 
69433d6423SLionel Sambuc static struct option options[] =
70433d6423SLionel Sambuc {
71433d6423SLionel Sambuc 	{"dir"   ,    required_argument, NULL, 'd'},
72433d6423SLionel Sambuc 	{"path",      required_argument, NULL, 'p'},
73433d6423SLionel Sambuc 	{"verbose",    required_argument, NULL, 'v'},
74433d6423SLionel Sambuc 	{"check-config", no_argument,       NULL, 'x'},
75433d6423SLionel Sambuc 	{0,0,0,0} /* terminating entry */
76433d6423SLionel Sambuc };
77433d6423SLionel Sambuc 
78433d6423SLionel Sambuc static char major_bitmap[16]; /* can store up to 128 major number states */
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc 
81433d6423SLionel Sambuc /*===========================================================================*
82433d6423SLionel Sambuc  *             run_upscript                                                  *
83433d6423SLionel Sambuc  *===========================================================================*/
run_upscript(struct devmand_driver_instance * inst)84433d6423SLionel Sambuc int run_upscript(struct devmand_driver_instance *inst)
85433d6423SLionel Sambuc {
86433d6423SLionel Sambuc 	char cmdl[1024];
87433d6423SLionel Sambuc 	cmdl[0] = 0;
88433d6423SLionel Sambuc 	int ret;
89433d6423SLionel Sambuc 
90683d394dSBen Gras 	assert(inst->drv->upscript);
91683d394dSBen Gras 	assert(inst->label);
92683d394dSBen Gras 
93433d6423SLionel Sambuc 	snprintf(cmdl, 1024, "%s up %s %d %d",
94433d6423SLionel Sambuc 	    inst->drv->upscript, inst->label, inst->major, inst->dev_id);
95433d6423SLionel Sambuc 	dbg("Running Upscript:  \"%s\"", cmdl);
96433d6423SLionel Sambuc 	ret = system(cmdl);
97433d6423SLionel Sambuc 	if (ret != 0) {
98433d6423SLionel Sambuc 		return EINVAL;
99433d6423SLionel Sambuc 	}
100433d6423SLionel Sambuc 	return 0;
101433d6423SLionel Sambuc }
102433d6423SLionel Sambuc 
103433d6423SLionel Sambuc /*===========================================================================*
104433d6423SLionel Sambuc  *             run_cleanscript                                               *
105433d6423SLionel Sambuc  *===========================================================================*/
run_cleanscript(struct devmand_usb_driver * drv)106433d6423SLionel Sambuc int run_cleanscript(struct devmand_usb_driver *drv)
107433d6423SLionel Sambuc {
108433d6423SLionel Sambuc 	char cmdl[1024];
109433d6423SLionel Sambuc 	cmdl[0] = 0;
110433d6423SLionel Sambuc 	int ret;
111433d6423SLionel Sambuc 
112683d394dSBen Gras 	assert(drv->upscript);
113683d394dSBen Gras 	assert(drv->devprefix);
114683d394dSBen Gras 
115433d6423SLionel Sambuc 	snprintf(cmdl, 1024, "%s clean %s ",
116433d6423SLionel Sambuc 		drv->upscript, drv->devprefix);
117433d6423SLionel Sambuc 	dbg("Running Upscript:  \"%s\"", cmdl);
118433d6423SLionel Sambuc 	ret = system(cmdl);
119433d6423SLionel Sambuc 
120433d6423SLionel Sambuc 	if (ret != 0) {
121433d6423SLionel Sambuc 		return EINVAL;
122433d6423SLionel Sambuc 	}
123433d6423SLionel Sambuc 
124433d6423SLionel Sambuc 	return 0;
125433d6423SLionel Sambuc }
126433d6423SLionel Sambuc 
127433d6423SLionel Sambuc 
128433d6423SLionel Sambuc /*===========================================================================*
129433d6423SLionel Sambuc  *             run_downscript                                                *
130433d6423SLionel Sambuc  *===========================================================================*/
run_downscript(struct devmand_driver_instance * inst)131433d6423SLionel Sambuc int run_downscript(struct devmand_driver_instance *inst)
132433d6423SLionel Sambuc {
133433d6423SLionel Sambuc 	char cmdl[1024];
134433d6423SLionel Sambuc 	cmdl[0] = 0;
135433d6423SLionel Sambuc 	int ret;
136433d6423SLionel Sambuc 
137683d394dSBen Gras 	assert(inst->drv->downscript);
138683d394dSBen Gras 	assert(inst->label);
139683d394dSBen Gras 
140433d6423SLionel Sambuc 	snprintf(cmdl, 1024, "%s down %s %d",
141433d6423SLionel Sambuc 	    inst->drv->downscript, inst->label, inst->major);
142433d6423SLionel Sambuc 
143433d6423SLionel Sambuc 	dbg("Running Upscript:  \"%s\"", cmdl);
144433d6423SLionel Sambuc 
145433d6423SLionel Sambuc 	ret = system(cmdl);
146433d6423SLionel Sambuc 
147433d6423SLionel Sambuc 	if (ret != 0) {
148433d6423SLionel Sambuc 		return EINVAL;
149433d6423SLionel Sambuc 	}
150433d6423SLionel Sambuc 
151433d6423SLionel Sambuc 	return 0;
152433d6423SLionel Sambuc }
153433d6423SLionel Sambuc 
154433d6423SLionel Sambuc 
155433d6423SLionel Sambuc /*===========================================================================*
156433d6423SLionel Sambuc  *             stop_driver                                                   *
157433d6423SLionel Sambuc  *===========================================================================*/
stop_driver(struct devmand_driver_instance * inst)158433d6423SLionel Sambuc int stop_driver(struct devmand_driver_instance *inst)
159433d6423SLionel Sambuc {
160433d6423SLionel Sambuc 	char cmdl[1024];
161433d6423SLionel Sambuc 	cmdl[0] = 0;
162433d6423SLionel Sambuc 	int ret;
163433d6423SLionel Sambuc 
164683d394dSBen Gras 	assert(inst->label);
165683d394dSBen Gras 
166433d6423SLionel Sambuc 	snprintf(cmdl, 1024, "%s down %s %d",
167*c58da9fbSDavid van Moolenbroek 	    _PATH_MINIX_SERVICE, inst->label, inst->dev_id);
168*c58da9fbSDavid van Moolenbroek 	dbg("executing minix-service: \"%s\"", cmdl);
169433d6423SLionel Sambuc 	ret = system(cmdl);
170433d6423SLionel Sambuc 	if (ret != 0)
171433d6423SLionel Sambuc 	{
172433d6423SLionel Sambuc 		return EINVAL;
173433d6423SLionel Sambuc 	}
174433d6423SLionel Sambuc 	printf("Stopped driver %s with label %s for device %d.\n",
175433d6423SLionel Sambuc 		inst->drv->binary, inst->label, inst->dev_id);
176433d6423SLionel Sambuc 
177433d6423SLionel Sambuc 	return 0;
178433d6423SLionel Sambuc }
179433d6423SLionel Sambuc 
180433d6423SLionel Sambuc 
181433d6423SLionel Sambuc /*===========================================================================*
182433d6423SLionel Sambuc  *             start_driver                                                  *
183433d6423SLionel Sambuc  *===========================================================================*/
start_driver(struct devmand_driver_instance * inst)184433d6423SLionel Sambuc int start_driver(struct devmand_driver_instance *inst)
185433d6423SLionel Sambuc {
186433d6423SLionel Sambuc 	char cmdl[1024];
187433d6423SLionel Sambuc 	cmdl[0] = 0;
188433d6423SLionel Sambuc 	int ret;
189433d6423SLionel Sambuc 
190433d6423SLionel Sambuc 	/* generate label */
191433d6423SLionel Sambuc 	ret = snprintf(inst->label, 32,  "%s%d", inst->drv->devprefix,
192433d6423SLionel Sambuc 		inst->dev_id);
193433d6423SLionel Sambuc 	if (ret < 0 || ret > DEVMAND_DRIVER_LABEL_LEN) {
194433d6423SLionel Sambuc 		dbg("label too long");
195433d6423SLionel Sambuc 		return ENOMEM;
196433d6423SLionel Sambuc 	}
197433d6423SLionel Sambuc 
198683d394dSBen Gras 	assert(inst->drv->binary);
199683d394dSBen Gras 	assert(inst->label);
200683d394dSBen Gras 
201433d6423SLionel Sambuc 	snprintf(cmdl, 1024, "%s up %s  -major %d -devid %d -label %s",
202*c58da9fbSDavid van Moolenbroek 	    _PATH_MINIX_SERVICE, inst->drv->binary, inst->major, inst->dev_id,
203433d6423SLionel Sambuc 		inst->label);
204*c58da9fbSDavid van Moolenbroek 	dbg("executing minix-service: \"%s\"", cmdl);
205433d6423SLionel Sambuc 
206433d6423SLionel Sambuc 	ret = system(cmdl);
207433d6423SLionel Sambuc 
208433d6423SLionel Sambuc 	if (ret != 0) {
209433d6423SLionel Sambuc 		return EINVAL;
210433d6423SLionel Sambuc 	}
211433d6423SLionel Sambuc 
212433d6423SLionel Sambuc 	printf("Started driver %s with label %s for device %d.\n",
213433d6423SLionel Sambuc 		inst->drv->binary, inst->label, inst->dev_id);
214433d6423SLionel Sambuc 
215433d6423SLionel Sambuc 	return 0;
216433d6423SLionel Sambuc }
217433d6423SLionel Sambuc 
218433d6423SLionel Sambuc /*===========================================================================*
219433d6423SLionel Sambuc  *             find_instance                                                 *
220433d6423SLionel Sambuc  *===========================================================================*/
221433d6423SLionel Sambuc static struct devmand_driver_instance *
find_instance(int dev_id)222433d6423SLionel Sambuc find_instance(int dev_id)
223433d6423SLionel Sambuc {
224433d6423SLionel Sambuc 	struct devmand_driver_instance *inst;
225433d6423SLionel Sambuc 
226433d6423SLionel Sambuc 	LIST_FOREACH(inst, &instances, list) {
227433d6423SLionel Sambuc 		if (inst->dev_id == dev_id) {
228433d6423SLionel Sambuc 			return inst;
229433d6423SLionel Sambuc 		}
230433d6423SLionel Sambuc 	}
231433d6423SLionel Sambuc 	return NULL;
232433d6423SLionel Sambuc }
233433d6423SLionel Sambuc 
234433d6423SLionel Sambuc /*===========================================================================*
235433d6423SLionel Sambuc  *              match_usb_driver                                             *
236433d6423SLionel Sambuc  *===========================================================================*/
237433d6423SLionel Sambuc static int
match_usb_id(struct devmand_usb_match_id * mid,struct usb_device_id * id)238433d6423SLionel Sambuc match_usb_id(struct devmand_usb_match_id *mid, struct usb_device_id *id)
239433d6423SLionel Sambuc {
240433d6423SLionel Sambuc 	int res = 1;
241433d6423SLionel Sambuc 	unsigned long match = mid->match_flags;
242433d6423SLionel Sambuc 	struct usb_device_id *_id = &mid->match_id;
243433d6423SLionel Sambuc 
244433d6423SLionel Sambuc 	if (match & USB_MATCH_ID_VENDOR)
245433d6423SLionel Sambuc 		if (id->idVendor != _id->idVendor) res = 0;
246433d6423SLionel Sambuc 	if (match & USB_MATCH_ID_PRODUCT)
247433d6423SLionel Sambuc 		if (id->idProduct != _id->idProduct) res = 0;
248433d6423SLionel Sambuc 	if (match & USB_MATCH_BCD_DEVICE)
249433d6423SLionel Sambuc 		if (id->bcdDevice != _id->bcdDevice) res = 0;
250433d6423SLionel Sambuc 	if (match & USB_MATCH_DEVICE_PROTOCOL)
251433d6423SLionel Sambuc 		if (id->bDeviceProtocol != _id->bDeviceProtocol) res = 0;
252433d6423SLionel Sambuc 	if (match & USB_MATCH_DEVICE_SUBCLASS)
253433d6423SLionel Sambuc 		if (id->bDeviceSubClass != _id->bDeviceSubClass) res = 0;
254433d6423SLionel Sambuc 	if (match & USB_MATCH_DEVICE_PROTOCOL)
255433d6423SLionel Sambuc 		if (id->bDeviceProtocol != _id->bDeviceProtocol) res = 0;
256433d6423SLionel Sambuc 	if (match & USB_MATCH_INTERFACE_CLASS)
257433d6423SLionel Sambuc 		if (id->bInterfaceClass != _id->bInterfaceClass) res = 0;
258433d6423SLionel Sambuc 	if (match & USB_MATCH_INTERFACE_SUBCLASS)
259433d6423SLionel Sambuc 		if (id->bInterfaceSubClass != _id->bInterfaceSubClass) res = 0;
260433d6423SLionel Sambuc 	if (match & USB_MATCH_INTERFACE_PROTOCOL)
261433d6423SLionel Sambuc 		if (id->bInterfaceProtocol != _id->bInterfaceProtocol) res = 0;
262433d6423SLionel Sambuc 
263433d6423SLionel Sambuc 	if (match == 0UL) {
264433d6423SLionel Sambuc 		res = 0;
265433d6423SLionel Sambuc 	}
266433d6423SLionel Sambuc 
267433d6423SLionel Sambuc 	return res;
268433d6423SLionel Sambuc }
269433d6423SLionel Sambuc 
270433d6423SLionel Sambuc /*===========================================================================*
271433d6423SLionel Sambuc  *              match_usb_driver                                             *
272433d6423SLionel Sambuc  *===========================================================================*/
273433d6423SLionel Sambuc static struct devmand_usb_driver*
match_usb_driver(struct usb_device_id * id)274433d6423SLionel Sambuc match_usb_driver(struct usb_device_id *id)
275433d6423SLionel Sambuc {
276433d6423SLionel Sambuc 	struct devmand_usb_driver *driver;
277433d6423SLionel Sambuc 	struct devmand_usb_match_id *mid;
278433d6423SLionel Sambuc 
279433d6423SLionel Sambuc 	LIST_FOREACH(driver, &drivers, list) {
280433d6423SLionel Sambuc 		LIST_FOREACH(mid, &driver->ids, list) {
281433d6423SLionel Sambuc 			if (match_usb_id(mid, id)) {
282433d6423SLionel Sambuc 				return driver;
283433d6423SLionel Sambuc 			}
284433d6423SLionel Sambuc 		}
285433d6423SLionel Sambuc 	}
286433d6423SLionel Sambuc 	return NULL;
287433d6423SLionel Sambuc }
288433d6423SLionel Sambuc 
289433d6423SLionel Sambuc /*===========================================================================*
290433d6423SLionel Sambuc  *              add_usb_match_id                                             *
291433d6423SLionel Sambuc  *===========================================================================*/
add_usb_driver(char * name)292433d6423SLionel Sambuc struct devmand_usb_driver * add_usb_driver(char *name)
293433d6423SLionel Sambuc {
294433d6423SLionel Sambuc 	struct devmand_usb_driver *udrv = (struct devmand_usb_driver*)
295433d6423SLionel Sambuc 	    malloc(sizeof(struct devmand_usb_driver));
296433d6423SLionel Sambuc 
297433d6423SLionel Sambuc 	LIST_INSERT_HEAD(&drivers, udrv, list);
298433d6423SLionel Sambuc 	LIST_INIT(&udrv->ids);
299433d6423SLionel Sambuc 
300433d6423SLionel Sambuc 	udrv->name = name;
301433d6423SLionel Sambuc 	return udrv;
302433d6423SLionel Sambuc }
303433d6423SLionel Sambuc 
304433d6423SLionel Sambuc /*===========================================================================*
305433d6423SLionel Sambuc  *              add_usb_match_id                                             *
306433d6423SLionel Sambuc  *===========================================================================*/
307433d6423SLionel Sambuc struct devmand_usb_match_id *
add_usb_match_id(struct devmand_usb_driver * drv)308433d6423SLionel Sambuc add_usb_match_id
309433d6423SLionel Sambuc (struct devmand_usb_driver *drv)
310433d6423SLionel Sambuc {
311433d6423SLionel Sambuc 	struct devmand_usb_match_id *id = (struct devmand_usb_match_id*)
312433d6423SLionel Sambuc 	    malloc(sizeof(struct devmand_usb_match_id));
313433d6423SLionel Sambuc 
314433d6423SLionel Sambuc 	memset(id, 0, sizeof(struct devmand_usb_match_id));
315433d6423SLionel Sambuc 
316433d6423SLionel Sambuc 	LIST_INSERT_HEAD(&drv->ids, id, list);
317433d6423SLionel Sambuc 
318433d6423SLionel Sambuc 	return id;
319433d6423SLionel Sambuc }
320433d6423SLionel Sambuc 
321433d6423SLionel Sambuc 
322433d6423SLionel Sambuc /*===========================================================================*
323433d6423SLionel Sambuc  *           parse_config                                                    *
324433d6423SLionel Sambuc  *===========================================================================*/
parse_config()325433d6423SLionel Sambuc static void parse_config()
326433d6423SLionel Sambuc {
327433d6423SLionel Sambuc 	int i, status, error;
328433d6423SLionel Sambuc 	struct stat stats;
329433d6423SLionel Sambuc 	char * dirname;
330433d6423SLionel Sambuc 
331433d6423SLionel Sambuc 	DIR * dir;
332433d6423SLionel Sambuc 	struct dirent entry;
333433d6423SLionel Sambuc 	struct dirent *result;
334433d6423SLionel Sambuc 	char config_file[PATH_MAX];
335433d6423SLionel Sambuc 
336433d6423SLionel Sambuc 	dbg("Parsing configuration directories... ");
337433d6423SLionel Sambuc 	/* Next parse the configuration directories */
338433d6423SLionel Sambuc 	for(i=0; i < args.config_dir_count; i++){
339433d6423SLionel Sambuc 		dirname = args.config_dirs[i];
340433d6423SLionel Sambuc 		dbg("Parsing config dir %s ", dirname);
341433d6423SLionel Sambuc 		status = stat(dirname,&stats);
342433d6423SLionel Sambuc 		if (status == -1){
343433d6423SLionel Sambuc 			error = errno;
344433d6423SLionel Sambuc 			dbg("Failed to read directory '%s':%s (skipping) \n",
345433d6423SLionel Sambuc 			    dirname,strerror(error));
346433d6423SLionel Sambuc 			continue;
347433d6423SLionel Sambuc 		}
348433d6423SLionel Sambuc 		if (!S_ISDIR(stats.st_mode)){
349433d6423SLionel Sambuc 			dbg("Parse configuration skipping %s "
350433d6423SLionel Sambuc 			    "(not a directory) \n",dirname);
351433d6423SLionel Sambuc 			continue;
352433d6423SLionel Sambuc 		}
353433d6423SLionel Sambuc 		dir = opendir(dirname);
354433d6423SLionel Sambuc 		if (dir == NULL){
355433d6423SLionel Sambuc 			error = errno;
356433d6423SLionel Sambuc 			dbg("Parse configuration failed to read dir '%s'"
357433d6423SLionel Sambuc 			    "(skipping) :%s\n",dirname, strerror(error));
358433d6423SLionel Sambuc 			continue;
359433d6423SLionel Sambuc 		}
360433d6423SLionel Sambuc 		while( (status = readdir_r(dir,&entry,&result)) == 0 ){
361433d6423SLionel Sambuc 			if (result == NULL){ /* last entry */
362433d6423SLionel Sambuc 				closedir(dir);
363433d6423SLionel Sambuc 				break;
364433d6423SLionel Sambuc 			}
365433d6423SLionel Sambuc 
366433d6423SLionel Sambuc 			/* concatenate dir and file name to open it */
367433d6423SLionel Sambuc 			snprintf(config_file,PATH_MAX, "%s/%s",
368433d6423SLionel Sambuc 				 dirname,entry.d_name);
369433d6423SLionel Sambuc 			status = stat(config_file, &stats);
370433d6423SLionel Sambuc 			if (status == -1){
371433d6423SLionel Sambuc 				error = errno;
372433d6423SLionel Sambuc 				dbg("Parse configuration Failed to stat file "
373433d6423SLionel Sambuc 				    "'%s': %s (skipping)\n", config_file,
374433d6423SLionel Sambuc 				    strerror(error));
375433d6423SLionel Sambuc 			}
376433d6423SLionel Sambuc 			if (S_ISREG(stats.st_mode)){
377433d6423SLionel Sambuc 				dbg("Parsing file %s",config_file);
378433d6423SLionel Sambuc 				yyin = fopen(config_file, "r");
379433d6423SLionel Sambuc 
380e3cf9c04SJacob Adams 				if (yyin == NULL) {
381433d6423SLionel Sambuc 					dbg("Can not open config file:"
382433d6423SLionel Sambuc 				 	       " %d.\n", errno);
383433d6423SLionel Sambuc 				}
384433d6423SLionel Sambuc 				yyparse();
385433d6423SLionel Sambuc 				dbg("Done.");
386433d6423SLionel Sambuc 				fclose(yyin);
387433d6423SLionel Sambuc 			}
388433d6423SLionel Sambuc 		}
389433d6423SLionel Sambuc 	}
390433d6423SLionel Sambuc 	dbg("Parsing configuration directories done... ");
391433d6423SLionel Sambuc 
392433d6423SLionel Sambuc }
393433d6423SLionel Sambuc 
394433d6423SLionel Sambuc /*===========================================================================*
395433d6423SLionel Sambuc  *           cleanup                                                        *
396433d6423SLionel Sambuc  *===========================================================================*/
cleanup()397433d6423SLionel Sambuc static void cleanup() {
398433d6423SLionel Sambuc 	struct devmand_driver_instance *inst;
399433d6423SLionel Sambuc 	/* destroy fifo */
400433d6423SLionel Sambuc 	dbg("cleaning up... ");
401433d6423SLionel Sambuc 	/* quit all running drivers */
402433d6423SLionel Sambuc 	LIST_FOREACH(inst, &instances, list) {
403433d6423SLionel Sambuc 		dbg("stopping driver %s", inst->label);
404683d394dSBen Gras 		if(inst->drv->downscript) {
405433d6423SLionel Sambuc 			run_downscript (inst);
406683d394dSBen Gras 		}
407433d6423SLionel Sambuc 		stop_driver(inst);
408433d6423SLionel Sambuc 	}
409433d6423SLionel Sambuc 	unlink("/var/run/devmand.pid");
410433d6423SLionel Sambuc }
411433d6423SLionel Sambuc 
sig_int(int sig)412433d6423SLionel Sambuc static void sig_int(int sig) {
413433d6423SLionel Sambuc 	dbg("devman: Received SIGINT... cleaning up.");
414433d6423SLionel Sambuc 	_run = 0;
415433d6423SLionel Sambuc }
416433d6423SLionel Sambuc 
417433d6423SLionel Sambuc /*===========================================================================*
418433d6423SLionel Sambuc  *           create_pid_file                                                 *
419433d6423SLionel Sambuc  *===========================================================================*/
create_pid_file()420433d6423SLionel Sambuc void create_pid_file()
421433d6423SLionel Sambuc {
422433d6423SLionel Sambuc 	FILE *fd;
423433d6423SLionel Sambuc 
424433d6423SLionel Sambuc 	fd = fopen("/var/run/devmand.pid", "r");
425433d6423SLionel Sambuc 	if(fd) {
426433d6423SLionel Sambuc 		fprintf(stderr, "devmand: /var/run/devmand.pid exists... "
427433d6423SLionel Sambuc 		                "another devmand running?\n");
428433d6423SLionel Sambuc 		fclose(fd);
429433d6423SLionel Sambuc 		exit(1);
430433d6423SLionel Sambuc 	} else {
431433d6423SLionel Sambuc 		fd = fopen("/var/run/devmand.pid","w");
432433d6423SLionel Sambuc 		fprintf(fd, "%d", getpid());
433433d6423SLionel Sambuc 		fclose(fd);
434433d6423SLionel Sambuc 	}
435433d6423SLionel Sambuc }
436433d6423SLionel Sambuc 
437433d6423SLionel Sambuc /*===========================================================================*
438433d6423SLionel Sambuc  *           main                                                            *
439433d6423SLionel Sambuc  *===========================================================================*/
main(int argc,char * argv[])440433d6423SLionel Sambuc int main(int argc, char *argv[])
441433d6423SLionel Sambuc {
442433d6423SLionel Sambuc 	int opt, optindex;
443433d6423SLionel Sambuc 	struct devmand_usb_driver *driver;
444433d6423SLionel Sambuc 
445433d6423SLionel Sambuc 
446433d6423SLionel Sambuc 	/* get command line arguments */
447433d6423SLionel Sambuc 	while ((opt = getopt_long(argc, argv, "d:p:vxh?", options, &optindex))
448433d6423SLionel Sambuc 			!= -1) {
449433d6423SLionel Sambuc 		switch (opt) {
450433d6423SLionel Sambuc 			case 'd':/* config directory */
451433d6423SLionel Sambuc 				if (args.config_dir_count >= MAX_CONFIG_DIRS){
452433d6423SLionel Sambuc 				 	fprintf(stderr,"Parse arguments: Maximum"
453433d6423SLionel Sambuc 					        " of %i configuration directories"
454433d6423SLionel Sambuc 						" reached skipping directory '%s'\n"
455433d6423SLionel Sambuc 						, MAX_CONFIG_DIRS, optarg);
456433d6423SLionel Sambuc 				 	break;
457433d6423SLionel Sambuc 				}
458433d6423SLionel Sambuc 				args.config_dirs[args.config_dir_count] = optarg;
459433d6423SLionel Sambuc 				args.config_dir_count++;
460433d6423SLionel Sambuc 				break;
461433d6423SLionel Sambuc 			case 'p': /* sysfs path */
462433d6423SLionel Sambuc 				args.path = optarg;
463433d6423SLionel Sambuc 				break;
464433d6423SLionel Sambuc 			case 'v': /* verbose */
465433d6423SLionel Sambuc 				args.verbose = 1;
466433d6423SLionel Sambuc 				break;
467433d6423SLionel Sambuc 			case 'x': /* check config */
468433d6423SLionel Sambuc 				args.check_config = 1;
469433d6423SLionel Sambuc 				break;
470433d6423SLionel Sambuc 			case 'h': /* help */
471433d6423SLionel Sambuc 			case '?': /* help */
472433d6423SLionel Sambuc 			default:
473433d6423SLionel Sambuc 				display_usage(argv[0]);
474433d6423SLionel Sambuc 				return 0;
475433d6423SLionel Sambuc 		}
476433d6423SLionel Sambuc 	}
477433d6423SLionel Sambuc 
478433d6423SLionel Sambuc 
479433d6423SLionel Sambuc 	/* is path set? */
480433d6423SLionel Sambuc 	if (args.path == NULL) {
481433d6423SLionel Sambuc 		args.path = "/sys/";
482433d6423SLionel Sambuc 	}
483433d6423SLionel Sambuc 
484433d6423SLionel Sambuc 	/* is the configuration directory set? */
485433d6423SLionel Sambuc 	if (args.config_dir_count == 0) {
486433d6423SLionel Sambuc 		dbg("Using default configuration directory");
487433d6423SLionel Sambuc 		args.config_dirs[0] = "/etc/devmand";
488433d6423SLionel Sambuc 		args.config_dir_count = 1;
489433d6423SLionel Sambuc 	}
490433d6423SLionel Sambuc 
491433d6423SLionel Sambuc 	/* If we only check the configuration run and exit imediately */
492433d6423SLionel Sambuc 	if (args.check_config == 1){
493433d6423SLionel Sambuc 		fprintf(stdout, "Only parsing configuration\n");
494433d6423SLionel Sambuc 		parse_config();
495433d6423SLionel Sambuc 		exit(0);
496433d6423SLionel Sambuc 	}
497433d6423SLionel Sambuc 
498433d6423SLionel Sambuc 	create_pid_file();
499433d6423SLionel Sambuc 
500433d6423SLionel Sambuc 	parse_config();
501433d6423SLionel Sambuc 	LIST_FOREACH(driver, &drivers, list) {
502683d394dSBen Gras 		if (driver->upscript) {
503433d6423SLionel Sambuc 			run_cleanscript(driver);
504433d6423SLionel Sambuc 		}
505683d394dSBen Gras 	}
506433d6423SLionel Sambuc 
507433d6423SLionel Sambuc 	signal(SIGINT, sig_int);
508433d6423SLionel Sambuc 
509433d6423SLionel Sambuc 	main_loop();
510433d6423SLionel Sambuc 
511433d6423SLionel Sambuc 	cleanup();
512433d6423SLionel Sambuc 
513433d6423SLionel Sambuc 	return 0;
514433d6423SLionel Sambuc }
515433d6423SLionel Sambuc 
516433d6423SLionel Sambuc /*===========================================================================*
517433d6423SLionel Sambuc  *           determine_type                                                  *
518433d6423SLionel Sambuc  *===========================================================================*/
determine_type(char * path)519433d6423SLionel Sambuc static enum dev_type determine_type (char *path)
520433d6423SLionel Sambuc {
521433d6423SLionel Sambuc 	FILE * fd;
522433d6423SLionel Sambuc 	char *mypath;
523433d6423SLionel Sambuc 	char buf[256];
524433d6423SLionel Sambuc 	int res;
525433d6423SLionel Sambuc 
526433d6423SLionel Sambuc 	mypath = (char *) calloc(1, strlen(path)+strlen(DEVMAN_TYPE_NAME)+1);
527433d6423SLionel Sambuc 
528433d6423SLionel Sambuc 	if (mypath == NULL) {
529433d6423SLionel Sambuc 		fprintf(stderr, "ERROR: out of mem\n");
530433d6423SLionel Sambuc 		cleanup();
531433d6423SLionel Sambuc 		exit(1);
532433d6423SLionel Sambuc 	}
533433d6423SLionel Sambuc 
534433d6423SLionel Sambuc 	strcat(mypath, path);
535433d6423SLionel Sambuc 	strcat(mypath, DEVMAN_TYPE_NAME);
536433d6423SLionel Sambuc 
537433d6423SLionel Sambuc 	fd = fopen(mypath, "r");
538433d6423SLionel Sambuc 	free(mypath);
539433d6423SLionel Sambuc 
540433d6423SLionel Sambuc 	if (fd == NULL) {
541433d6423SLionel Sambuc 		fprintf(stderr, "WARN: could not open %s\n", mypath);
542433d6423SLionel Sambuc 		return DEV_TYPE_UNKOWN;
543433d6423SLionel Sambuc 	}
544433d6423SLionel Sambuc 
5453a1943c1SJacob Adams 	res = fscanf(fd , "%255s\n", buf);
546433d6423SLionel Sambuc 	fclose(fd);
547433d6423SLionel Sambuc 
548433d6423SLionel Sambuc 	if (res != 1) {
549433d6423SLionel Sambuc 		fprintf(stderr, "WARN: could not parse %s\n", mypath);
550433d6423SLionel Sambuc 		return DEV_TYPE_UNKOWN;
551433d6423SLionel Sambuc 	}
552433d6423SLionel Sambuc 
553433d6423SLionel Sambuc 	if (strcmp(buf, "USB_DEV") == 0) {
554433d6423SLionel Sambuc 		return DEV_TYPE_USB_DEVICE;
555433d6423SLionel Sambuc 	} else if (strcmp(buf, "USB_INTF") == 0) {
556433d6423SLionel Sambuc 		return DEV_TYPE_USB_INTF;
557433d6423SLionel Sambuc 	}
558433d6423SLionel Sambuc 
559433d6423SLionel Sambuc 	return  DEV_TYPE_UNKOWN;
560433d6423SLionel Sambuc }
561433d6423SLionel Sambuc 
562433d6423SLionel Sambuc /*===========================================================================*
563433d6423SLionel Sambuc  *           read_hex_uint                                                   *
564433d6423SLionel Sambuc  *===========================================================================*/
read_hex_uint(char * base_path,char * name,unsigned int * val)565433d6423SLionel Sambuc static int read_hex_uint(char *base_path, char *name, unsigned int* val )
566433d6423SLionel Sambuc {
567433d6423SLionel Sambuc 	char my_path[PATH_LEN];
568433d6423SLionel Sambuc 	FILE *fd;
569433d6423SLionel Sambuc 	memset(my_path,0,PATH_LEN);
570433d6423SLionel Sambuc 	int ret = 0;
571433d6423SLionel Sambuc 
572433d6423SLionel Sambuc 	strcat(my_path, base_path);
573433d6423SLionel Sambuc 	strcat(my_path, name);
574433d6423SLionel Sambuc 
575433d6423SLionel Sambuc 	fd = fopen(my_path, "r");
576433d6423SLionel Sambuc 
577433d6423SLionel Sambuc 	if (fd == NULL) {
578433d6423SLionel Sambuc 		fprintf(stderr, "WARN: could not open %s\n", my_path);
579433d6423SLionel Sambuc 		return EEXIST;
580433d6423SLionel Sambuc 	} else	if (fscanf(fd, "0x%x\n", val ) != 1) {
581433d6423SLionel Sambuc 		fprintf(stderr, "WARN: could not parse %s\n", my_path);
582433d6423SLionel Sambuc 		ret = EINVAL;
583433d6423SLionel Sambuc 	}
584433d6423SLionel Sambuc 	fclose(fd);
585433d6423SLionel Sambuc 
586433d6423SLionel Sambuc 	return ret;
587433d6423SLionel Sambuc }
588433d6423SLionel Sambuc 
589433d6423SLionel Sambuc /*===========================================================================*
590433d6423SLionel Sambuc  *               get_major                                                   *
591433d6423SLionel Sambuc  *===========================================================================*/
get_major()592433d6423SLionel Sambuc static int get_major() {
593433d6423SLionel Sambuc 	int i, ret = args.major_offset;
594433d6423SLionel Sambuc 
595433d6423SLionel Sambuc 	for (i=0; i < 16; i++) {
596433d6423SLionel Sambuc 		int j;
597433d6423SLionel Sambuc 		for (j = 0; j < 8; j++ ) {
598433d6423SLionel Sambuc 			if ((major_bitmap[i] & (1 << j))) {
599433d6423SLionel Sambuc 				major_bitmap[i] &= !(1 << j);
600433d6423SLionel Sambuc 				return ret;
601433d6423SLionel Sambuc 			}
602433d6423SLionel Sambuc 			ret++;
603433d6423SLionel Sambuc 		}
604433d6423SLionel Sambuc 	}
605433d6423SLionel Sambuc 	return INVAL_MAJOR;
606433d6423SLionel Sambuc }
607433d6423SLionel Sambuc 
608433d6423SLionel Sambuc /*===========================================================================*
609433d6423SLionel Sambuc  *               put_major                                                   *
610433d6423SLionel Sambuc  *===========================================================================*/
put_major(int major)611433d6423SLionel Sambuc static void put_major(int major) {
612433d6423SLionel Sambuc 	int i;
613433d6423SLionel Sambuc 	major -= args.major_offset;
614433d6423SLionel Sambuc 	assert(major >= 0);
615433d6423SLionel Sambuc 
616433d6423SLionel Sambuc 	for (i=0; i < 16; i++) {
617433d6423SLionel Sambuc 		int j;
618433d6423SLionel Sambuc 		for (j = 0; j < 8; j++ ) {
619433d6423SLionel Sambuc 			if (major==0) {
620433d6423SLionel Sambuc 				assert(!(major_bitmap[i] & (1 <<j)));
621433d6423SLionel Sambuc 				major_bitmap[i] |= (1 << j);
622433d6423SLionel Sambuc 				return;
623433d6423SLionel Sambuc 			}
624433d6423SLionel Sambuc 			major--;
625433d6423SLionel Sambuc 		}
626433d6423SLionel Sambuc 	}
627433d6423SLionel Sambuc }
628433d6423SLionel Sambuc 
629433d6423SLionel Sambuc /*===========================================================================*
630433d6423SLionel Sambuc  *          generate_usb_device_id                                           *
631433d6423SLionel Sambuc  *===========================================================================*/
632433d6423SLionel Sambuc static struct usb_device_id *
generate_usb_device_id(char * path,int is_interface)633433d6423SLionel Sambuc generate_usb_device_id(char * path, int is_interface)
634433d6423SLionel Sambuc {
635433d6423SLionel Sambuc 	struct usb_device_id *ret;
636433d6423SLionel Sambuc 	int res;
637433d6423SLionel Sambuc 	unsigned int val;
638433d6423SLionel Sambuc 
639433d6423SLionel Sambuc 	ret = (struct usb_device_id *)
640433d6423SLionel Sambuc 	    calloc(1,sizeof (struct usb_device_id));
641433d6423SLionel Sambuc 
642433d6423SLionel Sambuc 	if (is_interface) {
643433d6423SLionel Sambuc 
644433d6423SLionel Sambuc 		res = read_hex_uint(path, "../idVendor", &val);
645433d6423SLionel Sambuc 		if (res) goto err;
646433d6423SLionel Sambuc 		ret->idVendor = val;
647433d6423SLionel Sambuc 
648433d6423SLionel Sambuc 		res = read_hex_uint(path, "../idProduct", &val);
649433d6423SLionel Sambuc 		if (res) goto err;
650433d6423SLionel Sambuc 		ret->idProduct = val;
651433d6423SLionel Sambuc #if 0
652433d6423SLionel Sambuc 		res = read_hex_uint(path, "../bcdDevice", &val);
653433d6423SLionel Sambuc 		if (res) goto err;
654433d6423SLionel Sambuc 		ret->bcdDevice = val;
655433d6423SLionel Sambuc #endif
656433d6423SLionel Sambuc 		res = read_hex_uint(path, "../bDeviceClass", &val);
657433d6423SLionel Sambuc 		if (res) goto err;
658433d6423SLionel Sambuc 		ret->bDeviceClass = val;
659433d6423SLionel Sambuc 
660433d6423SLionel Sambuc 		res = read_hex_uint(path, "../bDeviceSubClass", &val);
661433d6423SLionel Sambuc 		if (res) goto err;
662433d6423SLionel Sambuc 		ret->bDeviceSubClass = val;
663433d6423SLionel Sambuc 
664433d6423SLionel Sambuc 		res = read_hex_uint(path, "../bDeviceProtocol", &val);
665433d6423SLionel Sambuc 		if (res) goto err;
666433d6423SLionel Sambuc 		ret->bDeviceProtocol = val;
667433d6423SLionel Sambuc 
668433d6423SLionel Sambuc 		res = read_hex_uint(path, "/bInterfaceClass", &val);
669433d6423SLionel Sambuc 		if (res) goto err;
670433d6423SLionel Sambuc 		ret->bInterfaceClass = val;
671433d6423SLionel Sambuc 
672433d6423SLionel Sambuc 		res = read_hex_uint(path, "/bInterfaceSubClass", &val);
673433d6423SLionel Sambuc 		if (res) goto err;
674433d6423SLionel Sambuc 		ret->bInterfaceSubClass = val;
675433d6423SLionel Sambuc 
676433d6423SLionel Sambuc 		res = read_hex_uint(path, "/bInterfaceProtocol", &val);
677433d6423SLionel Sambuc 		if (res) goto err;
678433d6423SLionel Sambuc 		ret->bInterfaceProtocol = val;
679433d6423SLionel Sambuc 	}
680433d6423SLionel Sambuc 
681433d6423SLionel Sambuc 	return ret;
682433d6423SLionel Sambuc 
683433d6423SLionel Sambuc err:
684433d6423SLionel Sambuc 	free(ret);
685433d6423SLionel Sambuc 	return NULL;
686433d6423SLionel Sambuc }
687433d6423SLionel Sambuc 
688433d6423SLionel Sambuc /*===========================================================================*
689433d6423SLionel Sambuc  *            usb_intf_add_even                                              *
690433d6423SLionel Sambuc  *===========================================================================*/
usb_intf_add_event(char * path,int dev_id)691433d6423SLionel Sambuc static void usb_intf_add_event(char *path, int dev_id)
692433d6423SLionel Sambuc {
693433d6423SLionel Sambuc 	struct usb_device_id *id;
694433d6423SLionel Sambuc 	struct devmand_usb_driver *drv;
695433d6423SLionel Sambuc 	struct devmand_driver_instance *drv_inst;
696433d6423SLionel Sambuc 	int major, ret;
697433d6423SLionel Sambuc 
698433d6423SLionel Sambuc 	/* generate usb_match_id */
699433d6423SLionel Sambuc 	id = generate_usb_device_id(path,TRUE);
700433d6423SLionel Sambuc 	if (id == NULL) {
701433d6423SLionel Sambuc 		fprintf(stderr, "WARN: could not create usb_device id...\n"
702433d6423SLionel Sambuc 		                "      ommiting event\n");
703433d6423SLionel Sambuc 		free(id);
704433d6423SLionel Sambuc 		return;
705433d6423SLionel Sambuc 	}
706433d6423SLionel Sambuc 
707433d6423SLionel Sambuc 	/* find suitable driver */
708433d6423SLionel Sambuc 	drv = match_usb_driver(id);
709433d6423SLionel Sambuc 	free (id);
710433d6423SLionel Sambuc 
711433d6423SLionel Sambuc 	if (drv == NULL) {
712433d6423SLionel Sambuc 		dbg("INFO: could not find a suitable driver for %s", path);
713433d6423SLionel Sambuc 		return;
714433d6423SLionel Sambuc 	}
715433d6423SLionel Sambuc 
716433d6423SLionel Sambuc 	/* create instance */
717433d6423SLionel Sambuc 	drv_inst = (struct devmand_driver_instance *)
718433d6423SLionel Sambuc 	    calloc(1,sizeof(struct devmand_driver_instance));
719433d6423SLionel Sambuc 
720433d6423SLionel Sambuc 	if (drv_inst == NULL) {
721433d6423SLionel Sambuc 		fprintf(stderr, "ERROR: out of memory");
722433d6423SLionel Sambuc 		return; /* maybe better quit here. */
723433d6423SLionel Sambuc 	}
724433d6423SLionel Sambuc 
725433d6423SLionel Sambuc 
726433d6423SLionel Sambuc 	/* allocate inode number, if device files needed */
727433d6423SLionel Sambuc 	major = get_major();
728433d6423SLionel Sambuc 	if (major == INVAL_MAJOR) {
729433d6423SLionel Sambuc 		fprintf(stderr, "WARN: ran out of major numbers\n"
730433d6423SLionel Sambuc 		                "      cannot start driver %s for %s\n",
731433d6423SLionel Sambuc 							   drv->name, path);
732433d6423SLionel Sambuc 		return;
733433d6423SLionel Sambuc 	}
734433d6423SLionel Sambuc 
735433d6423SLionel Sambuc 	drv_inst->major  = major;
736433d6423SLionel Sambuc 	drv_inst->drv    = drv;
737433d6423SLionel Sambuc 	drv_inst->dev_id = dev_id;
738433d6423SLionel Sambuc 
739433d6423SLionel Sambuc 
740*c58da9fbSDavid van Moolenbroek 	/* start driver (invoke minix-service) */
741433d6423SLionel Sambuc 	start_driver(drv_inst);
742433d6423SLionel Sambuc 
743433d6423SLionel Sambuc 	/*
744433d6423SLionel Sambuc 	 * run the up action
745433d6423SLionel Sambuc 	 *
746433d6423SLionel Sambuc 	 * An up action can be any executable. Before running it devmand
747433d6423SLionel Sambuc 	 * will set certain environment variables so the script can configure
748433d6423SLionel Sambuc 	 * the device (or generate device files, etc). See up_action() for that.
749433d6423SLionel Sambuc 	 */
750433d6423SLionel Sambuc 	if (drv->upscript) {
751433d6423SLionel Sambuc 		ret = run_upscript(drv_inst);
752433d6423SLionel Sambuc 		if (ret) {
753433d6423SLionel Sambuc 			stop_driver(drv_inst);
754433d6423SLionel Sambuc 			fprintf(stderr, "devmand: warning, could not run up_action\n");
755433d6423SLionel Sambuc 			free(drv_inst);
756433d6423SLionel Sambuc 			return;
757433d6423SLionel Sambuc 		}
758433d6423SLionel Sambuc 	}
759433d6423SLionel Sambuc 
760433d6423SLionel Sambuc 	LIST_INSERT_HEAD(&instances,drv_inst,list);
761433d6423SLionel Sambuc }
762433d6423SLionel Sambuc 
763433d6423SLionel Sambuc /*===========================================================================*
764433d6423SLionel Sambuc  *            usb_intf_remove_event                                          *
765433d6423SLionel Sambuc  *===========================================================================*/
usb_intf_remove_event(char * path,int dev_id)766433d6423SLionel Sambuc static void usb_intf_remove_event(char *path, int dev_id)
767433d6423SLionel Sambuc {
768433d6423SLionel Sambuc 	struct devmand_driver_instance *inst;
769433d6423SLionel Sambuc 	struct devmand_usb_driver *drv;
770433d6423SLionel Sambuc 	int ret;
771433d6423SLionel Sambuc 
772433d6423SLionel Sambuc 	/* find the driver instance */
773433d6423SLionel Sambuc 	inst = find_instance(dev_id);
774433d6423SLionel Sambuc 
775433d6423SLionel Sambuc 	if (inst == NULL) {
776433d6423SLionel Sambuc 		dbg("No driver running for id: %d", dev_id);
777433d6423SLionel Sambuc 		return;
778433d6423SLionel Sambuc 	}
779433d6423SLionel Sambuc 	drv = inst->drv;
780433d6423SLionel Sambuc 
781433d6423SLionel Sambuc 	/* run the down script */
782433d6423SLionel Sambuc 	if (drv->downscript) {
783433d6423SLionel Sambuc 		ret = run_downscript(inst);
784433d6423SLionel Sambuc 		if (ret) {
785433d6423SLionel Sambuc 			fprintf(stderr, "WARN: error running up_action");
786433d6423SLionel Sambuc 		}
787433d6423SLionel Sambuc 	}
788433d6423SLionel Sambuc 
789433d6423SLionel Sambuc 	/* stop the driver */
790433d6423SLionel Sambuc 	stop_driver(inst);
791433d6423SLionel Sambuc 
792433d6423SLionel Sambuc 	/* free major */
793433d6423SLionel Sambuc 	put_major(inst->major);
794433d6423SLionel Sambuc 
795433d6423SLionel Sambuc 	/* free instance */
796433d6423SLionel Sambuc 	LIST_REMOVE(inst,list);
797433d6423SLionel Sambuc 	free(inst);
798433d6423SLionel Sambuc }
799433d6423SLionel Sambuc 
800433d6423SLionel Sambuc /*===========================================================================*
801433d6423SLionel Sambuc  *           handle_event                                                    *
802433d6423SLionel Sambuc  *===========================================================================*/
handle_event(char * event)803433d6423SLionel Sambuc static void handle_event(char *event)
804433d6423SLionel Sambuc {
805433d6423SLionel Sambuc 	enum dev_type type;
806433d6423SLionel Sambuc 	char path[PATH_LEN];
807433d6423SLionel Sambuc 	char tmp_path[PATH_LEN];
808433d6423SLionel Sambuc 	int dev_id, res;
809433d6423SLionel Sambuc 
810433d6423SLionel Sambuc 	path[0]=0;
811433d6423SLionel Sambuc 
812433d6423SLionel Sambuc 	if (strncmp("ADD ", event, 4) == 0) {
813433d6423SLionel Sambuc 
814433d6423SLionel Sambuc 		/* read data from event */
815433d6423SLionel Sambuc 		res = sscanf(event, "ADD %s 0x%x", tmp_path, &dev_id);
816433d6423SLionel Sambuc 
817433d6423SLionel Sambuc 		if (res != 2) {
818433d6423SLionel Sambuc 			fprintf(stderr, "WARN: could not parse event: %s", event);
819433d6423SLionel Sambuc 			fprintf(stderr, "WARN: omitting event: %s", event);
820433d6423SLionel Sambuc 		}
821433d6423SLionel Sambuc 
822433d6423SLionel Sambuc 		strcpy(path, args.path);
823433d6423SLionel Sambuc 		strcat(path, tmp_path);
824433d6423SLionel Sambuc 
825433d6423SLionel Sambuc 		/* what kind of device is added? */
826433d6423SLionel Sambuc 		type = determine_type(path);
827433d6423SLionel Sambuc 
828433d6423SLionel Sambuc 		switch (type) {
829433d6423SLionel Sambuc 			case DEV_TYPE_USB_DEVICE:
830433d6423SLionel Sambuc 				dbg("USB device added: ommited....");
831433d6423SLionel Sambuc 				/* ommit usb devices for now */
832433d6423SLionel Sambuc 				break;
833433d6423SLionel Sambuc 			case DEV_TYPE_USB_INTF:
834433d6423SLionel Sambuc 				dbg("USB interface added: (%s, devid: = %d)",path, dev_id);
835433d6423SLionel Sambuc 				usb_intf_add_event(path, dev_id);
836433d6423SLionel Sambuc 				return;
837433d6423SLionel Sambuc 			default:
838433d6423SLionel Sambuc 				dbg("default");
839433d6423SLionel Sambuc 				fprintf(stderr, "WARN: ommiting event\n");
840433d6423SLionel Sambuc 		}
841433d6423SLionel Sambuc 	} else if (strncmp("REMOVE ", event, 7) == 0) {
842433d6423SLionel Sambuc 
843433d6423SLionel Sambuc 		/* read data from event */
844433d6423SLionel Sambuc 		res = sscanf(event,"REMOVE %s 0x%x", tmp_path, &dev_id);
845433d6423SLionel Sambuc 
846433d6423SLionel Sambuc 		if (res != 2) {
847433d6423SLionel Sambuc 			fprintf(stderr, "WARN: could not parse event: %s", event);
848433d6423SLionel Sambuc 			fprintf(stderr, "WARN: omitting event: %s", event);
849433d6423SLionel Sambuc 		}
850433d6423SLionel Sambuc 
851433d6423SLionel Sambuc 		usb_intf_remove_event(path, dev_id);
852433d6423SLionel Sambuc 
853433d6423SLionel Sambuc #if 0
854433d6423SLionel Sambuc 		strcpy(path, args.path);
855433d6423SLionel Sambuc 		strcat(path, tmp_path);
856433d6423SLionel Sambuc 
857433d6423SLionel Sambuc 		/* what kind of device is added? */
858433d6423SLionel Sambuc 		type = determine_type(path);
859433d6423SLionel Sambuc 
860433d6423SLionel Sambuc 		switch (type) {
861433d6423SLionel Sambuc 			case DEV_TYPE_USB_DEVICE:
862433d6423SLionel Sambuc 				/* ommit usb devices for now */
863433d6423SLionel Sambuc 				break;
864433d6423SLionel Sambuc 			case DEV_TYPE_USB_INTF:
865433d6423SLionel Sambuc 				usb_intf_remove_event(path, dev_id);
866433d6423SLionel Sambuc 				return;
867433d6423SLionel Sambuc 			default:
868433d6423SLionel Sambuc 				fprintf(stderr, "WARN: ommiting event\n");
869433d6423SLionel Sambuc 		}
870433d6423SLionel Sambuc #endif
871433d6423SLionel Sambuc 
872433d6423SLionel Sambuc 	}
873433d6423SLionel Sambuc }
874433d6423SLionel Sambuc 
875433d6423SLionel Sambuc /*===========================================================================*
876433d6423SLionel Sambuc  *           main_loop                                                       *
877433d6423SLionel Sambuc  *===========================================================================*/
main_loop()878433d6423SLionel Sambuc static void main_loop()
879433d6423SLionel Sambuc {
880433d6423SLionel Sambuc 	char ev_path[128];
881433d6423SLionel Sambuc 	char buf[256];
882433d6423SLionel Sambuc 	int len;
883433d6423SLionel Sambuc 	FILE* fd;
884433d6423SLionel Sambuc 	len = strlen(args.path);
885433d6423SLionel Sambuc 
886433d6423SLionel Sambuc 	/* init major numbers */
887433d6423SLionel Sambuc 
888433d6423SLionel Sambuc 	memset(&major_bitmap, 0xff, 16);
889433d6423SLionel Sambuc 
890433d6423SLionel Sambuc 	if (len > 128 - 7 /*len of "events" */) {
891433d6423SLionel Sambuc 		fprintf(stderr, "pathname to long\n");
892433d6423SLionel Sambuc 		cleanup();
893433d6423SLionel Sambuc 		exit(1);
894433d6423SLionel Sambuc 	}
895433d6423SLionel Sambuc 
896433d6423SLionel Sambuc 	strcpy(ev_path, args.path);
897433d6423SLionel Sambuc 	strcat(ev_path, "events");
898433d6423SLionel Sambuc 
899433d6423SLionel Sambuc 
900433d6423SLionel Sambuc 	while (_run) {
901433d6423SLionel Sambuc 
902433d6423SLionel Sambuc 		char *res;
903433d6423SLionel Sambuc 
904433d6423SLionel Sambuc 		fd = fopen(ev_path, "r");
905433d6423SLionel Sambuc 		if (fd == NULL) {
906433d6423SLionel Sambuc 			/*
907433d6423SLionel Sambuc 			 * ENFILE is a temporary failure, often caused by
908433d6423SLionel Sambuc 			 * running the test set.  Don't die from that..
909433d6423SLionel Sambuc 			 */
910433d6423SLionel Sambuc 			if (errno == ENFILE) {
911433d6423SLionel Sambuc 				usleep(50000);
912433d6423SLionel Sambuc 				continue;
913433d6423SLionel Sambuc 			}
914433d6423SLionel Sambuc 
915433d6423SLionel Sambuc 			fprintf(stderr,"devmand error: could not open event "
916433d6423SLionel Sambuc 				"file %s bailing out\n", ev_path);
917433d6423SLionel Sambuc 			cleanup();
918433d6423SLionel Sambuc 			exit(1);
919433d6423SLionel Sambuc 		}
920433d6423SLionel Sambuc 
921433d6423SLionel Sambuc 		res = fgets(buf, 256, fd);
922433d6423SLionel Sambuc 		fclose(fd);
923433d6423SLionel Sambuc 
924433d6423SLionel Sambuc 		if (res == NULL) {
925433d6423SLionel Sambuc 			usleep(50000);
926433d6423SLionel Sambuc 			continue;
927433d6423SLionel Sambuc 		}
928433d6423SLionel Sambuc 		dbg("handle_event:  %s", buf);
929433d6423SLionel Sambuc 		handle_event(buf);
930433d6423SLionel Sambuc 	}
931433d6423SLionel Sambuc }
932433d6423SLionel Sambuc 
933433d6423SLionel Sambuc /*===========================================================================*
934433d6423SLionel Sambuc  *           display_usage                                                   *
935433d6423SLionel Sambuc  *===========================================================================*/
display_usage(const char * name)936433d6423SLionel Sambuc static void display_usage(const char *name)
937433d6423SLionel Sambuc {
938433d6423SLionel Sambuc 	printf("Usage: %s [{-p|--pathname} PATH_TO_SYS}"
939433d6423SLionel Sambuc 	       " [{-d|--config-dir} CONFIG_DIR] [-v|--verbose]"
940433d6423SLionel Sambuc 	       " [[x||--check-config]\n", name);
941433d6423SLionel Sambuc }
942433d6423SLionel Sambuc 
943