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