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.
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");
222 connection_state
= true;
225 TRACEPRINTF (t
, 1, this, "Opened");
228 USBLowLevelDriver::~USBLowLevelDriver ()
230 TRACEPRINTF (t
, 1, this, "Close");
232 pth_event_free (getwait
, PTH_FREE_THIS
);
234 TRACEPRINTF (t
, 1, this, "Release");
237 libusb_release_interface (dev
, d
.interface
);
238 libusb_attach_kernel_driver (dev
, d
.interface
);
240 TRACEPRINTF (t
, 1, this, "Close");
246 USBLowLevelDriver::init ()
252 USBLowLevelDriver::Connection_Lost ()
258 USBLowLevelDriver::Send_Packet (CArray l
)
261 t
->TracePacket (1, this, "Send", l
);
264 pth_sem_set_value (&send_empty
, 0);
265 pth_sem_inc (&in_signal
, TRUE
);
269 USBLowLevelDriver::SendReset ()
274 USBLowLevelDriver::Send_Queue_Empty ()
276 return inqueue
.isempty ();
280 USBLowLevelDriver::Send_Queue_Empty_Cond ()
286 USBLowLevelDriver::Get_Packet (pth_event_t stop
)
289 pth_event_concat (getwait
, stop
, NULL
);
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
);
307 LowLevelDriverInterface::EMIVer
USBLowLevelDriver::getEMIVer ()
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);
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
);
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
)
346 recvh
= libusb_alloc_transfer (0);
349 TRACEPRINTF (t
, 0, this, "Error AllocRecv");
352 libusb_fill_interrupt_transfer (recvh
, dev
, d
.recvep
, recvbuf
,
353 sizeof (recvbuf
), usb_complete
,
355 if (libusb_submit_transfer (recvh
))
357 TRACEPRINTF (t
, 0, this, "Error StartRecv");
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
);
371 TRACEPRINTF (t
, 0, this, "RecvComplete %d",
372 recvh
->actual_length
);
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;
394 connection_state
= false;
397 libusb_free_transfer (recvh
);
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
);
407 TRACEPRINTF (t
, 0, this, "SendComplete %d",
408 sendh
->actual_length
);
409 pth_sem_dec (&in_signal
);
411 if (inqueue
.isempty ())
412 pth_sem_set_value (&send_empty
, 1);
414 libusb_free_transfer (sendh
);
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);
428 TRACEPRINTF (t
, 0, this, "Error AllocSend");
431 libusb_fill_interrupt_transfer (sendh
, dev
, d
.sendep
, sendbuf
,
432 sizeof (sendbuf
), usb_complete
,
434 if (libusb_submit_transfer (sendh
))
436 TRACEPRINTF (t
, 0, this, "Error StartSend");
439 TRACEPRINTF (t
, 0, this, "StartSend");
440 pth_event (PTH_EVENT_SEM
| PTH_MODE_REUSE
| PTH_UNTIL_DECREMENT
,
441 sende
, &sendc
.signal
);
446 pth_event_concat (stop
, recve
, NULL
);
448 pth_event_concat (stop
, sende
, NULL
);
450 pth_event_concat (stop
, input
, NULL
);
454 pth_event_isolate (sende
);
455 pth_event_isolate (recve
);
456 pth_event_isolate (input
);
461 libusb_cancel_transfer (sendh
);
462 libusb_free_transfer (sendh
);
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
);