xref: /minix3/minix/commands/devmand/main.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc #include <stdio.h>
2*433d6423SLionel Sambuc #include <stdlib.h>
3*433d6423SLionel Sambuc #include <getopt.h>
4*433d6423SLionel Sambuc #include <errno.h>
5*433d6423SLionel Sambuc #include <string.h>
6*433d6423SLionel Sambuc #include <lib.h>
7*433d6423SLionel Sambuc #include <sys/stat.h>
8*433d6423SLionel Sambuc #include <dirent.h>
9*433d6423SLionel Sambuc #include <assert.h>
10*433d6423SLionel Sambuc #include <signal.h>
11*433d6423SLionel Sambuc #include <minix/dmap.h>
12*433d6423SLionel Sambuc #include "usb_driver.h"
13*433d6423SLionel Sambuc #include "proto.h"
14*433d6423SLionel Sambuc 
15*433d6423SLionel Sambuc #define SERVICE_BINARY "/bin/service"
16*433d6423SLionel Sambuc 
17*433d6423SLionel Sambuc 
18*433d6423SLionel Sambuc #define DEVMAN_TYPE_NAME "dev_type"
19*433d6423SLionel Sambuc #define PATH_LEN 256
20*433d6423SLionel Sambuc #define INVAL_MAJOR -1
21*433d6423SLionel Sambuc #define MAX_CONFIG_DIRS 4
22*433d6423SLionel Sambuc 
23*433d6423SLionel Sambuc static void main_loop();
24*433d6423SLionel Sambuc static void handle_event();
25*433d6423SLionel Sambuc static void cleanup();
26*433d6423SLionel Sambuc static void parse_config();
27*433d6423SLionel Sambuc static void display_usage();
28*433d6423SLionel Sambuc static enum dev_type determine_type(char *path);
29*433d6423SLionel Sambuc static int get_major();
30*433d6423SLionel Sambuc static void create_pid_file();
31*433d6423SLionel Sambuc static void put_major(int major);
32*433d6423SLionel Sambuc static struct devmand_usb_driver* match_usb_driver(struct usb_device_id *id);
33*433d6423SLionel Sambuc static struct devmand_driver_instance *find_instance(int dev_id);
34*433d6423SLionel Sambuc 
35*433d6423SLionel Sambuc #define dbg(fmt, ... ) \
36*433d6423SLionel Sambuc 	if (args.verbose) \
37*433d6423SLionel Sambuc 	printf("%8s:%4d: %13s()| "fmt"\n", __FILE__, __LINE__, __func__,  ##__VA_ARGS__ )
38*433d6423SLionel Sambuc 
39*433d6423SLionel Sambuc static LIST_HEAD(usb_driver_head, devmand_usb_driver) drivers =
40*433d6423SLionel Sambuc     LIST_HEAD_INITIALIZER(drivers);
41*433d6423SLionel Sambuc static LIST_HEAD(usb_driver_inst_head, devmand_driver_instance) instances =
42*433d6423SLionel Sambuc     LIST_HEAD_INITIALIZER(instances);
43*433d6423SLionel Sambuc 
44*433d6423SLionel Sambuc 
45*433d6423SLionel Sambuc static int _run = 1;
46*433d6423SLionel Sambuc struct global_args {
47*433d6423SLionel Sambuc 	char *path;
48*433d6423SLionel Sambuc 	char *config_dirs[MAX_CONFIG_DIRS];
49*433d6423SLionel Sambuc 	int config_dir_count ;
50*433d6423SLionel Sambuc 	int major_offset;
51*433d6423SLionel Sambuc 	int verbose;
52*433d6423SLionel Sambuc 	int check_config;
53*433d6423SLionel Sambuc };
54*433d6423SLionel Sambuc 
55*433d6423SLionel Sambuc enum dev_type {
56*433d6423SLionel Sambuc 	DEV_TYPE_USB_DEVICE,
57*433d6423SLionel Sambuc 	DEV_TYPE_USB_INTF,
58*433d6423SLionel Sambuc 	DEV_TYPE_UNKOWN
59*433d6423SLionel Sambuc };
60*433d6423SLionel Sambuc 
61*433d6423SLionel Sambuc extern FILE *yyin;
62*433d6423SLionel Sambuc 
63*433d6423SLionel Sambuc static struct global_args args = {
64*433d6423SLionel Sambuc 	.path = NULL,
65*433d6423SLionel Sambuc 	.config_dirs = {NULL,NULL,NULL,NULL},
66*433d6423SLionel Sambuc 	.config_dir_count = 0,
67*433d6423SLionel Sambuc 	.major_offset = USB_BASE_MAJOR,
68*433d6423SLionel Sambuc 	.verbose = 0,
69*433d6423SLionel Sambuc 	.check_config = 0};
70*433d6423SLionel Sambuc 
71*433d6423SLionel Sambuc static struct option options[] =
72*433d6423SLionel Sambuc {
73*433d6423SLionel Sambuc 	{"dir"   ,    required_argument, NULL, 'd'},
74*433d6423SLionel Sambuc 	{"path",      required_argument, NULL, 'p'},
75*433d6423SLionel Sambuc 	{"verbose",    required_argument, NULL, 'v'},
76*433d6423SLionel Sambuc 	{"check-config", no_argument,       NULL, 'x'},
77*433d6423SLionel Sambuc 	{0,0,0,0} /* terminating entry */
78*433d6423SLionel Sambuc };
79*433d6423SLionel Sambuc 
80*433d6423SLionel Sambuc static char major_bitmap[16]; /* can store up to 128 major number states */
81*433d6423SLionel Sambuc 
82*433d6423SLionel Sambuc 
83*433d6423SLionel Sambuc /*===========================================================================*
84*433d6423SLionel Sambuc  *             run_upscript                                                  *
85*433d6423SLionel Sambuc  *===========================================================================*/
86*433d6423SLionel Sambuc int run_upscript(struct devmand_driver_instance *inst)
87*433d6423SLionel Sambuc {
88*433d6423SLionel Sambuc 	char cmdl[1024];
89*433d6423SLionel Sambuc 	cmdl[0] = 0;
90*433d6423SLionel Sambuc 	int ret;
91*433d6423SLionel Sambuc 
92*433d6423SLionel Sambuc 	snprintf(cmdl, 1024, "%s up %s %d %d",
93*433d6423SLionel Sambuc 	    inst->drv->upscript, inst->label, inst->major, inst->dev_id);
94*433d6423SLionel Sambuc 	dbg("Running Upscript:  \"%s\"", cmdl);
95*433d6423SLionel Sambuc 	ret = system(cmdl);
96*433d6423SLionel Sambuc 	if (ret != 0) {
97*433d6423SLionel Sambuc 		return EINVAL;
98*433d6423SLionel Sambuc 	}
99*433d6423SLionel Sambuc 	return 0;
100*433d6423SLionel Sambuc }
101*433d6423SLionel Sambuc 
102*433d6423SLionel Sambuc /*===========================================================================*
103*433d6423SLionel Sambuc  *             run_cleanscript                                               *
104*433d6423SLionel Sambuc  *===========================================================================*/
105*433d6423SLionel Sambuc int run_cleanscript(struct devmand_usb_driver *drv)
106*433d6423SLionel Sambuc {
107*433d6423SLionel Sambuc 	char cmdl[1024];
108*433d6423SLionel Sambuc 	cmdl[0] = 0;
109*433d6423SLionel Sambuc 	int ret;
110*433d6423SLionel Sambuc 
111*433d6423SLionel Sambuc 	snprintf(cmdl, 1024, "%s clean %s ",
112*433d6423SLionel Sambuc 		drv->upscript, drv->devprefix);
113*433d6423SLionel Sambuc 	dbg("Running Upscript:  \"%s\"", cmdl);
114*433d6423SLionel Sambuc 	ret = system(cmdl);
115*433d6423SLionel Sambuc 
116*433d6423SLionel Sambuc 	if (ret != 0) {
117*433d6423SLionel Sambuc 		return EINVAL;
118*433d6423SLionel Sambuc 	}
119*433d6423SLionel Sambuc 
120*433d6423SLionel Sambuc 	return 0;
121*433d6423SLionel Sambuc }
122*433d6423SLionel Sambuc 
123*433d6423SLionel Sambuc 
124*433d6423SLionel Sambuc /*===========================================================================*
125*433d6423SLionel Sambuc  *             run_downscript                                                *
126*433d6423SLionel Sambuc  *===========================================================================*/
127*433d6423SLionel Sambuc int run_downscript(struct devmand_driver_instance *inst)
128*433d6423SLionel Sambuc {
129*433d6423SLionel Sambuc 	char cmdl[1024];
130*433d6423SLionel Sambuc 	cmdl[0] = 0;
131*433d6423SLionel Sambuc 	int ret;
132*433d6423SLionel Sambuc 
133*433d6423SLionel Sambuc 	snprintf(cmdl, 1024, "%s down %s %d",
134*433d6423SLionel Sambuc 	    inst->drv->downscript, inst->label, inst->major);
135*433d6423SLionel Sambuc 
136*433d6423SLionel Sambuc 	dbg("Running Upscript:  \"%s\"", cmdl);
137*433d6423SLionel Sambuc 
138*433d6423SLionel Sambuc 	ret = system(cmdl);
139*433d6423SLionel Sambuc 
140*433d6423SLionel Sambuc 	if (ret != 0) {
141*433d6423SLionel Sambuc 		return EINVAL;
142*433d6423SLionel Sambuc 	}
143*433d6423SLionel Sambuc 
144*433d6423SLionel Sambuc 	return 0;
145*433d6423SLionel Sambuc }
146*433d6423SLionel Sambuc 
147*433d6423SLionel Sambuc 
148*433d6423SLionel Sambuc /*===========================================================================*
149*433d6423SLionel Sambuc  *             stop_driver                                                   *
150*433d6423SLionel Sambuc  *===========================================================================*/
151*433d6423SLionel Sambuc int stop_driver(struct devmand_driver_instance *inst)
152*433d6423SLionel Sambuc {
153*433d6423SLionel Sambuc 	char cmdl[1024];
154*433d6423SLionel Sambuc 	cmdl[0] = 0;
155*433d6423SLionel Sambuc 	int ret;
156*433d6423SLionel Sambuc 
157*433d6423SLionel Sambuc 	snprintf(cmdl, 1024, "%s down %s %d",
158*433d6423SLionel Sambuc 	    SERVICE_BINARY, inst->label, inst->dev_id);
159*433d6423SLionel Sambuc 	dbg("executing service: \"%s\"", cmdl);
160*433d6423SLionel Sambuc 	ret = system(cmdl);
161*433d6423SLionel Sambuc 	if (ret != 0)
162*433d6423SLionel Sambuc 	{
163*433d6423SLionel Sambuc 		return EINVAL;
164*433d6423SLionel Sambuc 	}
165*433d6423SLionel Sambuc 	printf("Stopped driver %s with label %s for device %d.\n",
166*433d6423SLionel Sambuc 		inst->drv->binary, inst->label, inst->dev_id);
167*433d6423SLionel Sambuc 
168*433d6423SLionel Sambuc 	return 0;
169*433d6423SLionel Sambuc }
170*433d6423SLionel Sambuc 
171*433d6423SLionel Sambuc 
172*433d6423SLionel Sambuc /*===========================================================================*
173*433d6423SLionel Sambuc  *             start_driver                                                  *
174*433d6423SLionel Sambuc  *===========================================================================*/
175*433d6423SLionel Sambuc int start_driver(struct devmand_driver_instance *inst)
176*433d6423SLionel Sambuc {
177*433d6423SLionel Sambuc 	char cmdl[1024];
178*433d6423SLionel Sambuc 	cmdl[0] = 0;
179*433d6423SLionel Sambuc 	int ret;
180*433d6423SLionel Sambuc 
181*433d6423SLionel Sambuc 	/* generate label */
182*433d6423SLionel Sambuc 	ret = snprintf(inst->label, 32,  "%s%d", inst->drv->devprefix,
183*433d6423SLionel Sambuc 		inst->dev_id);
184*433d6423SLionel Sambuc 	if (ret < 0 || ret > DEVMAND_DRIVER_LABEL_LEN) {
185*433d6423SLionel Sambuc 		dbg("label too long");
186*433d6423SLionel Sambuc 		return ENOMEM;
187*433d6423SLionel Sambuc 	}
188*433d6423SLionel Sambuc 
189*433d6423SLionel Sambuc 	snprintf(cmdl, 1024, "%s up %s  -major %d -devid %d -label %s",
190*433d6423SLionel Sambuc 	    SERVICE_BINARY, inst->drv->binary, inst->major, inst->dev_id,
191*433d6423SLionel Sambuc 		inst->label);
192*433d6423SLionel Sambuc 	dbg("executing service: \"%s\"", cmdl);
193*433d6423SLionel Sambuc 
194*433d6423SLionel Sambuc 	ret = system(cmdl);
195*433d6423SLionel Sambuc 
196*433d6423SLionel Sambuc 	if (ret != 0) {
197*433d6423SLionel Sambuc 		return EINVAL;
198*433d6423SLionel Sambuc 	}
199*433d6423SLionel Sambuc 
200*433d6423SLionel Sambuc 	printf("Started driver %s with label %s for device %d.\n",
201*433d6423SLionel Sambuc 		inst->drv->binary, inst->label, inst->dev_id);
202*433d6423SLionel Sambuc 
203*433d6423SLionel Sambuc 	return 0;
204*433d6423SLionel Sambuc }
205*433d6423SLionel Sambuc 
206*433d6423SLionel Sambuc /*===========================================================================*
207*433d6423SLionel Sambuc  *             find_instance                                                 *
208*433d6423SLionel Sambuc  *===========================================================================*/
209*433d6423SLionel Sambuc static struct devmand_driver_instance *
210*433d6423SLionel Sambuc find_instance(int dev_id)
211*433d6423SLionel Sambuc {
212*433d6423SLionel Sambuc 	struct devmand_driver_instance *inst;
213*433d6423SLionel Sambuc 
214*433d6423SLionel Sambuc 	LIST_FOREACH(inst, &instances, list) {
215*433d6423SLionel Sambuc 		if (inst->dev_id == dev_id) {
216*433d6423SLionel Sambuc 			return inst;
217*433d6423SLionel Sambuc 		}
218*433d6423SLionel Sambuc 	}
219*433d6423SLionel Sambuc 	return NULL;
220*433d6423SLionel Sambuc }
221*433d6423SLionel Sambuc 
222*433d6423SLionel Sambuc /*===========================================================================*
223*433d6423SLionel Sambuc  *              match_usb_driver                                             *
224*433d6423SLionel Sambuc  *===========================================================================*/
225*433d6423SLionel Sambuc static int
226*433d6423SLionel Sambuc match_usb_id(struct devmand_usb_match_id *mid, struct usb_device_id *id)
227*433d6423SLionel Sambuc {
228*433d6423SLionel Sambuc 	int res = 1;
229*433d6423SLionel Sambuc 	unsigned long match = mid->match_flags;
230*433d6423SLionel Sambuc 	struct usb_device_id *_id = &mid->match_id;
231*433d6423SLionel Sambuc 
232*433d6423SLionel Sambuc 	if (match & USB_MATCH_ID_VENDOR)
233*433d6423SLionel Sambuc 		if (id->idVendor != _id->idVendor) res = 0;
234*433d6423SLionel Sambuc 	if (match & USB_MATCH_ID_PRODUCT)
235*433d6423SLionel Sambuc 		if (id->idProduct != _id->idProduct) res = 0;
236*433d6423SLionel Sambuc 	if (match & USB_MATCH_BCD_DEVICE)
237*433d6423SLionel Sambuc 		if (id->bcdDevice != _id->bcdDevice) res = 0;
238*433d6423SLionel Sambuc 	if (match & USB_MATCH_DEVICE_PROTOCOL)
239*433d6423SLionel Sambuc 		if (id->bDeviceProtocol != _id->bDeviceProtocol) res = 0;
240*433d6423SLionel Sambuc 	if (match & USB_MATCH_DEVICE_SUBCLASS)
241*433d6423SLionel Sambuc 		if (id->bDeviceSubClass != _id->bDeviceSubClass) res = 0;
242*433d6423SLionel Sambuc 	if (match & USB_MATCH_DEVICE_PROTOCOL)
243*433d6423SLionel Sambuc 		if (id->bDeviceProtocol != _id->bDeviceProtocol) res = 0;
244*433d6423SLionel Sambuc 	if (match & USB_MATCH_INTERFACE_CLASS)
245*433d6423SLionel Sambuc 		if (id->bInterfaceClass != _id->bInterfaceClass) res = 0;
246*433d6423SLionel Sambuc 	if (match & USB_MATCH_INTERFACE_SUBCLASS)
247*433d6423SLionel Sambuc 		if (id->bInterfaceSubClass != _id->bInterfaceSubClass) res = 0;
248*433d6423SLionel Sambuc 	if (match & USB_MATCH_INTERFACE_PROTOCOL)
249*433d6423SLionel Sambuc 		if (id->bInterfaceProtocol != _id->bInterfaceProtocol) res = 0;
250*433d6423SLionel Sambuc 
251*433d6423SLionel Sambuc 	if (match == 0UL) {
252*433d6423SLionel Sambuc 		res = 0;
253*433d6423SLionel Sambuc 	}
254*433d6423SLionel Sambuc 
255*433d6423SLionel Sambuc 	return res;
256*433d6423SLionel Sambuc }
257*433d6423SLionel Sambuc 
258*433d6423SLionel Sambuc /*===========================================================================*
259*433d6423SLionel Sambuc  *              match_usb_driver                                             *
260*433d6423SLionel Sambuc  *===========================================================================*/
261*433d6423SLionel Sambuc static struct devmand_usb_driver*
262*433d6423SLionel Sambuc match_usb_driver(struct usb_device_id *id)
263*433d6423SLionel Sambuc {
264*433d6423SLionel Sambuc 	struct devmand_usb_driver *driver;
265*433d6423SLionel Sambuc 	struct devmand_usb_match_id *mid;
266*433d6423SLionel Sambuc 
267*433d6423SLionel Sambuc 	LIST_FOREACH(driver, &drivers, list) {
268*433d6423SLionel Sambuc 		LIST_FOREACH(mid, &driver->ids, list) {
269*433d6423SLionel Sambuc 			if (match_usb_id(mid, id)) {
270*433d6423SLionel Sambuc 				return driver;
271*433d6423SLionel Sambuc 			}
272*433d6423SLionel Sambuc 		}
273*433d6423SLionel Sambuc 	}
274*433d6423SLionel Sambuc 	return NULL;
275*433d6423SLionel Sambuc }
276*433d6423SLionel Sambuc 
277*433d6423SLionel Sambuc /*===========================================================================*
278*433d6423SLionel Sambuc  *              add_usb_match_id                                             *
279*433d6423SLionel Sambuc  *===========================================================================*/
280*433d6423SLionel Sambuc struct devmand_usb_driver * add_usb_driver(char *name)
281*433d6423SLionel Sambuc {
282*433d6423SLionel Sambuc 	struct devmand_usb_driver *udrv = (struct devmand_usb_driver*)
283*433d6423SLionel Sambuc 	    malloc(sizeof(struct devmand_usb_driver));
284*433d6423SLionel Sambuc 
285*433d6423SLionel Sambuc 	LIST_INSERT_HEAD(&drivers, udrv, list);
286*433d6423SLionel Sambuc 	LIST_INIT(&udrv->ids);
287*433d6423SLionel Sambuc 
288*433d6423SLionel Sambuc 	udrv->name = name;
289*433d6423SLionel Sambuc 	return udrv;
290*433d6423SLionel Sambuc }
291*433d6423SLionel Sambuc 
292*433d6423SLionel Sambuc /*===========================================================================*
293*433d6423SLionel Sambuc  *              add_usb_match_id                                             *
294*433d6423SLionel Sambuc  *===========================================================================*/
295*433d6423SLionel Sambuc struct devmand_usb_match_id *
296*433d6423SLionel Sambuc add_usb_match_id
297*433d6423SLionel Sambuc (struct devmand_usb_driver *drv)
298*433d6423SLionel Sambuc {
299*433d6423SLionel Sambuc 	struct devmand_usb_match_id *id = (struct devmand_usb_match_id*)
300*433d6423SLionel Sambuc 	    malloc(sizeof(struct devmand_usb_match_id));
301*433d6423SLionel Sambuc 
302*433d6423SLionel Sambuc 	memset(id, 0, sizeof(struct devmand_usb_match_id));
303*433d6423SLionel Sambuc 
304*433d6423SLionel Sambuc 	LIST_INSERT_HEAD(&drv->ids, id, list);
305*433d6423SLionel Sambuc 
306*433d6423SLionel Sambuc 	return id;
307*433d6423SLionel Sambuc }
308*433d6423SLionel Sambuc 
309*433d6423SLionel Sambuc 
310*433d6423SLionel Sambuc /*===========================================================================*
311*433d6423SLionel Sambuc  *           parse_config                                                    *
312*433d6423SLionel Sambuc  *===========================================================================*/
313*433d6423SLionel Sambuc static void parse_config()
314*433d6423SLionel Sambuc {
315*433d6423SLionel Sambuc 	int i, status, error;
316*433d6423SLionel Sambuc 	struct stat stats;
317*433d6423SLionel Sambuc 	char * dirname;
318*433d6423SLionel Sambuc 
319*433d6423SLionel Sambuc 	DIR * dir;
320*433d6423SLionel Sambuc 	struct dirent entry;
321*433d6423SLionel Sambuc 	struct dirent *result;
322*433d6423SLionel Sambuc 	char config_file[PATH_MAX];
323*433d6423SLionel Sambuc 
324*433d6423SLionel Sambuc 	dbg("Parsing configuration directories... ");
325*433d6423SLionel Sambuc 	/* Next parse the configuration directories */
326*433d6423SLionel Sambuc 	for(i=0; i < args.config_dir_count; i++){
327*433d6423SLionel Sambuc 		dirname = args.config_dirs[i];
328*433d6423SLionel Sambuc 		dbg("Parsing config dir %s ", dirname);
329*433d6423SLionel Sambuc 		status = stat(dirname,&stats);
330*433d6423SLionel Sambuc 		if (status == -1){
331*433d6423SLionel Sambuc 			error = errno;
332*433d6423SLionel Sambuc 			dbg("Failed to read directory '%s':%s (skipping) \n",
333*433d6423SLionel Sambuc 			    dirname,strerror(error));
334*433d6423SLionel Sambuc 			continue;
335*433d6423SLionel Sambuc 		}
336*433d6423SLionel Sambuc 		if (!S_ISDIR(stats.st_mode)){
337*433d6423SLionel Sambuc 			dbg("Parse configuration skipping %s "
338*433d6423SLionel Sambuc 			    "(not a directory) \n",dirname);
339*433d6423SLionel Sambuc 			continue;
340*433d6423SLionel Sambuc 		}
341*433d6423SLionel Sambuc 		dir = opendir(dirname);
342*433d6423SLionel Sambuc 		if (dir == NULL){
343*433d6423SLionel Sambuc 			error = errno;
344*433d6423SLionel Sambuc 			dbg("Parse configuration failed to read dir '%s'"
345*433d6423SLionel Sambuc 			    "(skipping) :%s\n",dirname, strerror(error));
346*433d6423SLionel Sambuc 			continue;
347*433d6423SLionel Sambuc 		}
348*433d6423SLionel Sambuc 		while( (status = readdir_r(dir,&entry,&result)) == 0 ){
349*433d6423SLionel Sambuc 			if (result == NULL){ /* last entry */
350*433d6423SLionel Sambuc 				closedir(dir);
351*433d6423SLionel Sambuc 				break;
352*433d6423SLionel Sambuc 			}
353*433d6423SLionel Sambuc 
354*433d6423SLionel Sambuc 			/* concatenate dir and file name to open it */
355*433d6423SLionel Sambuc 			snprintf(config_file,PATH_MAX, "%s/%s",
356*433d6423SLionel Sambuc 				 dirname,entry.d_name);
357*433d6423SLionel Sambuc 			status = stat(config_file, &stats);
358*433d6423SLionel Sambuc 			if (status == -1){
359*433d6423SLionel Sambuc 				error = errno;
360*433d6423SLionel Sambuc 				dbg("Parse configuration Failed to stat file "
361*433d6423SLionel Sambuc 				    "'%s': %s (skipping)\n", config_file,
362*433d6423SLionel Sambuc 				    strerror(error));
363*433d6423SLionel Sambuc 			}
364*433d6423SLionel Sambuc 			if (S_ISREG(stats.st_mode)){
365*433d6423SLionel Sambuc 				dbg("Parsing file %s",config_file);
366*433d6423SLionel Sambuc 				yyin = fopen(config_file, "r");
367*433d6423SLionel Sambuc 
368*433d6423SLionel Sambuc 				if (yyin < 0) {
369*433d6423SLionel Sambuc 					dbg("Can not open config file:"
370*433d6423SLionel Sambuc 				 	       " %d.\n", errno);
371*433d6423SLionel Sambuc 				}
372*433d6423SLionel Sambuc 				yyparse();
373*433d6423SLionel Sambuc 				dbg("Done.");
374*433d6423SLionel Sambuc 				fclose(yyin);
375*433d6423SLionel Sambuc 			}
376*433d6423SLionel Sambuc 		}
377*433d6423SLionel Sambuc 	}
378*433d6423SLionel Sambuc 	dbg("Parsing configuration directories done... ");
379*433d6423SLionel Sambuc 
380*433d6423SLionel Sambuc }
381*433d6423SLionel Sambuc 
382*433d6423SLionel Sambuc /*===========================================================================*
383*433d6423SLionel Sambuc  *           cleanup                                                        *
384*433d6423SLionel Sambuc  *===========================================================================*/
385*433d6423SLionel Sambuc static void cleanup() {
386*433d6423SLionel Sambuc 	struct devmand_driver_instance *inst;
387*433d6423SLionel Sambuc 	/* destroy fifo */
388*433d6423SLionel Sambuc 	dbg("cleaning up... ");
389*433d6423SLionel Sambuc 	/* quit all running drivers */
390*433d6423SLionel Sambuc 	LIST_FOREACH(inst, &instances, list) {
391*433d6423SLionel Sambuc 		dbg("stopping driver %s", inst->label);
392*433d6423SLionel Sambuc 		run_downscript (inst);
393*433d6423SLionel Sambuc 		stop_driver(inst);
394*433d6423SLionel Sambuc 	}
395*433d6423SLionel Sambuc 	unlink("/var/run/devmand.pid");
396*433d6423SLionel Sambuc }
397*433d6423SLionel Sambuc 
398*433d6423SLionel Sambuc static void sig_int(int sig) {
399*433d6423SLionel Sambuc 	dbg("devman: Received SIGINT... cleaning up.");
400*433d6423SLionel Sambuc 	_run = 0;
401*433d6423SLionel Sambuc }
402*433d6423SLionel Sambuc 
403*433d6423SLionel Sambuc /*===========================================================================*
404*433d6423SLionel Sambuc  *           create_pid_file                                                 *
405*433d6423SLionel Sambuc  *===========================================================================*/
406*433d6423SLionel Sambuc void create_pid_file()
407*433d6423SLionel Sambuc {
408*433d6423SLionel Sambuc 	FILE *fd;
409*433d6423SLionel Sambuc 
410*433d6423SLionel Sambuc 	fd = fopen("/var/run/devmand.pid", "r");
411*433d6423SLionel Sambuc 	if(fd) {
412*433d6423SLionel Sambuc 		fprintf(stderr, "devmand: /var/run/devmand.pid exists... "
413*433d6423SLionel Sambuc 		                "another devmand running?\n");
414*433d6423SLionel Sambuc 		fclose(fd);
415*433d6423SLionel Sambuc 		exit(1);
416*433d6423SLionel Sambuc 	} else {
417*433d6423SLionel Sambuc 		fd = fopen("/var/run/devmand.pid","w");
418*433d6423SLionel Sambuc 		fprintf(fd, "%d", getpid());
419*433d6423SLionel Sambuc 		fclose(fd);
420*433d6423SLionel Sambuc 	}
421*433d6423SLionel Sambuc }
422*433d6423SLionel Sambuc 
423*433d6423SLionel Sambuc /*===========================================================================*
424*433d6423SLionel Sambuc  *           main                                                            *
425*433d6423SLionel Sambuc  *===========================================================================*/
426*433d6423SLionel Sambuc int main(int argc, char *argv[])
427*433d6423SLionel Sambuc {
428*433d6423SLionel Sambuc 	int opt, optindex;
429*433d6423SLionel Sambuc 	struct devmand_usb_driver *driver;
430*433d6423SLionel Sambuc 
431*433d6423SLionel Sambuc 
432*433d6423SLionel Sambuc 	/* get command line arguments */
433*433d6423SLionel Sambuc 	while ((opt = getopt_long(argc, argv, "d:p:vxh?", options, &optindex))
434*433d6423SLionel Sambuc 			!= -1) {
435*433d6423SLionel Sambuc 		switch (opt) {
436*433d6423SLionel Sambuc 			case 'd':/* config directory */
437*433d6423SLionel Sambuc 				if (args.config_dir_count >= MAX_CONFIG_DIRS){
438*433d6423SLionel Sambuc 				 	fprintf(stderr,"Parse arguments: Maximum"
439*433d6423SLionel Sambuc 					        " of %i configuration directories"
440*433d6423SLionel Sambuc 						" reached skipping directory '%s'\n"
441*433d6423SLionel Sambuc 						, MAX_CONFIG_DIRS, optarg);
442*433d6423SLionel Sambuc 				 	break;
443*433d6423SLionel Sambuc 				}
444*433d6423SLionel Sambuc 				args.config_dirs[args.config_dir_count] = optarg;
445*433d6423SLionel Sambuc 				args.config_dir_count++;
446*433d6423SLionel Sambuc 				break;
447*433d6423SLionel Sambuc 			case 'p': /* sysfs path */
448*433d6423SLionel Sambuc 				args.path = optarg;
449*433d6423SLionel Sambuc 				break;
450*433d6423SLionel Sambuc 			case 'v': /* verbose */
451*433d6423SLionel Sambuc 				args.verbose = 1;
452*433d6423SLionel Sambuc 				break;
453*433d6423SLionel Sambuc 			case 'x': /* check config */
454*433d6423SLionel Sambuc 				args.check_config = 1;
455*433d6423SLionel Sambuc 				break;
456*433d6423SLionel Sambuc 			case 'h': /* help */
457*433d6423SLionel Sambuc 			case '?': /* help */
458*433d6423SLionel Sambuc 			default:
459*433d6423SLionel Sambuc 				display_usage(argv[0]);
460*433d6423SLionel Sambuc 				return 0;
461*433d6423SLionel Sambuc 		}
462*433d6423SLionel Sambuc 	}
463*433d6423SLionel Sambuc 
464*433d6423SLionel Sambuc 
465*433d6423SLionel Sambuc 	/* is path set? */
466*433d6423SLionel Sambuc 	if (args.path == NULL) {
467*433d6423SLionel Sambuc 		args.path = "/sys/";
468*433d6423SLionel Sambuc 	}
469*433d6423SLionel Sambuc 
470*433d6423SLionel Sambuc 	/* is the configuration directory set? */
471*433d6423SLionel Sambuc 	if (args.config_dir_count == 0) {
472*433d6423SLionel Sambuc 		dbg("Using default configuration directory");
473*433d6423SLionel Sambuc 		args.config_dirs[0] = "/etc/devmand";
474*433d6423SLionel Sambuc 		args.config_dir_count = 1;
475*433d6423SLionel Sambuc 	}
476*433d6423SLionel Sambuc 
477*433d6423SLionel Sambuc 	/* If we only check the configuration run and exit imediately */
478*433d6423SLionel Sambuc 	if (args.check_config == 1){
479*433d6423SLionel Sambuc 		fprintf(stdout, "Only parsing configuration\n");
480*433d6423SLionel Sambuc 		parse_config();
481*433d6423SLionel Sambuc 		exit(0);
482*433d6423SLionel Sambuc 	}
483*433d6423SLionel Sambuc 
484*433d6423SLionel Sambuc 	create_pid_file();
485*433d6423SLionel Sambuc 
486*433d6423SLionel Sambuc 	parse_config();
487*433d6423SLionel Sambuc 	LIST_FOREACH(driver, &drivers, list) {
488*433d6423SLionel Sambuc 		run_cleanscript(driver);
489*433d6423SLionel Sambuc 	}
490*433d6423SLionel Sambuc 
491*433d6423SLionel Sambuc 	signal(SIGINT, sig_int);
492*433d6423SLionel Sambuc 
493*433d6423SLionel Sambuc 	main_loop();
494*433d6423SLionel Sambuc 
495*433d6423SLionel Sambuc 	cleanup();
496*433d6423SLionel Sambuc 
497*433d6423SLionel Sambuc 	return 0;
498*433d6423SLionel Sambuc }
499*433d6423SLionel Sambuc 
500*433d6423SLionel Sambuc /*===========================================================================*
501*433d6423SLionel Sambuc  *           determine_type                                                  *
502*433d6423SLionel Sambuc  *===========================================================================*/
503*433d6423SLionel Sambuc static enum dev_type determine_type (char *path)
504*433d6423SLionel Sambuc {
505*433d6423SLionel Sambuc 	FILE * fd;
506*433d6423SLionel Sambuc 	char *mypath;
507*433d6423SLionel Sambuc 	char buf[256];
508*433d6423SLionel Sambuc 	int res;
509*433d6423SLionel Sambuc 
510*433d6423SLionel Sambuc 	mypath = (char *) calloc(1, strlen(path)+strlen(DEVMAN_TYPE_NAME)+1);
511*433d6423SLionel Sambuc 
512*433d6423SLionel Sambuc 	if (mypath == NULL) {
513*433d6423SLionel Sambuc 		fprintf(stderr, "ERROR: out of mem\n");
514*433d6423SLionel Sambuc 		cleanup();
515*433d6423SLionel Sambuc 		exit(1);
516*433d6423SLionel Sambuc 	}
517*433d6423SLionel Sambuc 
518*433d6423SLionel Sambuc 	strcat(mypath, path);
519*433d6423SLionel Sambuc 	strcat(mypath, DEVMAN_TYPE_NAME);
520*433d6423SLionel Sambuc 
521*433d6423SLionel Sambuc 	fd = fopen(mypath, "r");
522*433d6423SLionel Sambuc 	free(mypath);
523*433d6423SLionel Sambuc 
524*433d6423SLionel Sambuc 	if (fd == NULL) {
525*433d6423SLionel Sambuc 		fprintf(stderr, "WARN: could not open %s\n", mypath);
526*433d6423SLionel Sambuc 		return DEV_TYPE_UNKOWN;
527*433d6423SLionel Sambuc 	}
528*433d6423SLionel Sambuc 
529*433d6423SLionel Sambuc 	res = fscanf(fd , "%s\n", buf);
530*433d6423SLionel Sambuc 	fclose(fd);
531*433d6423SLionel Sambuc 
532*433d6423SLionel Sambuc 	if (res != 1) {
533*433d6423SLionel Sambuc 		fprintf(stderr, "WARN: could not parse %s\n", mypath);
534*433d6423SLionel Sambuc 		return DEV_TYPE_UNKOWN;
535*433d6423SLionel Sambuc 	}
536*433d6423SLionel Sambuc 
537*433d6423SLionel Sambuc 	if (strcmp(buf, "USB_DEV") == 0) {
538*433d6423SLionel Sambuc 		return DEV_TYPE_USB_DEVICE;
539*433d6423SLionel Sambuc 	} else if (strcmp(buf, "USB_INTF") == 0) {
540*433d6423SLionel Sambuc 		return DEV_TYPE_USB_INTF;
541*433d6423SLionel Sambuc 	}
542*433d6423SLionel Sambuc 
543*433d6423SLionel Sambuc 	return  DEV_TYPE_UNKOWN;
544*433d6423SLionel Sambuc }
545*433d6423SLionel Sambuc 
546*433d6423SLionel Sambuc /*===========================================================================*
547*433d6423SLionel Sambuc  *           read_hex_uint                                                   *
548*433d6423SLionel Sambuc  *===========================================================================*/
549*433d6423SLionel Sambuc static int read_hex_uint(char *base_path, char *name, unsigned int* val )
550*433d6423SLionel Sambuc {
551*433d6423SLionel Sambuc 	char my_path[PATH_LEN];
552*433d6423SLionel Sambuc 	FILE *fd;
553*433d6423SLionel Sambuc 	memset(my_path,0,PATH_LEN);
554*433d6423SLionel Sambuc 	int ret = 0;
555*433d6423SLionel Sambuc 
556*433d6423SLionel Sambuc 	strcat(my_path, base_path);
557*433d6423SLionel Sambuc 	strcat(my_path, name);
558*433d6423SLionel Sambuc 
559*433d6423SLionel Sambuc 	fd = fopen(my_path, "r");
560*433d6423SLionel Sambuc 
561*433d6423SLionel Sambuc 	if (fd == NULL) {
562*433d6423SLionel Sambuc 		fprintf(stderr, "WARN: could not open %s\n", my_path);
563*433d6423SLionel Sambuc 		return EEXIST;
564*433d6423SLionel Sambuc 	} else	if (fscanf(fd, "0x%x\n", val ) != 1) {
565*433d6423SLionel Sambuc 		fprintf(stderr, "WARN: could not parse %s\n", my_path);
566*433d6423SLionel Sambuc 		ret = EINVAL;
567*433d6423SLionel Sambuc 	}
568*433d6423SLionel Sambuc 	fclose(fd);
569*433d6423SLionel Sambuc 
570*433d6423SLionel Sambuc 	return ret;
571*433d6423SLionel Sambuc }
572*433d6423SLionel Sambuc 
573*433d6423SLionel Sambuc /*===========================================================================*
574*433d6423SLionel Sambuc  *               get_major                                                   *
575*433d6423SLionel Sambuc  *===========================================================================*/
576*433d6423SLionel Sambuc static int get_major() {
577*433d6423SLionel Sambuc 	int i, ret = args.major_offset;
578*433d6423SLionel Sambuc 
579*433d6423SLionel Sambuc 	for (i=0; i < 16; i++) {
580*433d6423SLionel Sambuc 		int j;
581*433d6423SLionel Sambuc 		for (j = 0; j < 8; j++ ) {
582*433d6423SLionel Sambuc 			if ((major_bitmap[i] & (1 << j))) {
583*433d6423SLionel Sambuc 				major_bitmap[i] &= !(1 << j);
584*433d6423SLionel Sambuc 				return ret;
585*433d6423SLionel Sambuc 			}
586*433d6423SLionel Sambuc 			ret++;
587*433d6423SLionel Sambuc 		}
588*433d6423SLionel Sambuc 	}
589*433d6423SLionel Sambuc 	return INVAL_MAJOR;
590*433d6423SLionel Sambuc }
591*433d6423SLionel Sambuc 
592*433d6423SLionel Sambuc /*===========================================================================*
593*433d6423SLionel Sambuc  *               put_major                                                   *
594*433d6423SLionel Sambuc  *===========================================================================*/
595*433d6423SLionel Sambuc static void put_major(int major) {
596*433d6423SLionel Sambuc 	int i;
597*433d6423SLionel Sambuc 	major -= args.major_offset;
598*433d6423SLionel Sambuc 	assert(major >= 0);
599*433d6423SLionel Sambuc 
600*433d6423SLionel Sambuc 	for (i=0; i < 16; i++) {
601*433d6423SLionel Sambuc 		int j;
602*433d6423SLionel Sambuc 		for (j = 0; j < 8; j++ ) {
603*433d6423SLionel Sambuc 			if (major==0) {
604*433d6423SLionel Sambuc 				assert(!(major_bitmap[i] & (1 <<j)));
605*433d6423SLionel Sambuc 				major_bitmap[i] |= (1 << j);
606*433d6423SLionel Sambuc 				return;
607*433d6423SLionel Sambuc 			}
608*433d6423SLionel Sambuc 			major--;
609*433d6423SLionel Sambuc 		}
610*433d6423SLionel Sambuc 	}
611*433d6423SLionel Sambuc }
612*433d6423SLionel Sambuc 
613*433d6423SLionel Sambuc /*===========================================================================*
614*433d6423SLionel Sambuc  *          generate_usb_device_id                                           *
615*433d6423SLionel Sambuc  *===========================================================================*/
616*433d6423SLionel Sambuc static struct usb_device_id *
617*433d6423SLionel Sambuc generate_usb_device_id(char * path, int is_interface)
618*433d6423SLionel Sambuc {
619*433d6423SLionel Sambuc 	struct usb_device_id *ret;
620*433d6423SLionel Sambuc 	int res;
621*433d6423SLionel Sambuc 	unsigned int val;
622*433d6423SLionel Sambuc 
623*433d6423SLionel Sambuc 	ret = (struct usb_device_id *)
624*433d6423SLionel Sambuc 	    calloc(1,sizeof (struct usb_device_id));
625*433d6423SLionel Sambuc 
626*433d6423SLionel Sambuc 	if (is_interface) {
627*433d6423SLionel Sambuc 
628*433d6423SLionel Sambuc 		res = read_hex_uint(path, "../idVendor", &val);
629*433d6423SLionel Sambuc 		if (res) goto err;
630*433d6423SLionel Sambuc 		ret->idVendor = val;
631*433d6423SLionel Sambuc 
632*433d6423SLionel Sambuc 		res = read_hex_uint(path, "../idProduct", &val);
633*433d6423SLionel Sambuc 		if (res) goto err;
634*433d6423SLionel Sambuc 		ret->idProduct = val;
635*433d6423SLionel Sambuc #if 0
636*433d6423SLionel Sambuc 		res = read_hex_uint(path, "../bcdDevice", &val);
637*433d6423SLionel Sambuc 		if (res) goto err;
638*433d6423SLionel Sambuc 		ret->bcdDevice = val;
639*433d6423SLionel Sambuc #endif
640*433d6423SLionel Sambuc 		res = read_hex_uint(path, "../bDeviceClass", &val);
641*433d6423SLionel Sambuc 		if (res) goto err;
642*433d6423SLionel Sambuc 		ret->bDeviceClass = val;
643*433d6423SLionel Sambuc 
644*433d6423SLionel Sambuc 		res = read_hex_uint(path, "../bDeviceSubClass", &val);
645*433d6423SLionel Sambuc 		if (res) goto err;
646*433d6423SLionel Sambuc 		ret->bDeviceSubClass = val;
647*433d6423SLionel Sambuc 
648*433d6423SLionel Sambuc 		res = read_hex_uint(path, "../bDeviceProtocol", &val);
649*433d6423SLionel Sambuc 		if (res) goto err;
650*433d6423SLionel Sambuc 		ret->bDeviceProtocol = val;
651*433d6423SLionel Sambuc 
652*433d6423SLionel Sambuc 		res = read_hex_uint(path, "/bInterfaceClass", &val);
653*433d6423SLionel Sambuc 		if (res) goto err;
654*433d6423SLionel Sambuc 		ret->bInterfaceClass = val;
655*433d6423SLionel Sambuc 
656*433d6423SLionel Sambuc 		res = read_hex_uint(path, "/bInterfaceSubClass", &val);
657*433d6423SLionel Sambuc 		if (res) goto err;
658*433d6423SLionel Sambuc 		ret->bInterfaceSubClass = val;
659*433d6423SLionel Sambuc 
660*433d6423SLionel Sambuc 		res = read_hex_uint(path, "/bInterfaceProtocol", &val);
661*433d6423SLionel Sambuc 		if (res) goto err;
662*433d6423SLionel Sambuc 		ret->bInterfaceProtocol = val;
663*433d6423SLionel Sambuc 	}
664*433d6423SLionel Sambuc 
665*433d6423SLionel Sambuc 	return ret;
666*433d6423SLionel Sambuc 
667*433d6423SLionel Sambuc err:
668*433d6423SLionel Sambuc 	free(ret);
669*433d6423SLionel Sambuc 	return NULL;
670*433d6423SLionel Sambuc }
671*433d6423SLionel Sambuc 
672*433d6423SLionel Sambuc /*===========================================================================*
673*433d6423SLionel Sambuc  *            usb_intf_add_even                                              *
674*433d6423SLionel Sambuc  *===========================================================================*/
675*433d6423SLionel Sambuc static void usb_intf_add_event(char *path, int dev_id)
676*433d6423SLionel Sambuc {
677*433d6423SLionel Sambuc 	struct usb_device_id *id;
678*433d6423SLionel Sambuc 	struct devmand_usb_driver *drv;
679*433d6423SLionel Sambuc 	struct devmand_driver_instance *drv_inst;
680*433d6423SLionel Sambuc 	int major, ret;
681*433d6423SLionel Sambuc 
682*433d6423SLionel Sambuc 	/* generate usb_match_id */
683*433d6423SLionel Sambuc 	id = generate_usb_device_id(path,TRUE);
684*433d6423SLionel Sambuc 	if (id == NULL) {
685*433d6423SLionel Sambuc 		fprintf(stderr, "WARN: could not create usb_device id...\n"
686*433d6423SLionel Sambuc 		                "      ommiting event\n");
687*433d6423SLionel Sambuc 		free(id);
688*433d6423SLionel Sambuc 		return;
689*433d6423SLionel Sambuc 	}
690*433d6423SLionel Sambuc 
691*433d6423SLionel Sambuc 	/* find suitable driver */
692*433d6423SLionel Sambuc 	drv = match_usb_driver(id);
693*433d6423SLionel Sambuc 	free (id);
694*433d6423SLionel Sambuc 
695*433d6423SLionel Sambuc 	if (drv == NULL) {
696*433d6423SLionel Sambuc 		dbg("INFO: could not find a suitable driver for %s", path);
697*433d6423SLionel Sambuc 		return;
698*433d6423SLionel Sambuc 	}
699*433d6423SLionel Sambuc 
700*433d6423SLionel Sambuc 	/* create instance */
701*433d6423SLionel Sambuc 	drv_inst = (struct devmand_driver_instance *)
702*433d6423SLionel Sambuc 	    calloc(1,sizeof(struct devmand_driver_instance));
703*433d6423SLionel Sambuc 
704*433d6423SLionel Sambuc 	if (drv_inst == NULL) {
705*433d6423SLionel Sambuc 		fprintf(stderr, "ERROR: out of memory");
706*433d6423SLionel Sambuc 		return; /* maybe better quit here. */
707*433d6423SLionel Sambuc 	}
708*433d6423SLionel Sambuc 
709*433d6423SLionel Sambuc 
710*433d6423SLionel Sambuc 	/* allocate inode number, if device files needed */
711*433d6423SLionel Sambuc 	major = get_major();
712*433d6423SLionel Sambuc 	if (major == INVAL_MAJOR) {
713*433d6423SLionel Sambuc 		fprintf(stderr, "WARN: ran out of major numbers\n"
714*433d6423SLionel Sambuc 		                "      cannot start driver %s for %s\n",
715*433d6423SLionel Sambuc 							   drv->name, path);
716*433d6423SLionel Sambuc 		return;
717*433d6423SLionel Sambuc 	}
718*433d6423SLionel Sambuc 
719*433d6423SLionel Sambuc 	drv_inst->major  = major;
720*433d6423SLionel Sambuc 	drv_inst->drv    = drv;
721*433d6423SLionel Sambuc 	drv_inst->dev_id = dev_id;
722*433d6423SLionel Sambuc 
723*433d6423SLionel Sambuc 
724*433d6423SLionel Sambuc 	/* start driver (invoke service) */
725*433d6423SLionel Sambuc 	start_driver(drv_inst);
726*433d6423SLionel Sambuc 
727*433d6423SLionel Sambuc 	/*
728*433d6423SLionel Sambuc 	 * run the up action
729*433d6423SLionel Sambuc 	 *
730*433d6423SLionel Sambuc 	 * An up action can be any executable. Before running it devmand
731*433d6423SLionel Sambuc 	 * will set certain environment variables so the script can configure
732*433d6423SLionel Sambuc 	 * the device (or generate device files, etc). See up_action() for that.
733*433d6423SLionel Sambuc 	 */
734*433d6423SLionel Sambuc 	if (drv->upscript) {
735*433d6423SLionel Sambuc 		ret = run_upscript(drv_inst);
736*433d6423SLionel Sambuc 		if (ret) {
737*433d6423SLionel Sambuc 			stop_driver(drv_inst);
738*433d6423SLionel Sambuc 			fprintf(stderr, "devmand: warning, could not run up_action\n");
739*433d6423SLionel Sambuc 			free(drv_inst);
740*433d6423SLionel Sambuc 			return;
741*433d6423SLionel Sambuc 		}
742*433d6423SLionel Sambuc 	}
743*433d6423SLionel Sambuc 
744*433d6423SLionel Sambuc 	LIST_INSERT_HEAD(&instances,drv_inst,list);
745*433d6423SLionel Sambuc }
746*433d6423SLionel Sambuc 
747*433d6423SLionel Sambuc /*===========================================================================*
748*433d6423SLionel Sambuc  *            usb_intf_remove_event                                          *
749*433d6423SLionel Sambuc  *===========================================================================*/
750*433d6423SLionel Sambuc static void usb_intf_remove_event(char *path, int dev_id)
751*433d6423SLionel Sambuc {
752*433d6423SLionel Sambuc 	struct devmand_driver_instance *inst;
753*433d6423SLionel Sambuc 	struct devmand_usb_driver *drv;
754*433d6423SLionel Sambuc 	int ret;
755*433d6423SLionel Sambuc 
756*433d6423SLionel Sambuc 	/* find the driver instance */
757*433d6423SLionel Sambuc 	inst = find_instance(dev_id);
758*433d6423SLionel Sambuc 
759*433d6423SLionel Sambuc 	if (inst == NULL) {
760*433d6423SLionel Sambuc 		dbg("No driver running for id: %d", dev_id);
761*433d6423SLionel Sambuc 		return;
762*433d6423SLionel Sambuc 	}
763*433d6423SLionel Sambuc 	drv = inst->drv;
764*433d6423SLionel Sambuc 
765*433d6423SLionel Sambuc 	/* run the down script */
766*433d6423SLionel Sambuc 	if (drv->downscript) {
767*433d6423SLionel Sambuc 		ret = run_downscript(inst);
768*433d6423SLionel Sambuc 		if (ret) {
769*433d6423SLionel Sambuc 			fprintf(stderr, "WARN: error running up_action");
770*433d6423SLionel Sambuc 		}
771*433d6423SLionel Sambuc 	}
772*433d6423SLionel Sambuc 
773*433d6423SLionel Sambuc 	/* stop the driver */
774*433d6423SLionel Sambuc 	stop_driver(inst);
775*433d6423SLionel Sambuc 
776*433d6423SLionel Sambuc 	/* free major */
777*433d6423SLionel Sambuc 	put_major(inst->major);
778*433d6423SLionel Sambuc 
779*433d6423SLionel Sambuc 	/* free instance */
780*433d6423SLionel Sambuc 	LIST_REMOVE(inst,list);
781*433d6423SLionel Sambuc 	free(inst);
782*433d6423SLionel Sambuc }
783*433d6423SLionel Sambuc 
784*433d6423SLionel Sambuc /*===========================================================================*
785*433d6423SLionel Sambuc  *           handle_event                                                    *
786*433d6423SLionel Sambuc  *===========================================================================*/
787*433d6423SLionel Sambuc static void handle_event(char *event)
788*433d6423SLionel Sambuc {
789*433d6423SLionel Sambuc 	enum dev_type type;
790*433d6423SLionel Sambuc 	char path[PATH_LEN];
791*433d6423SLionel Sambuc 	char tmp_path[PATH_LEN];
792*433d6423SLionel Sambuc 	int dev_id, res;
793*433d6423SLionel Sambuc 
794*433d6423SLionel Sambuc 	path[0]=0;
795*433d6423SLionel Sambuc 
796*433d6423SLionel Sambuc 	if (strncmp("ADD ", event, 4) == 0) {
797*433d6423SLionel Sambuc 
798*433d6423SLionel Sambuc 		/* read data from event */
799*433d6423SLionel Sambuc 		res = sscanf(event, "ADD %s 0x%x", tmp_path, &dev_id);
800*433d6423SLionel Sambuc 
801*433d6423SLionel Sambuc 		if (res != 2) {
802*433d6423SLionel Sambuc 			fprintf(stderr, "WARN: could not parse event: %s", event);
803*433d6423SLionel Sambuc 			fprintf(stderr, "WARN: omitting event: %s", event);
804*433d6423SLionel Sambuc 		}
805*433d6423SLionel Sambuc 
806*433d6423SLionel Sambuc 		strcpy(path, args.path);
807*433d6423SLionel Sambuc 		strcat(path, tmp_path);
808*433d6423SLionel Sambuc 
809*433d6423SLionel Sambuc 		/* what kind of device is added? */
810*433d6423SLionel Sambuc 		type = determine_type(path);
811*433d6423SLionel Sambuc 
812*433d6423SLionel Sambuc 		switch (type) {
813*433d6423SLionel Sambuc 			case DEV_TYPE_USB_DEVICE:
814*433d6423SLionel Sambuc 				dbg("USB device added: ommited....");
815*433d6423SLionel Sambuc 				/* ommit usb devices for now */
816*433d6423SLionel Sambuc 				break;
817*433d6423SLionel Sambuc 			case DEV_TYPE_USB_INTF:
818*433d6423SLionel Sambuc 				dbg("USB interface added: (%s, devid: = %d)",path, dev_id);
819*433d6423SLionel Sambuc 				usb_intf_add_event(path, dev_id);
820*433d6423SLionel Sambuc 				return;
821*433d6423SLionel Sambuc 			default:
822*433d6423SLionel Sambuc 				dbg("default");
823*433d6423SLionel Sambuc 				fprintf(stderr, "WARN: ommiting event\n");
824*433d6423SLionel Sambuc 		}
825*433d6423SLionel Sambuc 	} else if (strncmp("REMOVE ", event, 7) == 0) {
826*433d6423SLionel Sambuc 
827*433d6423SLionel Sambuc 		/* read data from event */
828*433d6423SLionel Sambuc 		res = sscanf(event,"REMOVE %s 0x%x", tmp_path, &dev_id);
829*433d6423SLionel Sambuc 
830*433d6423SLionel Sambuc 		if (res != 2) {
831*433d6423SLionel Sambuc 			fprintf(stderr, "WARN: could not parse event: %s", event);
832*433d6423SLionel Sambuc 			fprintf(stderr, "WARN: omitting event: %s", event);
833*433d6423SLionel Sambuc 		}
834*433d6423SLionel Sambuc 
835*433d6423SLionel Sambuc 		usb_intf_remove_event(path, dev_id);
836*433d6423SLionel Sambuc 
837*433d6423SLionel Sambuc #if 0
838*433d6423SLionel Sambuc 		strcpy(path, args.path);
839*433d6423SLionel Sambuc 		strcat(path, tmp_path);
840*433d6423SLionel Sambuc 
841*433d6423SLionel Sambuc 		/* what kind of device is added? */
842*433d6423SLionel Sambuc 		type = determine_type(path);
843*433d6423SLionel Sambuc 
844*433d6423SLionel Sambuc 		switch (type) {
845*433d6423SLionel Sambuc 			case DEV_TYPE_USB_DEVICE:
846*433d6423SLionel Sambuc 				/* ommit usb devices for now */
847*433d6423SLionel Sambuc 				break;
848*433d6423SLionel Sambuc 			case DEV_TYPE_USB_INTF:
849*433d6423SLionel Sambuc 				usb_intf_remove_event(path, dev_id);
850*433d6423SLionel Sambuc 				return;
851*433d6423SLionel Sambuc 			default:
852*433d6423SLionel Sambuc 				fprintf(stderr, "WARN: ommiting event\n");
853*433d6423SLionel Sambuc 		}
854*433d6423SLionel Sambuc #endif
855*433d6423SLionel Sambuc 
856*433d6423SLionel Sambuc 	}
857*433d6423SLionel Sambuc }
858*433d6423SLionel Sambuc 
859*433d6423SLionel Sambuc /*===========================================================================*
860*433d6423SLionel Sambuc  *           main_loop                                                       *
861*433d6423SLionel Sambuc  *===========================================================================*/
862*433d6423SLionel Sambuc static void main_loop()
863*433d6423SLionel Sambuc {
864*433d6423SLionel Sambuc 	char ev_path[128];
865*433d6423SLionel Sambuc 	char buf[256];
866*433d6423SLionel Sambuc 	int len;
867*433d6423SLionel Sambuc 	FILE* fd;
868*433d6423SLionel Sambuc 	len = strlen(args.path);
869*433d6423SLionel Sambuc 
870*433d6423SLionel Sambuc 	/* init major numbers */
871*433d6423SLionel Sambuc 
872*433d6423SLionel Sambuc 	memset(&major_bitmap, 0xff, 16);
873*433d6423SLionel Sambuc 
874*433d6423SLionel Sambuc 	if (len > 128 - 7 /*len of "events" */) {
875*433d6423SLionel Sambuc 		fprintf(stderr, "pathname to long\n");
876*433d6423SLionel Sambuc 		cleanup();
877*433d6423SLionel Sambuc 		exit(1);
878*433d6423SLionel Sambuc 	}
879*433d6423SLionel Sambuc 
880*433d6423SLionel Sambuc 	strcpy(ev_path, args.path);
881*433d6423SLionel Sambuc 	strcat(ev_path, "events");
882*433d6423SLionel Sambuc 
883*433d6423SLionel Sambuc 
884*433d6423SLionel Sambuc 	while (_run) {
885*433d6423SLionel Sambuc 
886*433d6423SLionel Sambuc 		char *res;
887*433d6423SLionel Sambuc 
888*433d6423SLionel Sambuc 		fd = fopen(ev_path, "r");
889*433d6423SLionel Sambuc 		if (fd == NULL) {
890*433d6423SLionel Sambuc 			/*
891*433d6423SLionel Sambuc 			 * ENFILE is a temporary failure, often caused by
892*433d6423SLionel Sambuc 			 * running the test set.  Don't die from that..
893*433d6423SLionel Sambuc 			 */
894*433d6423SLionel Sambuc 			if (errno == ENFILE) {
895*433d6423SLionel Sambuc 				usleep(50000);
896*433d6423SLionel Sambuc 				continue;
897*433d6423SLionel Sambuc 			}
898*433d6423SLionel Sambuc 
899*433d6423SLionel Sambuc 			fprintf(stderr,"devmand error: could not open event "
900*433d6423SLionel Sambuc 				"file %s bailing out\n", ev_path);
901*433d6423SLionel Sambuc 			cleanup();
902*433d6423SLionel Sambuc 			exit(1);
903*433d6423SLionel Sambuc 		}
904*433d6423SLionel Sambuc 
905*433d6423SLionel Sambuc 		res = fgets(buf, 256, fd);
906*433d6423SLionel Sambuc 		fclose(fd);
907*433d6423SLionel Sambuc 
908*433d6423SLionel Sambuc 		if (res == NULL) {
909*433d6423SLionel Sambuc 			usleep(50000);
910*433d6423SLionel Sambuc 			continue;
911*433d6423SLionel Sambuc 		}
912*433d6423SLionel Sambuc 		dbg("handle_event:  %s", buf);
913*433d6423SLionel Sambuc 		handle_event(buf);
914*433d6423SLionel Sambuc 	}
915*433d6423SLionel Sambuc }
916*433d6423SLionel Sambuc 
917*433d6423SLionel Sambuc /*===========================================================================*
918*433d6423SLionel Sambuc  *           display_usage                                                   *
919*433d6423SLionel Sambuc  *===========================================================================*/
920*433d6423SLionel Sambuc static void display_usage(const char *name)
921*433d6423SLionel Sambuc {
922*433d6423SLionel Sambuc 	printf("Usage: %s [{-p|--pathname} PATH_TO_SYS}"
923*433d6423SLionel Sambuc 	       " [{-d|--config-dir} CONFIG_DIR] [-v|--verbose]"
924*433d6423SLionel Sambuc 	       " [[x||--check-config]\n", name);
925*433d6423SLionel Sambuc }
926*433d6423SLionel Sambuc 
927