Copyright update for 2011
[bcusdk.git] / eibd / backend / usbif.cpp
blobefd42899d73c75c1f6225ab81202b00207192df9
1 /*
2 EIBD eib bus access and management daemon
3 Copyright (C) 2005-2011 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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;
222 connection_state = true;
224 Start ();
225 TRACEPRINTF (t, 1, this, "Opened");
228 USBLowLevelDriver::~USBLowLevelDriver ()
230 TRACEPRINTF (t, 1, this, "Close");
231 Stop ();
232 pth_event_free (getwait, PTH_FREE_THIS);
234 TRACEPRINTF (t, 1, this, "Release");
235 if (state > 0)
237 libusb_release_interface (dev, d.interface);
238 libusb_attach_kernel_driver (dev, d.interface);
240 TRACEPRINTF (t, 1, this, "Close");
241 if (state > 0)
242 libusb_close (dev);
245 bool
246 USBLowLevelDriver::init ()
248 return state == 2;
251 bool
252 USBLowLevelDriver::Connection_Lost ()
254 return 0;
257 void
258 USBLowLevelDriver::Send_Packet (CArray l)
260 CArray pdu;
261 t->TracePacket (1, this, "Send", l);
263 inqueue.put (l);
264 pth_sem_set_value (&send_empty, 0);
265 pth_sem_inc (&in_signal, TRUE);
268 void
269 USBLowLevelDriver::SendReset ()
273 bool
274 USBLowLevelDriver::Send_Queue_Empty ()
276 return inqueue.isempty ();
279 pth_sem_t *
280 USBLowLevelDriver::Send_Queue_Empty_Cond ()
282 return &send_empty;
285 CArray *
286 USBLowLevelDriver::Get_Packet (pth_event_t stop)
288 if (stop != NULL)
289 pth_event_concat (getwait, stop, NULL);
291 pth_wait (getwait);
293 if (stop)
294 pth_event_isolate (getwait);
296 if (pth_event_status (getwait) == PTH_STATUS_OCCURRED)
298 pth_sem_dec (&out_signal);
299 CArray *c = outqueue.get ();
300 t->TracePacket (1, this, "Recv", *c);
301 return c;
303 else
304 return 0;
307 LowLevelDriverInterface::EMIVer USBLowLevelDriver::getEMIVer ()
309 return vRaw;
312 struct usb_complete
314 pth_sem_t
315 signal;
318 void
319 usb_complete (struct libusb_transfer *transfer)
321 struct usb_complete *
322 complete = (struct usb_complete *) transfer->user_data;
323 pth_sem_inc (&complete->signal, 0);
326 void
327 USBLowLevelDriver::Run (pth_sem_t * stop1)
329 pth_event_t stop = pth_event (PTH_EVENT_SEM, stop1);
330 pth_event_t input = pth_event (PTH_EVENT_SEM, &in_signal);
331 uchar recvbuf[64];
332 uchar sendbuf[64];
333 struct libusb_transfer *sendh = 0;
334 struct libusb_transfer *recvh = 0;
335 struct usb_complete sendc, recvc;
336 pth_event_t sende = pth_event (PTH_EVENT_SEM, &in_signal);
337 pth_event_t recve = pth_event (PTH_EVENT_SEM, &in_signal);
339 pth_sem_init (&sendc.signal);
340 pth_sem_init (&recvc.signal);
342 while (pth_event_status (stop) != PTH_STATUS_OCCURRED)
344 if (!recvh)
346 recvh = libusb_alloc_transfer (0);
347 if (!recvh)
349 TRACEPRINTF (t, 0, this, "Error AllocRecv");
350 break;
352 libusb_fill_interrupt_transfer (recvh, dev, d.recvep, recvbuf,
353 sizeof (recvbuf), usb_complete,
354 &recvc, 30000);
355 if (libusb_submit_transfer (recvh))
357 TRACEPRINTF (t, 0, this, "Error StartRecv");
358 break;
361 TRACEPRINTF (t, 0, this, "StartRecv");
362 pth_event (PTH_EVENT_SEM | PTH_MODE_REUSE | PTH_UNTIL_DECREMENT,
363 recve, &recvc.signal);
365 if (recvh && pth_event_status (recve) == PTH_STATUS_OCCURRED)
367 if (recvh->status != LIBUSB_TRANSFER_COMPLETED)
368 TRACEPRINTF (t, 0, this, "RecvError %d", recvh->status);
369 else
371 TRACEPRINTF (t, 0, this, "RecvComplete %d",
372 recvh->actual_length);
373 CArray res;
374 res.set (recvbuf, sizeof (recvbuf));
375 t->TracePacket (0, this, "RecvUSB", res);
376 outqueue.put (new CArray (res));
377 pth_sem_inc (&out_signal, 1);
378 if (recvbuf [0] == 0x01 &&
379 recvbuf [1] == 0x13 &&
380 recvbuf [2] == 0x0A &&
381 recvbuf [3] == 0x00 &&
382 recvbuf [4] == 0x08 &&
383 recvbuf [5] == 0x00 &&
384 recvbuf [6] == 0x02 &&
385 recvbuf [7] == 0x0F &&
386 recvbuf [8] == 0x04 &&
387 recvbuf [9] == 0x00 &&
388 recvbuf [10] == 0x00 &&
389 recvbuf [11] == 0x03)
391 if (recvbuf [12] & 0x1)
392 connection_state = true;
393 else
394 connection_state = false;
397 libusb_free_transfer (recvh);
398 recvh = 0;
399 continue;
401 if (sendh && pth_event_status (sende) == PTH_STATUS_OCCURRED)
403 if (sendh->status != LIBUSB_TRANSFER_COMPLETED)
404 TRACEPRINTF (t, 0, this, "SendError %d", sendh->status);
405 else
407 TRACEPRINTF (t, 0, this, "SendComplete %d",
408 sendh->actual_length);
409 pth_sem_dec (&in_signal);
410 inqueue.get ();
411 if (inqueue.isempty ())
412 pth_sem_set_value (&send_empty, 1);
414 libusb_free_transfer (sendh);
415 sendh = 0;
416 continue;
418 if (!sendh && !inqueue.isempty () && connection_state)
420 const CArray & c = inqueue.top ();
421 t->TracePacket (0, this, "Send", c);
422 memset (sendbuf, 0, sizeof (sendbuf));
423 memcpy (sendbuf, c.array (),
424 (c () > sizeof (sendbuf) ? sizeof (sendbuf) : c ()));
425 sendh = libusb_alloc_transfer (0);
426 if (!sendh)
428 TRACEPRINTF (t, 0, this, "Error AllocSend");
429 break;
431 libusb_fill_interrupt_transfer (sendh, dev, d.sendep, sendbuf,
432 sizeof (sendbuf), usb_complete,
433 &sendc, 1000);
434 if (libusb_submit_transfer (sendh))
436 TRACEPRINTF (t, 0, this, "Error StartSend");
437 break;
439 TRACEPRINTF (t, 0, this, "StartSend");
440 pth_event (PTH_EVENT_SEM | PTH_MODE_REUSE | PTH_UNTIL_DECREMENT,
441 sende, &sendc.signal);
442 continue;
445 if (recvh)
446 pth_event_concat (stop, recve, NULL);
447 if (sendh)
448 pth_event_concat (stop, sende, NULL);
449 else
450 pth_event_concat (stop, input, NULL);
452 pth_wait (stop);
454 pth_event_isolate (sende);
455 pth_event_isolate (recve);
456 pth_event_isolate (input);
459 if (sendh)
461 libusb_cancel_transfer (sendh);
462 libusb_free_transfer (sendh);
464 if (recvh)
466 libusb_cancel_transfer (recvh);
467 libusb_free_transfer (recvh);
469 pth_event_free (stop, PTH_FREE_THIS);
470 pth_event_free (input, PTH_FREE_THIS);
471 pth_event_free (sende, PTH_FREE_THIS);
472 pth_event_free (recve, PTH_FREE_THIS);