1 /**
2  * @file
3  * Generic driver functions.
4  *
5  * Copyright (C) 2003, Olaf Kirch <okir@suse.de>
6  */
7 
8 #include "internal.h"
9 #include <stdlib.h>
10 #include <string.h>
11 
12 struct ifd_driver_info {
13 	struct ifd_driver_info *next;
14 
15 	ifd_driver_t driver;
16 
17 	unsigned int nids;
18 	ifd_devid_t *id;
19 };
20 
21 static struct ifd_driver_info *list;
22 
23 /*
24  * Find registered driver by name
25  */
find_by_name(const char * name,int create)26 static struct ifd_driver_info *find_by_name(const char *name, int create)
27 {
28 	struct ifd_driver_info *ip;
29 
30 	for (ip = list; ip; ip = ip->next) {
31 		if (!strcmp(ip->driver.name, name))
32 			return ip;
33 	}
34 
35 	if (!create)
36 		return NULL;
37 
38 	ip = (struct ifd_driver_info *)calloc(1, sizeof(*ip));
39 	if (!ip) {
40 		ct_error("out of memory");
41 		return NULL;
42 	}
43 	ip->driver.name = strdup(name);
44 	ip->next = list;
45 	list = ip;
46 
47 	return ip;
48 }
49 
50 /**
51  * Register a driver.
52  *
53  * @param name Driver name.
54  * @param ops Driver operations.
55  */
ifd_driver_register(const char * name,struct ifd_driver_ops * ops)56 void ifd_driver_register(const char *name, struct ifd_driver_ops *ops)
57 {
58 	struct ifd_driver_info *ip;
59 
60 	ip = find_by_name(name, 1);
61 	if (ip->driver.ops == NULL)
62 		ip->driver.ops = ops;
63 }
64 
65 /**
66  * Add a device ID to a driver.
67  *
68  * @param id Device ID.
69  * @param name Driver name.
70  *
71  * Device which support plug-and-play can be mapped to drivers based on the
72  * device ID. This function adds a device ID to a driver, so that the driver
73  * can be looked-up at device detection time. The driver doesn't have to be
74  * registered before calling this function.
75  *
76  * Device IDs start with the device type followed by a semi-colon and by a
77  * device type specific ID. The following device types are supported:
78  *
79  * @li USB usb:vendor_id/device_id
80  *
81  * @return Error code <0 if failure.
82  */
ifd_driver_add_id(const char * id,const char * name)83 int ifd_driver_add_id(const char *id, const char *name)
84 {
85 	struct ifd_driver_info *ip;
86 
87 	ifd_debug(3, "ifd_driver_add_id(%s, %s)", id, name);
88 	ip = find_by_name(name, 1);
89 	if (!ip)
90 		return -1;
91 
92 	ip->id = (ifd_devid_t *) realloc(ip->id,
93 					 (ip->nids + 1) * sizeof(ifd_devid_t));
94 	if (!ip->id) {
95 		ct_error("out of memory");
96 		return IFD_ERROR_NO_MEMORY;
97 	}
98 	if (ifd_device_id_parse(id, &ip->id[ip->nids]) >= 0)
99 		ip->nids++;
100 
101 	return 0;
102 }
103 
104 /**
105  * Get the driver name for a given device ID.
106  *
107  * @param id Device ID.
108  *
109  * @sa ifd_driver_add_id
110  * @return Driver name or NULL if no driver is found.
111  */
ifd_driver_for_id(ifd_devid_t * id)112 const char *ifd_driver_for_id(ifd_devid_t * id)
113 {
114 	struct ifd_driver_info *ip;
115 	unsigned int n;
116 
117 	for (ip = list; ip; ip = ip->next) {
118 		for (n = 0; n < ip->nids; n++) {
119 			if (ifd_device_id_match(&ip->id[n], id))
120 				return ip->driver.name;
121 		}
122 	}
123 
124 	return NULL;
125 }
126 
127 /**
128  * Lookup a driver by name.
129  *
130  * @param name Driver name.
131  *
132  * If the configuration parameter @a autoload is set, OpenCT will try to load
133  * an external module for the requested driver.
134  *
135  * @return Pointer the the driver structure, or NULL if no driver is found.
136  */
ifd_driver_get(const char * name)137 const ifd_driver_t *ifd_driver_get(const char *name)
138 {
139 	struct ifd_driver_info *ip;
140 	int retries = 2;
141 
142 	while (retries--) {
143 		ip = find_by_name(name, ct_config.autoload);
144 		if (ip == NULL)
145 			break;
146 		if (ip->driver.ops != NULL)
147 			return &ip->driver;
148 		if (!ct_config.autoload || ifd_load_module("driver", name) < 0)
149 			break;
150 	}
151 
152 	return NULL;
153 }
154 
155 /**
156  * Get a list of registered drivers.
157  *
158  * @param names Name array.
159  * @param max Size of the name array.
160  *
161  * This function fills the array pointed by @a names with pointers to the
162  * driver names. At most @a max entries are returned. The names must @b not
163  * be freed by the caller.
164  *
165  * @return Number of driver names.
166  */
ifd_drivers_list(const char ** names,size_t max)167 unsigned int ifd_drivers_list(const char **names, size_t max)
168 {
169 	struct ifd_driver_info *ip;
170 	unsigned int n;
171 
172 	for (ip = list, n = 0; ip && n < max; ip = ip->next, n++) {
173 		names[n] = ip->driver.name;
174 	}
175 	return n;
176 }
177