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
30 parseUSBEndpoint (const char *addr
)
43 while (isdigit (*addr
))
50 e
.device
= atoi (addr
);
51 while (isdigit (*addr
))
58 e
.config
= atoi (addr
);
59 while (isdigit (*addr
))
66 e
.altsetting
= atoi (addr
);
72 e
.interface
= atoi (addr
);
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
;
91 if (libusb_get_bus_number (dev
) != e
.bus
&& e
.bus
!= -1)
93 if (libusb_get_device_address (dev
) != e
.device
&& e
.device
!= -1)
96 if (libusb_get_device_descriptor (dev
, &desc
))
99 for (j
= 0; j
< desc
.bNumConfigurations
; j
++)
101 if (libusb_get_config_descriptor (dev
, j
, &cfg
))
103 if (cfg
->bConfigurationValue
!= e
.config
&& e
.config
!= -1)
105 libusb_free_config_descriptor (cfg
);
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
)
117 if (alts
->bAlternateSetting
!= e
.altsetting
118 && e
.altsetting
!= -1)
120 if (alts
->bInterfaceNumber
!= e
.interface
&& e
.interface
!= -1)
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
)
133 bmAttributes
& LIBUSB_TRANSFER_TYPE_MASK
) ==
134 LIBUSB_TRANSFER_TYPE_INTERRUPT
)
135 in
= ep
->bEndpointAddress
;
140 bmAttributes
& LIBUSB_TRANSFER_TYPE_MASK
) ==
141 LIBUSB_TRANSFER_TYPE_INTERRUPT
)
142 out
= ep
->bEndpointAddress
;
149 if (!libusb_open (dev
, &h
))
153 libusb_ref_device (dev
);
154 e1
.config
= cfg
->bConfigurationValue
;
155 e1
.interface
= alts
->bInterfaceNumber
;
156 e1
.altsetting
= alts
->bAlternateSetting
;
161 libusb_free_config_descriptor (cfg
);
166 libusb_free_config_descriptor (cfg
);
172 detectUSBEndpoint (USBEndpoint e
)
174 libusb_device
**devs
;
178 count
= libusb_get_device_list (NULL
, &devs
);
180 for (i
= 0; i
< count
; i
++)
181 if (check_device (devs
[i
], e
, e2
))
184 libusb_free_device_list (devs
, 1);
189 USBLowLevelDriver::USBLowLevelDriver (const char *Dev
, Trace
* 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
);
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)
210 libusb_unref_device (d
.dev
);
212 TRACEPRINTF (t
, 1, this, "Open");
213 libusb_detach_kernel_driver (dev
, d
.interface
);
214 if (libusb_set_configuration (dev
, d
.config
) < 0)
216 if (libusb_claim_interface (dev
, d
.interface
) < 0)
218 if (libusb_set_interface_alt_setting (dev
, d
.interface
, d
.altsetting
) < 0)
220 TRACEPRINTF (t
, 1, this, "Claimed");
224 TRACEPRINTF (t
, 1, this, "Opened");
227 USBLowLevelDriver::~USBLowLevelDriver ()
229 TRACEPRINTF (t
, 1, this, "Close");
231 pth_event_free (getwait
, PTH_FREE_THIS
);
233 TRACEPRINTF (t
, 1, this, "Release");
236 libusb_release_interface (dev
, d
.interface
);
237 libusb_attach_kernel_driver (dev
, d
.interface
);
239 TRACEPRINTF (t
, 1, this, "Close");
245 USBLowLevelDriver::init ()
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 ()
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);
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
);
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
)
345 recvh
= libusb_alloc_transfer (0);
348 TRACEPRINTF (t
, 0, this, "Error AllocRecv");
351 libusb_fill_interrupt_transfer (recvh
, dev
, d
.recvep
, recvbuf
,
352 sizeof (recvbuf
), usb_complete
,
354 if (libusb_submit_transfer (recvh
))
356 TRACEPRINTF (t
, 0, this, "Error StartRecv");
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
);
370 TRACEPRINTF (t
, 0, this, "RecvComplete %d",
371 recvh
->actual_length
);
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
);
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
);
388 TRACEPRINTF (t
, 0, this, "SendComplete %d",
389 sendh
->actual_length
);
390 pth_sem_dec (&in_signal
);
392 if (inqueue
.isempty ())
393 pth_sem_set_value (&send_empty
, 1);
395 libusb_free_transfer (sendh
);
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);
409 TRACEPRINTF (t
, 0, this, "Error AllocSend");
412 libusb_fill_interrupt_transfer (sendh
, dev
, d
.sendep
, sendbuf
,
413 sizeof (sendbuf
), usb_complete
,
415 if (libusb_submit_transfer (sendh
))
417 TRACEPRINTF (t
, 0, this, "Error StartSend");
420 TRACEPRINTF (t
, 0, this, "StartSend");
421 pth_event (PTH_EVENT_SEM
| PTH_MODE_REUSE
| PTH_UNTIL_DECREMENT
,
422 sende
, &sendc
.signal
);
427 pth_event_concat (stop
, recve
, NULL
);
429 pth_event_concat (stop
, sende
, NULL
);
431 pth_event_concat (stop
, input
, NULL
);
435 pth_event_isolate (sende
);
436 pth_event_isolate (recve
);
437 pth_event_isolate (input
);
442 libusb_cancel_transfer (sendh
);
443 libusb_free_transfer (sendh
);
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
);