Use Makefile variables for Python paths
[bcusdk.git] / eibd / backend / usbif.cpp
blob1ff28ff59fdac7faf3294ce60831b8e6de37b7c4
1 /*
2 EIBD eib bus access and management daemon
3 Copyright (C) 2005-2007 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 <asm/types.h>
27 #include <linux/hiddev.h>
28 #include <sys/ioctl.h>
29 #include "usbif.h"
31 USBEndpoint
32 parseUSBEndpoint (const char *addr)
34 USBEndpoint e;
35 e.bus = -1;
36 e.device = -1;
37 e.config = -1;
38 e.interface = -1;
39 if (!*addr)
40 return e;
41 if (!isdigit (*addr))
42 return e;
43 e.bus = atoi (addr);
44 while (isdigit (*addr))
45 addr++;
46 if (*addr != ':')
47 return e;
48 addr++;
49 if (!isdigit (*addr))
50 return e;
51 e.device = atoi (addr);
52 while (isdigit (*addr))
53 addr++;
54 if (*addr != ':')
55 return e;
56 addr++;
57 if (!isdigit (*addr))
58 return e;
59 e.config = atoi (addr);
60 while (isdigit (*addr))
61 addr++;
62 if (*addr != ':')
63 return e;
64 addr++;
65 if (!isdigit (*addr))
66 return e;
67 e.interface = atoi (addr);
68 return e;
71 void
72 check_device (libusb_device_id_t cdev, USBEndpoint e)
74 struct usb_device_desc desc;
75 struct usb_config_desc cfg;
76 struct usb_interface_desc intf;
77 struct usb_endpoint_desc ep;
78 int in, out, outint;
79 libusb_bus_id_t bus;
80 unsigned char devnum;
81 libusb_dev_handle_t h;
82 int j, k, l;
84 if (!cdev)
85 return;
87 libusb_get_devnum (cdev, &devnum);
88 libusb_get_bus_id (cdev, &bus);
90 if (libusb_get_busnum (bus) != e.bus && e.bus != -1)
91 return;
92 if (devnum != e.device && e.device != -1)
93 return;
95 libusb_get_device_desc (cdev, &desc);
96 for (j = 0; j < desc.bNumConfigurations; j++)
98 libusb_get_config_desc (cdev, j, &cfg);
99 if (cfg.bConfigurationValue != e.config && e.config != -1)
100 continue;
101 for (k = 0; k < cfg.bNumInterfaces; k++)
103 libusb_get_interface_desc (cdev, j, k, &intf);
104 if (intf.bInterfaceNumber != e.interface && e.interface != -1)
105 continue;
106 if (intf.bInterfaceClass != USB_CLASS_HID)
107 continue;
109 in = 0;
110 out = 0;
111 outint = 0;
113 for (l = 0; l < intf.bNumEndpoints; l++)
115 libusb_get_endpoint_desc (cdev, j, k, l, &ep);
116 if (ep.wMaxPacketSize == 64)
118 if (ep.bEndpointAddress & 0x80)
120 if ((ep.bmAttributes & USB_ENDPOINT_TYPE_MASK) ==
121 USB_ENDPOINT_TYPE_INTERRUPT)
122 in = ep.bEndpointAddress;
124 else
126 if (((ep.bmAttributes & USB_ENDPOINT_TYPE_MASK) ==
127 USB_ENDPOINT_TYPE_CONTROL && !outint && 0)
128 || (ep.bmAttributes & USB_ENDPOINT_TYPE_MASK) ==
129 USB_ENDPOINT_TYPE_INTERRUPT)
131 out = ep.bEndpointAddress;
132 outint =
133 (ep.bmAttributes & USB_ENDPOINT_TYPE_MASK) ==
134 USB_ENDPOINT_TYPE_INTERRUPT;
140 if (!in || !out)
141 continue;
142 if (libusb_open (cdev, &h) >= 0)
144 USBDevice e1;
145 e1.dev = cdev;
146 e1.config = cfg.bConfigurationValue;
147 e1.interface = intf.bInterfaceNumber;
148 e1.sendep = out;
149 e1.recvep = in;
150 libusb_close (h);
151 throw e1;
158 void
159 check_devlist (libusb_device_id_t dev, USBEndpoint e)
161 libusb_device_id_t cdev;
162 unsigned char count;
163 int i;
165 check_device (dev, e);
166 libusb_get_child_count (dev, &count);
167 for (i = 0; i < count; i++)
169 if (libusb_get_child_device_id (dev, i + 1, &cdev) < 0)
170 continue;
171 check_devlist (cdev, e);
175 USBDevice
176 detectUSBEndpoint (USBEndpoint e)
178 libusb_bus_id_t bus;
179 libusb_device_id_t dev;
180 USBDevice e2;
183 for (libusb_get_first_bus_id (&bus); bus;)
185 libusb_get_first_device_id (bus, &dev);
186 check_devlist (dev, e);
188 if (libusb_get_next_bus_id (&bus) < 0)
189 break;
192 catch (USBDevice e1)
194 return e1;
196 e2.dev = -1;
197 return e2;
201 USBLowLevelDriver::USBLowLevelDriver (const char *Dev, Trace * tr)
203 libusb_bus_id_t bus;
204 unsigned char devnum;
206 t = tr;
207 TRACEPRINTF (t, 1, this, "Detect");
208 USBEndpoint e = parseUSBEndpoint (Dev);
209 d = detectUSBEndpoint (e);
210 if (d.dev == -1)
211 throw Exception (DEV_OPEN_FAIL);
212 libusb_get_devnum (d.dev, &devnum);
213 libusb_get_bus_id (d.dev, &bus);
214 TRACEPRINTF (t, 1, this, "Using %d (%d:%d:%d:%d) (%d:%d)", d.dev,
215 libusb_get_busnum (bus),
216 devnum, d.config, d.interface, d.sendep, d.recvep);
217 if (libusb_open (d.dev, &dev) < 0)
218 throw Exception (DEV_OPEN_FAIL);
219 TRACEPRINTF (t, 1, this, "Open");
220 libusb_detach_kernel_driver_np (dev, d.interface);
221 if (libusb_set_configuration (dev, d.config) < 0)
222 throw Exception (DEV_OPEN_FAIL);
223 if (libusb_claim_interface (dev, d.interface) < 0)
224 throw Exception (DEV_OPEN_FAIL);
225 TRACEPRINTF (t, 1, this, "Claimed");
227 pth_sem_init (&in_signal);
228 pth_sem_init (&out_signal);
229 pth_sem_init (&send_empty);
230 pth_sem_set_value (&send_empty, 1);
231 getwait = pth_event (PTH_EVENT_SEM, &out_signal);
232 Start ();
233 TRACEPRINTF (t, 1, this, "Opened");
236 USBLowLevelDriver::~USBLowLevelDriver ()
238 TRACEPRINTF (t, 1, this, "Close");
239 Stop ();
240 pth_event_free (getwait, PTH_FREE_THIS);
242 TRACEPRINTF (t, 1, this, "Release");
243 libusb_release_interface (dev, d.interface);
244 libusb_attach_kernel_driver_np (dev, d.interface);
245 TRACEPRINTF (t, 1, this, "Close");
246 libusb_close (dev);
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;
312 void
313 USBLowLevelDriver::Run (pth_sem_t * stop1)
315 int i, j;
316 pth_event_t stop = pth_event (PTH_EVENT_SEM, stop1);
317 pth_event_t input = pth_event (PTH_EVENT_SEM, &in_signal);
318 uchar recvbuf[64];
319 uchar sendbuf[64];
320 libusb_io_handle_t *sendh = 0;
321 libusb_io_handle_t *recvh = 0;
322 pth_event_t sende = pth_event (PTH_EVENT_SEM, &in_signal);;
323 pth_event_t recve = pth_event (PTH_EVENT_SEM, &in_signal);;
325 while (pth_event_status (stop) != PTH_STATUS_OCCURRED)
327 if (!recvh)
329 recvh =
330 libusb_submit_interrupt_read (dev, d.recvep, recvbuf,
331 sizeof (recvbuf), 1000, 0);
332 if (!recvh)
334 TRACEPRINTF (t, 0, this, "Error StartRecv");
335 break;
337 TRACEPRINTF (t, 0, this, "StartRecv");
338 pth_event (PTH_EVENT_FD | PTH_MODE_REUSE | PTH_UNTIL_FD_READABLE |
339 PTH_UNTIL_FD_WRITEABLE, recve,
340 libusb_io_wait_handle (recvh));
343 if (recvh && libusb_is_io_completed (recvh))
345 if (libusb_io_comp_status (recvh) < 0)
346 TRACEPRINTF (t, 0, this, "RecvError %d",
347 libusb_io_comp_status (recvh));
348 else
350 TRACEPRINTF (t, 0, this, "RecvComplete %d",
351 libusb_io_xfer_size (recvh));
352 CArray res;
353 res.set (recvbuf, sizeof (recvbuf));
354 t->TracePacket (0, this, "RecvUSB", res);
355 outqueue.put (new CArray (res));
356 pth_sem_inc (&out_signal, 1);
358 libusb_io_free (recvh);
359 recvh = 0;
360 continue;
363 if (sendh && libusb_is_io_completed (sendh))
365 if (libusb_io_comp_status (sendh) < 0)
366 TRACEPRINTF (t, 0, this, "SendError %d",
367 libusb_io_comp_status (sendh));
368 else
370 TRACEPRINTF (t, 0, this, "SendComplete %d",
371 libusb_io_xfer_size (sendh));
372 pth_sem_dec (&in_signal);
373 inqueue.get ();
374 if (inqueue.isempty ())
375 pth_sem_set_value (&send_empty, 1);
377 libusb_io_free (sendh);
378 sendh = 0;
379 continue;
381 if (!sendh && !inqueue.isempty ())
383 const CArray & c = inqueue.top ();
384 t->TracePacket (0, this, "Send", c);
385 memset (sendbuf, 0, sizeof (sendbuf));
386 memcpy (sendbuf, c.array (),
387 (c () > sizeof (sendbuf) ? sizeof (sendbuf) : c ()));
389 sendh =
390 libusb_submit_interrupt_write (dev, d.sendep, sendbuf,
391 sizeof (sendbuf), 1000, 0);
392 if (!sendh)
394 TRACEPRINTF (t, 0, this, "Error StartSend");
395 break;
397 TRACEPRINTF (t, 0, this, "StartSend");
398 pth_event (PTH_EVENT_FD | PTH_MODE_REUSE | PTH_UNTIL_FD_READABLE |
399 PTH_UNTIL_FD_WRITEABLE, sende,
400 libusb_io_wait_handle (sendh));
401 continue;
404 if (recvh)
405 pth_event_concat (stop, recve, NULL);
406 if (sendh)
407 pth_event_concat (stop, sende, NULL);
408 else
409 pth_event_concat (stop, input, NULL);
411 pth_wait (stop);
413 pth_event_isolate (sende);
414 pth_event_isolate (recve);
415 pth_event_isolate (input);
418 if (sendh)
420 libusb_io_cancel (sendh);
421 libusb_io_free (sendh);
423 if (recvh)
425 libusb_io_cancel (recvh);
426 libusb_io_free (recvh);
428 pth_event_free (stop, PTH_FREE_THIS);
429 pth_event_free (input, PTH_FREE_THIS);
430 pth_event_free (sende, PTH_FREE_THIS);
431 pth_event_free (recve, PTH_FREE_THIS);