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
26 #include <asm/types.h>
27 #include <linux/hiddev.h>
28 #include <sys/ioctl.h>
32 parseUSBEndpoint (const char *addr
)
44 while (isdigit (*addr
))
51 e
.device
= atoi (addr
);
52 while (isdigit (*addr
))
59 e
.config
= atoi (addr
);
60 while (isdigit (*addr
))
67 e
.interface
= atoi (addr
);
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
;
81 libusb_dev_handle_t h
;
87 libusb_get_devnum (cdev
, &devnum
);
88 libusb_get_bus_id (cdev
, &bus
);
90 if (libusb_get_busnum (bus
) != e
.bus
&& e
.bus
!= -1)
92 if (devnum
!= e
.device
&& e
.device
!= -1)
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)
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)
106 if (intf
.bInterfaceClass
!= USB_CLASS_HID
)
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
;
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
;
133 (ep
.bmAttributes
& USB_ENDPOINT_TYPE_MASK
) ==
134 USB_ENDPOINT_TYPE_INTERRUPT
;
142 if (libusb_open (cdev
, &h
) >= 0)
146 e1
.config
= cfg
.bConfigurationValue
;
147 e1
.interface
= intf
.bInterfaceNumber
;
159 check_devlist (libusb_device_id_t dev
, USBEndpoint e
)
161 libusb_device_id_t cdev
;
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)
171 check_devlist (cdev
, e
);
176 detectUSBEndpoint (USBEndpoint e
)
179 libusb_device_id_t dev
;
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)
201 USBLowLevelDriver::USBLowLevelDriver (const char *Dev
, Trace
* tr
)
204 unsigned char devnum
;
207 TRACEPRINTF (t
, 1, this, "Detect");
208 USBEndpoint e
= parseUSBEndpoint (Dev
);
209 d
= detectUSBEndpoint (e
);
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
);
233 TRACEPRINTF (t
, 1, this, "Opened");
236 USBLowLevelDriver::~USBLowLevelDriver ()
238 TRACEPRINTF (t
, 1, this, "Close");
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");
251 USBLowLevelDriver::Connection_Lost ()
257 USBLowLevelDriver::Send_Packet (CArray l
)
260 t
->TracePacket (1, this, "Send", l
);
263 pth_sem_set_value (&send_empty
, 0);
264 pth_sem_inc (&in_signal
, TRUE
);
268 USBLowLevelDriver::SendReset ()
273 USBLowLevelDriver::Send_Queue_Empty ()
275 return inqueue
.isempty ();
279 USBLowLevelDriver::Send_Queue_Empty_Cond ()
285 USBLowLevelDriver::Get_Packet (pth_event_t stop
)
288 pth_event_concat (getwait
, stop
, NULL
);
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
);
306 LowLevelDriverInterface::EMIVer
USBLowLevelDriver::getEMIVer ()
313 USBLowLevelDriver::Run (pth_sem_t
* stop1
)
316 pth_event_t stop
= pth_event (PTH_EVENT_SEM
, stop1
);
317 pth_event_t input
= pth_event (PTH_EVENT_SEM
, &in_signal
);
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
)
330 libusb_submit_interrupt_read (dev
, d
.recvep
, recvbuf
,
331 sizeof (recvbuf
), 1000, 0);
334 TRACEPRINTF (t
, 0, this, "Error StartRecv");
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
));
350 TRACEPRINTF (t
, 0, this, "RecvComplete %d",
351 libusb_io_xfer_size (recvh
));
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
);
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
));
370 TRACEPRINTF (t
, 0, this, "SendComplete %d",
371 libusb_io_xfer_size (sendh
));
372 pth_sem_dec (&in_signal
);
374 if (inqueue
.isempty ())
375 pth_sem_set_value (&send_empty
, 1);
377 libusb_io_free (sendh
);
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 ()));
390 libusb_submit_interrupt_write (dev
, d
.sendep
, sendbuf
,
391 sizeof (sendbuf
), 1000, 0);
394 TRACEPRINTF (t
, 0, this, "Error StartSend");
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
));
405 pth_event_concat (stop
, recve
, NULL
);
407 pth_event_concat (stop
, sende
, NULL
);
409 pth_event_concat (stop
, input
, NULL
);
413 pth_event_isolate (sende
);
414 pth_event_isolate (recve
);
415 pth_event_isolate (input
);
420 libusb_io_cancel (sendh
);
421 libusb_io_free (sendh
);
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
);