1 /*
2 * Generic IFD device layer
3 *
4 * Copyright (C) 2003 Olaf Kirch <okir@suse.de>
5 */
6
7 #include "internal.h"
8 #include <stdlib.h>
9 #include <string.h>
10
11 /*
12 * Open a device given the name
13 */
ifd_device_open(const char * name)14 ifd_device_t *ifd_device_open(const char *name)
15 {
16 if (name == NULL) {
17 ct_error("Null device");
18 return NULL;
19 }
20
21 if (!strncmp(name, "serial:", 7))
22 return ifd_open_serial(name + 7);
23 if (!strncmp(name, "usb:", 4))
24 return ifd_open_usb(name + 4);
25 if (!strncmp(name, "remote:", 7))
26 return ifd_open_remote(name + 7);
27 if (!strncmp(name, "pcmcia:", 7))
28 return ifd_open_pcmcia(name + 7);
29 if (!strncmp(name, "pcmcia_block:", 13))
30 return ifd_open_pcmcia_block(name + 13);
31
32 ct_error("Unknown device type \"%s\"", name);
33 return NULL;
34 }
35
36 /*
37 * Create a new device struct
38 * This is an internal function called by the different device
39 * type handlers (serial, usb, etc)
40 */
ifd_device_new(const char * name,struct ifd_device_ops * ops,size_t size)41 ifd_device_t *ifd_device_new(const char *name, struct ifd_device_ops * ops,
42 size_t size)
43 {
44 ifd_device_t *dev;
45
46 dev = (ifd_device_t *) calloc(1, size);
47 if (!dev) {
48 ct_error("out of memory");
49 return NULL;
50 }
51 dev->name = strdup(name);
52 dev->ops = ops;
53
54 return dev;
55 }
56
57 /*
58 * Destroy a device handle
59 */
ifd_device_free(ifd_device_t * dev)60 void ifd_device_free(ifd_device_t * dev)
61 {
62 if (dev->name)
63 free(dev->name);
64 memset(dev, 0, sizeof(*dev));
65 free(dev);
66 }
67
68 /*
69 * Miscellaneous device operations. These functions
70 * just do a consistency check on the handle, and route
71 * the call to the appropriate member function
72 */
ifd_device_type(ifd_device_t * dev)73 int ifd_device_type(ifd_device_t * dev)
74 {
75 return dev->type;
76 }
77
ifd_device_reset(ifd_device_t * dev)78 int ifd_device_reset(ifd_device_t * dev)
79 {
80 if (!dev || !dev->ops || !dev->ops->reset)
81 return IFD_ERROR_NOT_SUPPORTED;
82 return dev->ops->reset(dev);
83 }
84
ifd_device_set_hotplug(ifd_device_t * dev,int hotplug)85 void ifd_device_set_hotplug(ifd_device_t * dev, int hotplug)
86 {
87 if (hotplug)
88 dev->hotplug = 1;
89 }
90
ifd_device_set_parameters(ifd_device_t * dev,const ifd_device_params_t * parms)91 int ifd_device_set_parameters(ifd_device_t * dev,
92 const ifd_device_params_t * parms)
93 {
94 if (!dev || !dev->ops || !dev->ops->set_params)
95 return IFD_ERROR_NOT_SUPPORTED;
96 return dev->ops->set_params(dev, parms);
97 }
98
ifd_device_get_parameters(ifd_device_t * dev,ifd_device_params_t * parms)99 int ifd_device_get_parameters(ifd_device_t * dev, ifd_device_params_t * parms)
100 {
101 if (!dev || !dev->ops || !dev->ops->get_params)
102 return IFD_ERROR_NOT_SUPPORTED;
103 return dev->ops->get_params(dev, parms);
104 }
105
ifd_device_flush(ifd_device_t * dev)106 void ifd_device_flush(ifd_device_t * dev)
107 {
108 if (!dev || !dev->ops || !dev->ops->flush)
109 return;
110 dev->ops->flush(dev);
111 }
112
ifd_device_send_break(ifd_device_t * dev,unsigned int usec)113 void ifd_device_send_break(ifd_device_t * dev, unsigned int usec)
114 {
115 if (!dev || !dev->ops || !dev->ops->send_break)
116 return;
117 dev->ops->send_break(dev, usec);
118 }
119
ifd_device_send(ifd_device_t * dev,const unsigned char * data,size_t len)120 int ifd_device_send(ifd_device_t * dev, const unsigned char *data, size_t len)
121 {
122 if (!dev || !dev->ops || !dev->ops->send)
123 return IFD_ERROR_NOT_SUPPORTED;
124 return dev->ops->send(dev, data, len);
125 }
126
ifd_device_control(ifd_device_t * dev,void * cmsg,size_t len)127 int ifd_device_control(ifd_device_t * dev, void *cmsg, size_t len)
128 {
129 if (!dev || !dev->ops || !dev->ops->control)
130 return IFD_ERROR_NOT_SUPPORTED;
131 return dev->ops->control(dev, cmsg, len);
132 }
133
ifd_device_recv(ifd_device_t * dev,unsigned char * data,size_t len,long timeout)134 int ifd_device_recv(ifd_device_t * dev, unsigned char *data, size_t len,
135 long timeout)
136 {
137 if (timeout < 0)
138 timeout = dev->timeout;
139
140 if (!dev || !dev->ops || !dev->ops->recv)
141 return IFD_ERROR_NOT_SUPPORTED;
142 return dev->ops->recv(dev, data, len, timeout);
143 }
144
ifd_device_transceive(ifd_device_t * dev,const void * sbuf,size_t slen,void * rbuf,size_t rlen,long timeout)145 int ifd_device_transceive(ifd_device_t * dev, const void *sbuf, size_t slen,
146 void *rbuf, size_t rlen, long timeout)
147 {
148 int rc;
149
150 if (timeout < 0)
151 timeout = dev->timeout;
152
153 if (!dev || !dev->ops)
154 return -1;
155 if (dev->ops->transceive)
156 return dev->ops->transceive(dev,
157 sbuf, slen, rbuf, rlen, timeout);
158
159 /* Fall back to send/recv */
160 ifd_device_flush(dev);
161 if ((rc = ifd_device_send(dev, (const unsigned char *)sbuf, slen)) < 0)
162 return rc;
163 return ifd_device_recv(dev, (unsigned char *)rbuf, rlen, timeout);
164 }
165
ifd_device_poll_presence(ifd_device_t * dev,struct pollfd * pfd)166 int ifd_device_poll_presence(ifd_device_t * dev, struct pollfd *pfd)
167 {
168 if (!dev || !dev->ops || !dev->ops->poll_presence)
169 return 1;
170 return dev->ops->poll_presence(dev, pfd);
171 }
172
ifd_device_get_eventfd(ifd_device_t * dev,short * events)173 int ifd_device_get_eventfd(ifd_device_t * dev, short *events)
174 {
175 if (!dev || !dev->ops)
176 return -1;
177 if (!dev->ops->get_eventfd)
178 return -1;
179 return dev->ops->get_eventfd(dev, events);
180 }
181
ifd_device_close(ifd_device_t * dev)182 void ifd_device_close(ifd_device_t * dev)
183 {
184 if (!dev)
185 return;
186 if (dev->ops && dev->ops->close)
187 dev->ops->close(dev);
188 ifd_device_free(dev);
189 }
190
191 /*
192 * Device ID handling
193 */
ifd_device_id_parse(const char * str,ifd_devid_t * id)194 int ifd_device_id_parse(const char *str, ifd_devid_t * id)
195 {
196 unsigned int n;
197
198 id->type = IFD_DEVICE_TYPE_OTHER;
199
200 n = strcspn(str, ":");
201 if (str[n] == ':') {
202 if (!strncmp(str, "usb", n))
203 id->type = IFD_DEVICE_TYPE_USB;
204 else if (!strncmp(str, "pcmcia", n))
205 id->type = IFD_DEVICE_TYPE_PCMCIA;
206 else
207 return -1;
208 str += n + 1;
209 }
210
211 for (n = 0; *str && n < IFD_MAX_DEVID_PARTS; n++) {
212 id->val[n] = strtoul(str, (char **)&str, 16);
213 if (*str == '/')
214 str++;
215 }
216
217 if (*str || n == 0)
218 return -1;
219 id->num = n;
220 return 0;
221 }
222
ifd_device_id_match(const ifd_devid_t * match,const ifd_devid_t * id)223 int ifd_device_id_match(const ifd_devid_t * match, const ifd_devid_t * id)
224 {
225 if (id->type != match->type
226 || id->num < match->num
227 || memcmp(id->val, match->val, match->num * sizeof(id->val[0])))
228 return 0;
229 return 1;
230 }
231