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