Misc: Fix usbi_os_backend structure initialization
[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 int netbsd_reset_device(struct libusb_device_handle *);
72 static void netbsd_destroy_device(struct libusb_device *);
73
74 static int netbsd_submit_transfer(struct usbi_transfer *);
75 static int netbsd_cancel_transfer(struct usbi_transfer *);
76 static void netbsd_clear_transfer_priv(struct usbi_transfer *);
77 static int netbsd_handle_transfer_completion(struct usbi_transfer *);
78 static int netbsd_clock_gettime(int, struct timespec *);
79
80 /*
81  * Private functions
82  */
83 static int _errno_to_libusb(int);
84 static int _cache_active_config_descriptor(struct libusb_device *, int);
85 static int _sync_control_transfer(struct usbi_transfer *);
86 static int _sync_gen_transfer(struct usbi_transfer *);
87 static int _access_endpoint(struct libusb_transfer *);
88
89 const struct usbi_os_backend netbsd_backend = {
90         "Synchronous NetBSD backend",
91         0,
92         NULL,                           /* init() */
93         NULL,                           /* exit() */
94         netbsd_get_device_list,
95         NULL,                           /* hotplug_poll */
96         netbsd_open,
97         netbsd_close,
98
99         netbsd_get_device_descriptor,
100         netbsd_get_active_config_descriptor,
101         netbsd_get_config_descriptor,
102         NULL,                           /* get_config_descriptor_by_value() */
103
104         netbsd_get_configuration,
105         netbsd_set_configuration,
106
107         netbsd_claim_interface,
108         netbsd_release_interface,
109
110         netbsd_set_interface_altsetting,
111         netbsd_clear_halt,
112         netbsd_reset_device,
113
114         NULL,                           /* alloc_streams */
115         NULL,                           /* free_streams */
116
117         NULL,                           /* dev_mem_alloc() */
118         NULL,                           /* dev_mem_free() */
119
120         NULL,                           /* kernel_driver_active() */
121         NULL,                           /* detach_kernel_driver() */
122         NULL,                           /* attach_kernel_driver() */
123
124         netbsd_destroy_device,
125
126         netbsd_submit_transfer,
127         netbsd_cancel_transfer,
128         netbsd_clear_transfer_priv,
129
130         NULL,                           /* handle_events() */
131         netbsd_handle_transfer_completion,
132
133         netbsd_clock_gettime,
134         sizeof(struct device_priv),
135         sizeof(struct handle_priv),
136         0,                              /* transfer_priv_size */
137 };
138
139 int
140 netbsd_get_device_list(struct libusb_context * ctx,
141         struct discovered_devs **discdevs)
142 {
143         struct libusb_device *dev;
144         struct device_priv *dpriv;
145         struct usb_device_info di;
146         unsigned long session_id;
147         char devnode[16];
148         int fd, err, i;
149
150         usbi_dbg("");
151
152         /* Only ugen(4) is supported */
153         for (i = 0; i < USB_MAX_DEVICES; i++) {
154                 /* Control endpoint is always .00 */
155                 snprintf(devnode, sizeof(devnode), "/dev/ugen%d.00", i);
156
157                 if ((fd = open(devnode, O_RDONLY)) < 0) {
158                         if (errno != ENOENT && errno != ENXIO)
159                                 usbi_err(ctx, "could not open %s", devnode);
160                         continue;
161                 }
162
163                 if (ioctl(fd, USB_GET_DEVICEINFO, &di) < 0)
164                         continue;
165
166                 session_id = (di.udi_bus << 8 | di.udi_addr);
167                 dev = usbi_get_device_by_session_id(ctx, session_id);
168
169                 if (dev == NULL) {
170                         dev = usbi_alloc_device(ctx, session_id);
171                         if (dev == NULL)
172                                 return (LIBUSB_ERROR_NO_MEM);
173
174                         dev->bus_number = di.udi_bus;
175                         dev->device_address = di.udi_addr;
176                         dev->speed = di.udi_speed;
177
178                         dpriv = (struct device_priv *)dev->os_priv;
179                         strlcpy(dpriv->devnode, devnode, sizeof(devnode));
180                         dpriv->fd = -1;
181
182                         if (ioctl(fd, USB_GET_DEVICE_DESC, &dpriv->ddesc) < 0) {
183                                 err = errno;
184                                 goto error;
185                         }
186
187                         dpriv->cdesc = NULL;
188                         if (_cache_active_config_descriptor(dev, fd)) {
189                                 err = errno;
190                                 goto error;
191                         }
192
193                         if ((err = usbi_sanitize_device(dev)))
194                                 goto error;
195                 }
196                 close(fd);
197
198                 if (discovered_devs_append(*discdevs, dev) == NULL)
199                         return (LIBUSB_ERROR_NO_MEM);
200
201                 libusb_unref_device(dev);
202         }
203
204         return (LIBUSB_SUCCESS);
205
206 error:
207         close(fd);
208         libusb_unref_device(dev);
209         return _errno_to_libusb(err);
210 }
211
212 int
213 netbsd_open(struct libusb_device_handle *handle)
214 {
215         struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
216         struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
217
218         dpriv->fd = open(dpriv->devnode, O_RDWR);
219         if (dpriv->fd < 0) {
220                 dpriv->fd = open(dpriv->devnode, O_RDONLY);
221                 if (dpriv->fd < 0)
222                         return _errno_to_libusb(errno);
223         }
224
225         usbi_dbg("open %s: fd %d", dpriv->devnode, dpriv->fd);
226
227         return (LIBUSB_SUCCESS);
228 }
229
230 void
231 netbsd_close(struct libusb_device_handle *handle)
232 {
233         struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
234         struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
235
236         usbi_dbg("close: fd %d", dpriv->fd);
237
238         close(dpriv->fd);
239         dpriv->fd = -1;
240 }
241
242 int
243 netbsd_get_device_descriptor(struct libusb_device *dev, unsigned char *buf,
244     int *host_endian)
245 {
246         struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
247
248         usbi_dbg("");
249
250         memcpy(buf, &dpriv->ddesc, DEVICE_DESC_LENGTH);
251
252         *host_endian = 0;
253
254         return (LIBUSB_SUCCESS);
255 }
256
257 int
258 netbsd_get_active_config_descriptor(struct libusb_device *dev,
259     unsigned char *buf, size_t len, int *host_endian)
260 {
261         struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
262         usb_config_descriptor_t *ucd;
263
264         ucd = (usb_config_descriptor_t *) dpriv->cdesc;
265         len = MIN(len, UGETW(ucd->wTotalLength));
266
267         usbi_dbg("len %d", len);
268
269         memcpy(buf, dpriv->cdesc, len);
270
271         *host_endian = 0;
272
273         return len;
274 }
275
276 int
277 netbsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
278     unsigned char *buf, size_t len, int *host_endian)
279 {
280         struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
281         struct usb_full_desc ufd;
282         int fd, err;
283
284         usbi_dbg("index %d, len %d", idx, len);
285
286         /* A config descriptor may be requested before opening the device */
287         if (dpriv->fd >= 0) {
288                 fd = dpriv->fd;
289         } else {
290                 fd = open(dpriv->devnode, O_RDONLY);
291                 if (fd < 0)
292                         return _errno_to_libusb(errno);
293         }
294
295         ufd.ufd_config_index = idx;
296         ufd.ufd_size = len;
297         ufd.ufd_data = buf;
298
299         if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
300                 err = errno;
301                 if (dpriv->fd < 0)
302                         close(fd);
303                 return _errno_to_libusb(err);
304         }
305
306         if (dpriv->fd < 0)
307                 close(fd);
308
309         *host_endian = 0;
310
311         return len;
312 }
313
314 int
315 netbsd_get_configuration(struct libusb_device_handle *handle, int *config)
316 {
317         struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
318
319         usbi_dbg("");
320
321         if (ioctl(dpriv->fd, USB_GET_CONFIG, config) < 0)
322                 return _errno_to_libusb(errno);
323
324         usbi_dbg("configuration %d", *config);
325
326         return (LIBUSB_SUCCESS);
327 }
328
329 int
330 netbsd_set_configuration(struct libusb_device_handle *handle, int config)
331 {
332         struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
333
334         usbi_dbg("configuration %d", config);
335
336         if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0)
337                 return _errno_to_libusb(errno);
338
339         return _cache_active_config_descriptor(handle->dev, dpriv->fd);
340 }
341
342 int
343 netbsd_claim_interface(struct libusb_device_handle *handle, int iface)
344 {
345         struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
346         int i;
347
348         for (i = 0; i < USB_MAX_ENDPOINTS; i++)
349                 hpriv->endpoints[i] = -1;
350
351         return (LIBUSB_SUCCESS);
352 }
353
354 int
355 netbsd_release_interface(struct libusb_device_handle *handle, int iface)
356 {
357         struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
358         int i;
359
360         for (i = 0; i < USB_MAX_ENDPOINTS; i++)
361                 if (hpriv->endpoints[i] >= 0)
362                         close(hpriv->endpoints[i]);
363
364         return (LIBUSB_SUCCESS);
365 }
366
367 int
368 netbsd_set_interface_altsetting(struct libusb_device_handle *handle, int iface,
369     int altsetting)
370 {
371         struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
372         struct usb_alt_interface intf;
373
374         usbi_dbg("iface %d, setting %d", iface, altsetting);
375
376         memset(&intf, 0, sizeof(intf));
377
378         intf.uai_interface_index = iface;
379         intf.uai_alt_no = altsetting;
380
381         if (ioctl(dpriv->fd, USB_SET_ALTINTERFACE, &intf) < 0)
382                 return _errno_to_libusb(errno);
383
384         return (LIBUSB_SUCCESS);
385 }
386
387 int
388 netbsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
389 {
390         struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
391         struct usb_ctl_request req;
392
393         usbi_dbg("");
394
395         req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT;
396         req.ucr_request.bRequest = UR_CLEAR_FEATURE;
397         USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT);
398         USETW(req.ucr_request.wIndex, endpoint);
399         USETW(req.ucr_request.wLength, 0);
400
401         if (ioctl(dpriv->fd, USB_DO_REQUEST, &req) < 0)
402                 return _errno_to_libusb(errno);
403
404         return (LIBUSB_SUCCESS);
405 }
406
407 int
408 netbsd_reset_device(struct libusb_device_handle *handle)
409 {
410         usbi_dbg("");
411
412         return (LIBUSB_ERROR_NOT_SUPPORTED);
413 }
414
415 void
416 netbsd_destroy_device(struct libusb_device *dev)
417 {
418         struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
419
420         usbi_dbg("");
421
422         free(dpriv->cdesc);
423 }
424
425 int
426 netbsd_submit_transfer(struct usbi_transfer *itransfer)
427 {
428         struct libusb_transfer *transfer;
429         struct handle_priv *hpriv;
430         int err = 0;
431
432         usbi_dbg("");
433
434         transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
435         hpriv = (struct handle_priv *)transfer->dev_handle->os_priv;
436
437         switch (transfer->type) {
438         case LIBUSB_TRANSFER_TYPE_CONTROL:
439                 err = _sync_control_transfer(itransfer);
440                 break;
441         case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
442                 if (IS_XFEROUT(transfer)) {
443                         /* Isochronous write is not supported */
444                         err = LIBUSB_ERROR_NOT_SUPPORTED;
445                         break;
446                 }
447                 err = _sync_gen_transfer(itransfer);
448                 break;
449         case LIBUSB_TRANSFER_TYPE_BULK:
450         case LIBUSB_TRANSFER_TYPE_INTERRUPT:
451                 if (IS_XFEROUT(transfer) &&
452                     transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
453                         err = LIBUSB_ERROR_NOT_SUPPORTED;
454                         break;
455                 }
456                 err = _sync_gen_transfer(itransfer);
457                 break;
458         case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
459                 err = LIBUSB_ERROR_NOT_SUPPORTED;
460                 break;
461         }
462
463         if (err)
464                 return (err);
465
466         usbi_signal_transfer_completion(itransfer);
467
468         return (LIBUSB_SUCCESS);
469 }
470
471 int
472 netbsd_cancel_transfer(struct usbi_transfer *itransfer)
473 {
474         usbi_dbg("");
475
476         return (LIBUSB_ERROR_NOT_SUPPORTED);
477 }
478
479 void
480 netbsd_clear_transfer_priv(struct usbi_transfer *itransfer)
481 {
482         usbi_dbg("");
483
484         /* Nothing to do */
485 }
486
487 int
488 netbsd_handle_transfer_completion(struct usbi_transfer *itransfer)
489 {
490         return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
491 }
492
493 int
494 netbsd_clock_gettime(int clkid, struct timespec *tp)
495 {
496         usbi_dbg("clock %d", clkid);
497
498         if (clkid == USBI_CLOCK_REALTIME)
499                 return clock_gettime(CLOCK_REALTIME, tp);
500
501         if (clkid == USBI_CLOCK_MONOTONIC)
502                 return clock_gettime(CLOCK_MONOTONIC, tp);
503
504         return (LIBUSB_ERROR_INVALID_PARAM);
505 }
506
507 int
508 _errno_to_libusb(int err)
509 {
510         switch (err) {
511         case EIO:
512                 return (LIBUSB_ERROR_IO);
513         case EACCES:
514                 return (LIBUSB_ERROR_ACCESS);
515         case ENOENT:
516                 return (LIBUSB_ERROR_NO_DEVICE);
517         case ENOMEM:
518                 return (LIBUSB_ERROR_NO_MEM);
519         }
520
521         usbi_dbg("error: %s", strerror(err));
522
523         return (LIBUSB_ERROR_OTHER);
524 }
525
526 int
527 _cache_active_config_descriptor(struct libusb_device *dev, int fd)
528 {
529         struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
530         struct usb_config_desc ucd;
531         struct usb_full_desc ufd;
532         unsigned char* buf;
533         int len;
534
535         usbi_dbg("fd %d", fd);
536
537         ucd.ucd_config_index = USB_CURRENT_CONFIG_INDEX;
538
539         if ((ioctl(fd, USB_GET_CONFIG_DESC, &ucd)) < 0)
540                 return _errno_to_libusb(errno);
541
542         usbi_dbg("active bLength %d", ucd.ucd_desc.bLength);
543
544         len = UGETW(ucd.ucd_desc.wTotalLength);
545         buf = malloc(len);
546         if (buf == NULL)
547                 return (LIBUSB_ERROR_NO_MEM);
548
549         ufd.ufd_config_index = ucd.ucd_config_index;
550         ufd.ufd_size = len;
551         ufd.ufd_data = buf;
552
553         usbi_dbg("index %d, len %d", ufd.ufd_config_index, len);
554
555         if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
556                 free(buf);
557                 return _errno_to_libusb(errno);
558         }
559
560         if (dpriv->cdesc)
561                 free(dpriv->cdesc);
562         dpriv->cdesc = buf;
563
564         return (0);
565 }
566
567 int
568 _sync_control_transfer(struct usbi_transfer *itransfer)
569 {
570         struct libusb_transfer *transfer;
571         struct libusb_control_setup *setup;
572         struct device_priv *dpriv;
573         struct usb_ctl_request req;
574
575         transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
576         dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;
577         setup = (struct libusb_control_setup *)transfer->buffer;
578
579         usbi_dbg("type %d request %d value %d index %d length %d timeout %d",
580             setup->bmRequestType, setup->bRequest,
581             libusb_le16_to_cpu(setup->wValue),
582             libusb_le16_to_cpu(setup->wIndex),
583             libusb_le16_to_cpu(setup->wLength), transfer->timeout);
584
585         req.ucr_request.bmRequestType = setup->bmRequestType;
586         req.ucr_request.bRequest = setup->bRequest;
587         /* Don't use USETW, libusb already deals with the endianness */
588         (*(uint16_t *)req.ucr_request.wValue) = setup->wValue;
589         (*(uint16_t *)req.ucr_request.wIndex) = setup->wIndex;
590         (*(uint16_t *)req.ucr_request.wLength) = setup->wLength;
591         req.ucr_data = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
592
593         if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
594                 req.ucr_flags = USBD_SHORT_XFER_OK;
595
596         if ((ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
597                 return _errno_to_libusb(errno);
598
599         if ((ioctl(dpriv->fd, USB_DO_REQUEST, &req)) < 0)
600                 return _errno_to_libusb(errno);
601
602         itransfer->transferred = req.ucr_actlen;
603
604         usbi_dbg("transferred %d", itransfer->transferred);
605
606         return (0);
607 }
608
609 int
610 _access_endpoint(struct libusb_transfer *transfer)
611 {
612         struct handle_priv *hpriv;
613         struct device_priv *dpriv;
614         char *s, devnode[16];
615         int fd, endpt;
616         mode_t mode;
617
618         hpriv = (struct handle_priv *)transfer->dev_handle->os_priv;
619         dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;
620
621         endpt = UE_GET_ADDR(transfer->endpoint);
622         mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;
623
624         usbi_dbg("endpoint %d mode %d", endpt, mode);
625
626         if (hpriv->endpoints[endpt] < 0) {
627                 /* Pick the right node given the control one */
628                 strlcpy(devnode, dpriv->devnode, sizeof(devnode));
629                 s = strchr(devnode, '.');
630                 snprintf(s, 4, ".%02d", endpt);
631
632                 /* We may need to read/write to the same endpoint later. */
633                 if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
634                         if ((fd = open(devnode, mode)) < 0)
635                                 return (-1);
636
637                 hpriv->endpoints[endpt] = fd;
638         }
639
640         return (hpriv->endpoints[endpt]);
641 }
642
643 int
644 _sync_gen_transfer(struct usbi_transfer *itransfer)
645 {
646         struct libusb_transfer *transfer;
647         int fd, nr = 1;
648
649         transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
650
651         /*
652          * Bulk, Interrupt or Isochronous transfer depends on the
653          * endpoint and thus the node to open.
654          */
655         if ((fd = _access_endpoint(transfer)) < 0)
656                 return _errno_to_libusb(errno);
657
658         if ((ioctl(fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
659                 return _errno_to_libusb(errno);
660
661         if (IS_XFERIN(transfer)) {
662                 if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
663                         if ((ioctl(fd, USB_SET_SHORT_XFER, &nr)) < 0)
664                                 return _errno_to_libusb(errno);
665
666                 nr = read(fd, transfer->buffer, transfer->length);
667         } else {
668                 nr = write(fd, transfer->buffer, transfer->length);
669         }
670
671         if (nr < 0)
672                 return _errno_to_libusb(errno);
673
674         itransfer->transferred = nr;
675
676         return (0);
677 }