Implement connectionless management client
[bcusdk.git] / eibd / backend / usbif.cpp
blob29091f09c2d078f33e6d5edf2b70284ea3ea9452
1 /*
2 EIBD eib bus access and management daemon
3 Copyright (C) 2005-2009 Martin Koegler <mkoegler@auto.tuwien.ac.at>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <ctype.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include "usbif.h"
27 #include "usb.h"
29 USBEndpoint
30 parseUSBEndpoint (const char *addr)
32 USBEndpoint e;
33 e.bus = -1;
34 e.device = -1;
35 e.config = -1;
36 e.altsetting = -1;
37 e.interface = -1;
38 if (!*addr)
39 return e;
40 if (!isdigit (*addr))
41 return e;
42 e.bus = atoi (addr);
43 while (isdigit (*addr))
44 addr++;
45 if (*addr != ':')
46 return e;
47 addr++;
48 if (!isdigit (*addr))
49 return e;
50 e.device = atoi (addr);
51 while (isdigit (*addr))
52 addr++;
53 if (*addr != ':')
54 return e;
55 addr++;
56 if (!isdigit (*addr))
57 return e;
58 e.config = atoi (addr);
59 while (isdigit (*addr))
60 addr++;
61 if (*addr != ':')
62 return e;
63 addr++;
64 if (!isdigit (*addr))
65 return e;
66 e.altsetting = atoi (addr);
67 if (*addr != ':')
68 return e;
69 addr++;
70 if (!isdigit (*addr))
71 return e;
72 e.interface = atoi (addr);
73 return e;
76 bool
77 check_device (libusb_device * dev, USBEndpoint e, USBDevice & e2)
79 struct libusb_device_descriptor desc;
80 struct libusb_config_descriptor *cfg;
81 const struct libusb_interface *intf;
82 const struct libusb_interface_descriptor *alts;
83 const struct libusb_endpoint_descriptor *ep;
84 libusb_device_handle *h;
85 int j, k, l, m;
86 int in, out;
88 if (!dev)
89 return false;
91 if (libusb_get_bus_number (dev) != e.bus && e.bus != -1)
92 return false;
93 if (libusb_get_device_address (dev) != e.device && e.device != -1)
94 return false;
96 if (libusb_get_device_descriptor (dev, &desc))
97 return false;
99 for (j = 0; j < desc.bNumConfigurations; j++)
101 if (libusb_get_config_descriptor (dev, j, &cfg))
102 continue;
103 if (cfg->bConfigurationValue != e.config && e.config != -1)
105 libusb_free_config_descriptor (cfg);
106 continue;
109 for (k = 0; k < cfg->bNumInterfaces; k++)
111 intf = &cfg->interface[k];
112 for (l = 0; l < intf->num_altsetting; l++)
114 alts = &intf->altsetting[l];
115 if (alts->bInterfaceClass != LIBUSB_CLASS_HID)
116 continue;
117 if (alts->bAlternateSetting != e.altsetting
118 && e.altsetting != -1)
119 continue;
120 if (alts->bInterfaceNumber != e.interface && e.interface != -1)
121 continue;
123 in = 0;
124 out = 0;
125 for (m = 0; m < alts->bNumEndpoints; m++)
127 ep = &alts->endpoint[m];
128 if (ep->wMaxPacketSize == 64)
130 if (ep->bEndpointAddress & LIBUSB_ENDPOINT_IN)
132 if ((ep->
133 bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) ==
134 LIBUSB_TRANSFER_TYPE_INTERRUPT)
135 in = ep->bEndpointAddress;
137 else
139 if ((ep->
140 bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) ==
141 LIBUSB_TRANSFER_TYPE_INTERRUPT)
142 out = ep->bEndpointAddress;
147 if (!in || !out)
148 continue;
149 if (!libusb_open (dev, &h))
151 USBDevice e1;
152 e1.dev = dev;
153 libusb_ref_device (dev);
154 e1.config = cfg->bConfigurationValue;
155 e1.interface = alts->bInterfaceNumber;
156 e1.altsetting = alts->bAlternateSetting;
157 e1.sendep = out;
158 e1.recvep = in;
159 libusb_close (h);
160 e2 = e1;
161 libusb_free_config_descriptor (cfg);
162 return true;
166 libusb_free_config_descriptor (cfg);
168 return false;
171 USBDevice
172 detectUSBEndpoint (USBEndpoint e)
174 libusb_device **devs;
175 int i, count;
176 USBDevice e2;
177 e2.dev = NULL;
178 count = libusb_get_device_list (NULL, &devs);
180 for (i = 0; i < count; i++)
181 if (check_device (devs[i], e, e2))
182 break;
184 libusb_free_device_list (devs, 1);
186 return e2;
189 USBLowLevelDriver::USBLowLevelDriver (const char *Dev, Trace * tr)
191 t = tr;
192 pth_sem_init (&in_signal);
193 pth_sem_init (&out_signal);
194 pth_sem_init (&send_empty);
195 pth_sem_set_value (&send_empty, 1);
196 getwait = pth_event (PTH_EVENT_SEM, &out_signal);
198 TRACEPRINTF (t, 1, this, "Detect");
199 USBEndpoint e = parseUSBEndpoint (Dev);
200 d = detectUSBEndpoint (e);
201 state = 0;
202 if (d.dev == 0)
203 return;
204 TRACEPRINTF (t, 1, this, "Using %d:%d:%d:%d:%d (%d:%d)",
205 libusb_get_bus_number (d.dev),
206 libusb_get_device_address (d.dev), d.config, d.altsetting,
207 d.interface, d.sendep, d.recvep);
208 if (libusb_open (d.dev, &dev) < 0)
209 return;
210 libusb_unref_device (d.dev);
211 state = 1;
212 TRACEPRINTF (t, 1, this, "Open");
213 libusb_detach_kernel_driver (dev, d.interface);
214 if (libusb_set_configuration (dev, d.config) < 0)
215 return;
216 if (libusb_claim_interface (dev, d.interface) < 0)
217 return;
218 if (libusb_set_interface_alt_setting (dev, d.interface, d.altsetting) < 0)
219 return;
220 TRACEPRINTF (t, 1, this, "Claimed");
221 state = 2;
223 Start ();
224 TRACEPRINTF (t, 1, this, "Opened");
227 USBLowLevelDriver::~USBLowLevelDriver ()
229 TRACEPRINTF (t, 1, this, "Close");
230 Stop ();
231 pth_event_free (getwait, PTH_FREE_THIS);
233 TRACEPRINTF (t, 1, this, "Release");
234 if (state > 0)
236 libusb_release_interface (dev, d.interface);
237 libusb_attach_kernel_driver (dev, d.interface);
239 TRACEPRINTF (t, 1, this, "Close");
240 if (state > 0)
241 libusb_close (dev);
244 bool
245 USBLowLevelDriver::init ()
247 return state == 2;
250 bool
251 USBLowLevelDriver::Connection_Lost ()
253 return 0;
256 void
257 USBLowLevelDriver::Send_Packet (CArray l)
259 CArray pdu;
260 t->TracePacket (1, this, "Send", l);
262 inqueue.put (l);
263 pth_sem_set_value (&send_empty, 0);
264 pth_sem_inc (&in_signal, TRUE);
267 void
268 USBLowLevelDriver::SendReset ()
272 bool
273 USBLowLevelDriver::Send_Queue_Empty ()
275 return inqueue.isempty ();
278 pth_sem_t *
279 USBLowLevelDriver::Send_Queue_Empty_Cond ()
281 return &send_empty;
284 CArray *
285 USBLowLevelDriver::Get_Packet (pth_event_t stop)
287 if (stop != NULL)
288 pth_event_concat (getwait, stop, NULL);
290 pth_wait (getwait);
292 if (stop)
293 pth_event_isolate (getwait);
295 if (pth_event_status (getwait) == PTH_STATUS_OCCURRED)
297 pth_sem_dec (&out_signal);
298 CArray *c = outqueue.get ();
299 t->TracePacket (1, this, "Recv", *c);
300 return c;
302 else
303 return 0;
306 LowLevelDriverInterface::EMIVer USBLowLevelDriver::getEMIVer ()
308 return vRaw;
311 struct usb_complete
313 pth_sem_t
314 signal;
317 void
318 usb_complete (struct libusb_transfer *transfer)
320 struct usb_complete *
321 complete = (struct usb_complete *) transfer->user_data;
322 pth_sem_inc (&complete->signal, 0);
325 void
326 USBLowLevelDriver::Run (pth_sem_t * stop1)
328 pth_event_t stop = pth_event (PTH_EVENT_SEM, stop1);
329 pth_event_t input = pth_event (PTH_EVENT_SEM, &in_signal);
330 uchar recvbuf[64];
331 uchar sendbuf[64];
332 struct libusb_transfer *sendh = 0;
333 struct libusb_transfer *recvh = 0;
334 struct usb_complete sendc, recvc;
335 pth_event_t sende = pth_event (PTH_EVENT_SEM, &in_signal);
336 pth_event_t recve = pth_event (PTH_EVENT_SEM, &in_signal);
338 pth_sem_init (&sendc.signal);
339 pth_sem_init (&recvc.signal);
341 while (pth_event_status (stop) != PTH_STATUS_OCCURRED)
343 if (!recvh)
345 recvh = libusb_alloc_transfer (0);
346 if (!recvh)
348 TRACEPRINTF (t, 0, this, "Error AllocRecv");
349 break;
351 libusb_fill_interrupt_transfer (recvh, dev, d.recvep, recvbuf,
352 sizeof (recvbuf), usb_complete,
353 &recvc, 30000);
354 if (libusb_submit_transfer (recvh))
356 TRACEPRINTF (t, 0, this, "Error StartRecv");
357 break;
360 TRACEPRINTF (t, 0, this, "StartRecv");
361 pth_event (PTH_EVENT_SEM | PTH_MODE_REUSE | PTH_UNTIL_DECREMENT,
362 recve, &recvc.signal);
364 if (recvh && pth_event_status (recve) == PTH_STATUS_OCCURRED)
366 if (recvh->status != LIBUSB_TRANSFER_COMPLETED)
367 TRACEPRINTF (t, 0, this, "RecvError %d", recvh->status);
368 else
370 TRACEPRINTF (t, 0, this, "RecvComplete %d",
371 recvh->actual_length);
372 CArray res;
373 res.set (recvbuf, sizeof (recvbuf));
374 t->TracePacket (0, this, "RecvUSB", res);
375 outqueue.put (new CArray (res));
376 pth_sem_inc (&out_signal, 1);
378 libusb_free_transfer (recvh);
379 recvh = 0;
380 continue;
382 if (sendh && pth_event_status (sende) == PTH_STATUS_OCCURRED)
384 if (sendh->status != LIBUSB_TRANSFER_COMPLETED)
385 TRACEPRINTF (t, 0, this, "SendError %d", sendh->status);
386 else
388 TRACEPRINTF (t, 0, this, "SendComplete %d",
389 sendh->actual_length);
390 pth_sem_dec (&in_signal);
391 inqueue.get ();
392 if (inqueue.isempty ())
393 pth_sem_set_value (&send_empty, 1);
395 libusb_free_transfer (sendh);
396 sendh = 0;
397 continue;
399 if (!sendh && !inqueue.isempty ())
401 const CArray & c = inqueue.top ();
402 t->TracePacket (0, this, "Send", c);
403 memset (sendbuf, 0, sizeof (sendbuf));
404 memcpy (sendbuf, c.array (),
405 (c () > sizeof (sendbuf) ? sizeof (sendbuf) : c ()));
406 sendh = libusb_alloc_transfer (0);
407 if (!sendh)
409 TRACEPRINTF (t, 0, this, "Error AllocSend");
410 break;
412 libusb_fill_interrupt_transfer (sendh, dev, d.sendep, sendbuf,
413 sizeof (sendbuf), usb_complete,
414 &sendc, 1000);
415 if (libusb_submit_transfer (sendh))
417 TRACEPRINTF (t, 0, this, "Error StartSend");
418 break;
420 TRACEPRINTF (t, 0, this, "StartSend");
421 pth_event (PTH_EVENT_SEM | PTH_MODE_REUSE | PTH_UNTIL_DECREMENT,
422 sende, &sendc.signal);
423 continue;
426 if (recvh)
427 pth_event_concat (stop, recve, NULL);
428 if (sendh)
429 pth_event_concat (stop, sende, NULL);
430 else
431 pth_event_concat (stop, input, NULL);
433 pth_wait (stop);
435 pth_event_isolate (sende);
436 pth_event_isolate (recve);
437 pth_event_isolate (input);
440 if (sendh)
442 libusb_cancel_transfer (sendh);
443 libusb_free_transfer (sendh);
445 if (recvh)
447 libusb_cancel_transfer (recvh);
448 libusb_free_transfer (recvh);
450 pth_event_free (stop, PTH_FREE_THIS);
451 pth_event_free (input, PTH_FREE_THIS);
452 pth_event_free (sende, PTH_FREE_THIS);
453 pth_event_free (recve, PTH_FREE_THIS);