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