netbsd: Recognize device timeouts.
[platform/upstream/libusb.git] / libusb / os / netbsd_usb.c
1 /*
2  * Copyright © 2011 Martin Pieuchot <mpi@openbsd.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 #include <config.h>
20
21 #include <sys/time.h>
22 #include <sys/types.h>
23
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30
31 #include <dev/usb/usb.h>
32
33 #include "libusbi.h"
34
35 struct device_priv {
36         char devnode[16];
37         int fd;
38
39         unsigned char *cdesc;                   /* active config descriptor */
40         usb_device_descriptor_t ddesc;          /* usb device descriptor */
41 };
42
43 struct handle_priv {
44         int endpoints[USB_MAX_ENDPOINTS];
45 };
46
47 /*
48  * Backend functions
49  */
50 static int netbsd_get_device_list(struct libusb_context *,
51     struct discovered_devs **);
52 static int netbsd_open(struct libusb_device_handle *);
53 static void netbsd_close(struct libusb_device_handle *);
54
55 static int netbsd_get_device_descriptor(struct libusb_device *, unsigned char *,
56     int *);
57 static int netbsd_get_active_config_descriptor(struct libusb_device *,
58     unsigned char *, size_t, int *);
59 static int netbsd_get_config_descriptor(struct libusb_device *, uint8_t,
60     unsigned char *, size_t, int *);
61
62 static int netbsd_get_configuration(struct libusb_device_handle *, int *);
63 static int netbsd_set_configuration(struct libusb_device_handle *, int);
64
65 static int netbsd_claim_interface(struct libusb_device_handle *, int);
66 static int netbsd_release_interface(struct libusb_device_handle *, int);
67
68 static int netbsd_set_interface_altsetting(struct libusb_device_handle *, int,
69     int);
70 static int netbsd_clear_halt(struct libusb_device_handle *, unsigned char);
71 static void netbsd_destroy_device(struct libusb_device *);
72
73 static int netbsd_submit_transfer(struct usbi_transfer *);
74 static int netbsd_cancel_transfer(struct usbi_transfer *);
75 static int netbsd_handle_transfer_completion(struct usbi_transfer *);
76
77 /*
78  * Private functions
79  */
80 static int _errno_to_libusb(int);
81 static int _cache_active_config_descriptor(struct libusb_device *, int);
82 static int _sync_control_transfer(struct usbi_transfer *);
83 static int _sync_gen_transfer(struct usbi_transfer *);
84 static int _access_endpoint(struct libusb_transfer *);
85
86 const struct usbi_os_backend usbi_backend = {
87         .name = "Synchronous NetBSD backend",
88         .caps = 0,
89         .get_device_list = netbsd_get_device_list,
90         .open = netbsd_open,
91         .close = netbsd_close,
92
93         .get_device_descriptor = netbsd_get_device_descriptor,
94         .get_active_config_descriptor = netbsd_get_active_config_descriptor,
95         .get_config_descriptor = netbsd_get_config_descriptor,
96
97         .get_configuration = netbsd_get_configuration,
98         .set_configuration = netbsd_set_configuration,
99
100         .claim_interface = netbsd_claim_interface,
101         .release_interface = netbsd_release_interface,
102
103         .set_interface_altsetting = netbsd_set_interface_altsetting,
104         .clear_halt = netbsd_clear_halt,
105
106         .destroy_device = netbsd_destroy_device,
107
108         .submit_transfer = netbsd_submit_transfer,
109         .cancel_transfer = netbsd_cancel_transfer,
110
111         .handle_transfer_completion = netbsd_handle_transfer_completion,
112
113         .device_priv_size = sizeof(struct device_priv),
114         .device_handle_priv_size = sizeof(struct handle_priv),
115 };
116
117 int
118 netbsd_get_device_list(struct libusb_context * ctx,
119         struct discovered_devs **discdevs)
120 {
121         struct libusb_device *dev;
122         struct device_priv *dpriv;
123         struct usb_device_info di;
124         unsigned long session_id;
125         char devnode[16];
126         int fd, err, i;
127
128         usbi_dbg(" ");
129
130         /* Only ugen(4) is supported */
131         for (i = 0; i < USB_MAX_DEVICES; i++) {
132                 /* Control endpoint is always .00 */
133                 snprintf(devnode, sizeof(devnode), "/dev/ugen%d.00", i);
134
135                 if ((fd = open(devnode, O_RDONLY)) < 0) {
136                         if (errno != ENOENT && errno != ENXIO)
137                                 usbi_err(ctx, "could not open %s", devnode);
138                         continue;
139                 }
140
141                 if (ioctl(fd, USB_GET_DEVICEINFO, &di) < 0)
142                         continue;
143
144                 session_id = (di.udi_bus << 8 | di.udi_addr);
145                 dev = usbi_get_device_by_session_id(ctx, session_id);
146
147                 if (dev == NULL) {
148                         dev = usbi_alloc_device(ctx, session_id);
149                         if (dev == NULL)
150                                 return (LIBUSB_ERROR_NO_MEM);
151
152                         dev->bus_number = di.udi_bus;
153                         dev->device_address = di.udi_addr;
154                         dev->speed = di.udi_speed;
155
156                         dpriv = usbi_get_device_priv(dev);
157                         strlcpy(dpriv->devnode, devnode, sizeof(devnode));
158                         dpriv->fd = -1;
159
160                         if (ioctl(fd, USB_GET_DEVICE_DESC, &dpriv->ddesc) < 0) {
161                                 err = errno;
162                                 goto error;
163                         }
164
165                         dpriv->cdesc = NULL;
166                         if (_cache_active_config_descriptor(dev, fd)) {
167                                 err = errno;
168                                 goto error;
169                         }
170
171                         if ((err = usbi_sanitize_device(dev)))
172                                 goto error;
173                 }
174                 close(fd);
175
176                 if (discovered_devs_append(*discdevs, dev) == NULL)
177                         return (LIBUSB_ERROR_NO_MEM);
178
179                 libusb_unref_device(dev);
180         }
181
182         return (LIBUSB_SUCCESS);
183
184 error:
185         close(fd);
186         libusb_unref_device(dev);
187         return _errno_to_libusb(err);
188 }
189
190 int
191 netbsd_open(struct libusb_device_handle *handle)
192 {
193         struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
194         struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
195         int i;
196
197         dpriv->fd = open(dpriv->devnode, O_RDWR);
198         if (dpriv->fd < 0) {
199                 dpriv->fd = open(dpriv->devnode, O_RDONLY);
200                 if (dpriv->fd < 0)
201                         return _errno_to_libusb(errno);
202         }
203
204         for (i = 0; i < USB_MAX_ENDPOINTS; i++)
205                 hpriv->endpoints[i] = -1;
206
207         usbi_dbg("open %s: fd %d", dpriv->devnode, dpriv->fd);
208
209         return (LIBUSB_SUCCESS);
210 }
211
212 void
213 netbsd_close(struct libusb_device_handle *handle)
214 {
215         struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
216
217         usbi_dbg("close: fd %d", dpriv->fd);
218
219         close(dpriv->fd);
220         dpriv->fd = -1;
221 }
222
223 int
224 netbsd_get_device_descriptor(struct libusb_device *dev, unsigned char *buf,
225     int *host_endian)
226 {
227         struct device_priv *dpriv = usbi_get_device_priv(dev);
228
229         usbi_dbg(" ");
230
231         memcpy(buf, &dpriv->ddesc, DEVICE_DESC_LENGTH);
232
233         *host_endian = 0;
234
235         return (LIBUSB_SUCCESS);
236 }
237
238 int
239 netbsd_get_active_config_descriptor(struct libusb_device *dev,
240     unsigned char *buf, size_t len, int *host_endian)
241 {
242         struct device_priv *dpriv = usbi_get_device_priv(dev);
243         usb_config_descriptor_t *ucd;
244
245         ucd = (usb_config_descriptor_t *) dpriv->cdesc;
246         len = MIN(len, UGETW(ucd->wTotalLength));
247
248         usbi_dbg("len %d", len);
249
250         memcpy(buf, dpriv->cdesc, len);
251
252         *host_endian = 0;
253
254         return len;
255 }
256
257 int
258 netbsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
259     unsigned char *buf, size_t len, int *host_endian)
260 {
261         struct device_priv *dpriv = usbi_get_device_priv(dev);
262         struct usb_full_desc ufd;
263         int fd, err;
264
265         usbi_dbg("index %d, len %d", idx, len);
266
267         /* A config descriptor may be requested before opening the device */
268         if (dpriv->fd >= 0) {
269                 fd = dpriv->fd;
270         } else {
271                 fd = open(dpriv->devnode, O_RDONLY);
272                 if (fd < 0)
273                         return _errno_to_libusb(errno);
274         }
275
276         ufd.ufd_config_index = idx;
277         ufd.ufd_size = len;
278         ufd.ufd_data = buf;
279
280         if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
281                 err = errno;
282                 if (dpriv->fd < 0)
283                         close(fd);
284                 return _errno_to_libusb(err);
285         }
286
287         if (dpriv->fd < 0)
288                 close(fd);
289
290         *host_endian = 0;
291
292         return len;
293 }
294
295 int
296 netbsd_get_configuration(struct libusb_device_handle *handle, int *config)
297 {
298         struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
299
300         usbi_dbg(" ");
301
302         if (ioctl(dpriv->fd, USB_GET_CONFIG, config) < 0)
303                 return _errno_to_libusb(errno);
304
305         usbi_dbg("configuration %d", *config);
306
307         return (LIBUSB_SUCCESS);
308 }
309
310 int
311 netbsd_set_configuration(struct libusb_device_handle *handle, int config)
312 {
313         struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
314
315         usbi_dbg("configuration %d", config);
316
317         if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0)
318                 return _errno_to_libusb(errno);
319
320         return _cache_active_config_descriptor(handle->dev, dpriv->fd);
321 }
322
323 int
324 netbsd_claim_interface(struct libusb_device_handle *handle, int iface)
325 {
326         struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
327         int i;
328
329         for (i = 0; i < USB_MAX_ENDPOINTS; i++)
330                 hpriv->endpoints[i] = -1;
331
332         return (LIBUSB_SUCCESS);
333 }
334
335 int
336 netbsd_release_interface(struct libusb_device_handle *handle, int iface)
337 {
338         struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
339         int i;
340
341         for (i = 0; i < USB_MAX_ENDPOINTS; i++)
342                 if (hpriv->endpoints[i] >= 0)
343                         close(hpriv->endpoints[i]);
344
345         return (LIBUSB_SUCCESS);
346 }
347
348 int
349 netbsd_set_interface_altsetting(struct libusb_device_handle *handle, int iface,
350     int altsetting)
351 {
352         struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
353         struct usb_alt_interface intf;
354
355         usbi_dbg("iface %d, setting %d", iface, altsetting);
356
357         memset(&intf, 0, sizeof(intf));
358
359         intf.uai_interface_index = iface;
360         intf.uai_alt_no = altsetting;
361
362         if (ioctl(dpriv->fd, USB_SET_ALTINTERFACE, &intf) < 0)
363                 return _errno_to_libusb(errno);
364
365         return (LIBUSB_SUCCESS);
366 }
367
368 int
369 netbsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
370 {
371         struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
372         struct usb_ctl_request req;
373
374         usbi_dbg(" ");
375
376         req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT;
377         req.ucr_request.bRequest = UR_CLEAR_FEATURE;
378         USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT);
379         USETW(req.ucr_request.wIndex, endpoint);
380         USETW(req.ucr_request.wLength, 0);
381
382         if (ioctl(dpriv->fd, USB_DO_REQUEST, &req) < 0)
383                 return _errno_to_libusb(errno);
384
385         return (LIBUSB_SUCCESS);
386 }
387
388 void
389 netbsd_destroy_device(struct libusb_device *dev)
390 {
391         struct device_priv *dpriv = usbi_get_device_priv(dev);
392
393         usbi_dbg(" ");
394
395         free(dpriv->cdesc);
396 }
397
398 int
399 netbsd_submit_transfer(struct usbi_transfer *itransfer)
400 {
401         struct libusb_transfer *transfer;
402         struct handle_priv *hpriv;
403         int err = 0;
404
405         usbi_dbg(" ");
406
407         transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
408         hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
409
410         switch (transfer->type) {
411         case LIBUSB_TRANSFER_TYPE_CONTROL:
412                 err = _sync_control_transfer(itransfer);
413                 break;
414         case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
415                 if (IS_XFEROUT(transfer)) {
416                         /* Isochronous write is not supported */
417                         err = LIBUSB_ERROR_NOT_SUPPORTED;
418                         break;
419                 }
420                 err = _sync_gen_transfer(itransfer);
421                 break;
422         case LIBUSB_TRANSFER_TYPE_BULK:
423         case LIBUSB_TRANSFER_TYPE_INTERRUPT:
424                 if (IS_XFEROUT(transfer) &&
425                     transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
426                         err = LIBUSB_ERROR_NOT_SUPPORTED;
427                         break;
428                 }
429                 err = _sync_gen_transfer(itransfer);
430                 break;
431         case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
432                 err = LIBUSB_ERROR_NOT_SUPPORTED;
433                 break;
434         }
435
436         if (err)
437                 return (err);
438
439         usbi_signal_transfer_completion(itransfer);
440
441         return (LIBUSB_SUCCESS);
442 }
443
444 int
445 netbsd_cancel_transfer(struct usbi_transfer *itransfer)
446 {
447         usbi_dbg(" ");
448
449         return (LIBUSB_ERROR_NOT_SUPPORTED);
450 }
451
452 int
453 netbsd_handle_transfer_completion(struct usbi_transfer *itransfer)
454 {
455         return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
456 }
457
458 int
459 _errno_to_libusb(int err)
460 {
461         switch (err) {
462         case EIO:
463                 return (LIBUSB_ERROR_IO);
464         case EACCES:
465                 return (LIBUSB_ERROR_ACCESS);
466         case ENOENT:
467                 return (LIBUSB_ERROR_NO_DEVICE);
468         case ENOMEM:
469                 return (LIBUSB_ERROR_NO_MEM);
470         case EWOULDBLOCK:
471         case ETIMEDOUT:
472                 return (LIBUSB_ERROR_TIMEOUT);
473         }
474
475         usbi_dbg("error: %s", strerror(err));
476
477         return (LIBUSB_ERROR_OTHER);
478 }
479
480 int
481 _cache_active_config_descriptor(struct libusb_device *dev, int fd)
482 {
483         struct device_priv *dpriv = usbi_get_device_priv(dev);
484         struct usb_config_desc ucd;
485         struct usb_full_desc ufd;
486         unsigned char* buf;
487         int len;
488
489         usbi_dbg("fd %d", fd);
490
491         ucd.ucd_config_index = USB_CURRENT_CONFIG_INDEX;
492
493         if ((ioctl(fd, USB_GET_CONFIG_DESC, &ucd)) < 0)
494                 return _errno_to_libusb(errno);
495
496         usbi_dbg("active bLength %d", ucd.ucd_desc.bLength);
497
498         len = UGETW(ucd.ucd_desc.wTotalLength);
499         buf = malloc(len);
500         if (buf == NULL)
501                 return (LIBUSB_ERROR_NO_MEM);
502
503         ufd.ufd_config_index = ucd.ucd_config_index;
504         ufd.ufd_size = len;
505         ufd.ufd_data = buf;
506
507         usbi_dbg("index %d, len %d", ufd.ufd_config_index, len);
508
509         if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
510                 free(buf);
511                 return _errno_to_libusb(errno);
512         }
513
514         if (dpriv->cdesc)
515                 free(dpriv->cdesc);
516         dpriv->cdesc = buf;
517
518         return (0);
519 }
520
521 int
522 _sync_control_transfer(struct usbi_transfer *itransfer)
523 {
524         struct libusb_transfer *transfer;
525         struct libusb_control_setup *setup;
526         struct device_priv *dpriv;
527         struct usb_ctl_request req;
528
529         transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
530         dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
531         setup = (struct libusb_control_setup *)transfer->buffer;
532
533         usbi_dbg("type %d request %d value %d index %d length %d timeout %d",
534             setup->bmRequestType, setup->bRequest,
535             libusb_le16_to_cpu(setup->wValue),
536             libusb_le16_to_cpu(setup->wIndex),
537             libusb_le16_to_cpu(setup->wLength), transfer->timeout);
538
539         req.ucr_request.bmRequestType = setup->bmRequestType;
540         req.ucr_request.bRequest = setup->bRequest;
541         /* Don't use USETW, libusb already deals with the endianness */
542         (*(uint16_t *)req.ucr_request.wValue) = setup->wValue;
543         (*(uint16_t *)req.ucr_request.wIndex) = setup->wIndex;
544         (*(uint16_t *)req.ucr_request.wLength) = setup->wLength;
545         req.ucr_data = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
546
547         if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
548                 req.ucr_flags = USBD_SHORT_XFER_OK;
549
550         if ((ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
551                 return _errno_to_libusb(errno);
552
553         if ((ioctl(dpriv->fd, USB_DO_REQUEST, &req)) < 0)
554                 return _errno_to_libusb(errno);
555
556         itransfer->transferred = req.ucr_actlen;
557
558         usbi_dbg("transferred %d", itransfer->transferred);
559
560         return (0);
561 }
562
563 int
564 _access_endpoint(struct libusb_transfer *transfer)
565 {
566         struct handle_priv *hpriv;
567         struct device_priv *dpriv;
568         char *s, devnode[16];
569         int fd, endpt;
570         mode_t mode;
571
572         hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
573         dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
574
575         endpt = UE_GET_ADDR(transfer->endpoint);
576         mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;
577
578         usbi_dbg("endpoint %d mode %d", endpt, mode);
579
580         if (hpriv->endpoints[endpt] < 0) {
581                 /* Pick the right node given the control one */
582                 strlcpy(devnode, dpriv->devnode, sizeof(devnode));
583                 s = strchr(devnode, '.');
584                 snprintf(s, 4, ".%02d", endpt);
585
586                 /* We may need to read/write to the same endpoint later. */
587                 if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
588                         if ((fd = open(devnode, mode)) < 0)
589                                 return (-1);
590
591                 hpriv->endpoints[endpt] = fd;
592         }
593
594         return (hpriv->endpoints[endpt]);
595 }
596
597 int
598 _sync_gen_transfer(struct usbi_transfer *itransfer)
599 {
600         struct libusb_transfer *transfer;
601         int fd, nr = 1;
602
603         transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
604
605         /*
606          * Bulk, Interrupt or Isochronous transfer depends on the
607          * endpoint and thus the node to open.
608          */
609         if ((fd = _access_endpoint(transfer)) < 0)
610                 return _errno_to_libusb(errno);
611
612         if ((ioctl(fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
613                 return _errno_to_libusb(errno);
614
615         if (IS_XFERIN(transfer)) {
616                 if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
617                         if ((ioctl(fd, USB_SET_SHORT_XFER, &nr)) < 0)
618                                 return _errno_to_libusb(errno);
619
620                 nr = read(fd, transfer->buffer, transfer->length);
621         } else {
622                 nr = write(fd, transfer->buffer, transfer->length);
623         }
624
625         if (nr < 0)
626                 return _errno_to_libusb(errno);
627
628         itransfer->transferred = nr;
629
630         return (0);
631 }