core: Make the 'reset_device' function of the backend optional
[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         }
471
472         usbi_dbg("error: %s", strerror(err));
473
474         return (LIBUSB_ERROR_OTHER);
475 }
476
477 int
478 _cache_active_config_descriptor(struct libusb_device *dev, int fd)
479 {
480         struct device_priv *dpriv = usbi_get_device_priv(dev);
481         struct usb_config_desc ucd;
482         struct usb_full_desc ufd;
483         unsigned char* buf;
484         int len;
485
486         usbi_dbg("fd %d", fd);
487
488         ucd.ucd_config_index = USB_CURRENT_CONFIG_INDEX;
489
490         if ((ioctl(fd, USB_GET_CONFIG_DESC, &ucd)) < 0)
491                 return _errno_to_libusb(errno);
492
493         usbi_dbg("active bLength %d", ucd.ucd_desc.bLength);
494
495         len = UGETW(ucd.ucd_desc.wTotalLength);
496         buf = malloc(len);
497         if (buf == NULL)
498                 return (LIBUSB_ERROR_NO_MEM);
499
500         ufd.ufd_config_index = ucd.ucd_config_index;
501         ufd.ufd_size = len;
502         ufd.ufd_data = buf;
503
504         usbi_dbg("index %d, len %d", ufd.ufd_config_index, len);
505
506         if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
507                 free(buf);
508                 return _errno_to_libusb(errno);
509         }
510
511         if (dpriv->cdesc)
512                 free(dpriv->cdesc);
513         dpriv->cdesc = buf;
514
515         return (0);
516 }
517
518 int
519 _sync_control_transfer(struct usbi_transfer *itransfer)
520 {
521         struct libusb_transfer *transfer;
522         struct libusb_control_setup *setup;
523         struct device_priv *dpriv;
524         struct usb_ctl_request req;
525
526         transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
527         dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
528         setup = (struct libusb_control_setup *)transfer->buffer;
529
530         usbi_dbg("type %d request %d value %d index %d length %d timeout %d",
531             setup->bmRequestType, setup->bRequest,
532             libusb_le16_to_cpu(setup->wValue),
533             libusb_le16_to_cpu(setup->wIndex),
534             libusb_le16_to_cpu(setup->wLength), transfer->timeout);
535
536         req.ucr_request.bmRequestType = setup->bmRequestType;
537         req.ucr_request.bRequest = setup->bRequest;
538         /* Don't use USETW, libusb already deals with the endianness */
539         (*(uint16_t *)req.ucr_request.wValue) = setup->wValue;
540         (*(uint16_t *)req.ucr_request.wIndex) = setup->wIndex;
541         (*(uint16_t *)req.ucr_request.wLength) = setup->wLength;
542         req.ucr_data = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
543
544         if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
545                 req.ucr_flags = USBD_SHORT_XFER_OK;
546
547         if ((ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
548                 return _errno_to_libusb(errno);
549
550         if ((ioctl(dpriv->fd, USB_DO_REQUEST, &req)) < 0)
551                 return _errno_to_libusb(errno);
552
553         itransfer->transferred = req.ucr_actlen;
554
555         usbi_dbg("transferred %d", itransfer->transferred);
556
557         return (0);
558 }
559
560 int
561 _access_endpoint(struct libusb_transfer *transfer)
562 {
563         struct handle_priv *hpriv;
564         struct device_priv *dpriv;
565         char *s, devnode[16];
566         int fd, endpt;
567         mode_t mode;
568
569         hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
570         dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
571
572         endpt = UE_GET_ADDR(transfer->endpoint);
573         mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;
574
575         usbi_dbg("endpoint %d mode %d", endpt, mode);
576
577         if (hpriv->endpoints[endpt] < 0) {
578                 /* Pick the right node given the control one */
579                 strlcpy(devnode, dpriv->devnode, sizeof(devnode));
580                 s = strchr(devnode, '.');
581                 snprintf(s, 4, ".%02d", endpt);
582
583                 /* We may need to read/write to the same endpoint later. */
584                 if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
585                         if ((fd = open(devnode, mode)) < 0)
586                                 return (-1);
587
588                 hpriv->endpoints[endpt] = fd;
589         }
590
591         return (hpriv->endpoints[endpt]);
592 }
593
594 int
595 _sync_gen_transfer(struct usbi_transfer *itransfer)
596 {
597         struct libusb_transfer *transfer;
598         int fd, nr = 1;
599
600         transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
601
602         /*
603          * Bulk, Interrupt or Isochronous transfer depends on the
604          * endpoint and thus the node to open.
605          */
606         if ((fd = _access_endpoint(transfer)) < 0)
607                 return _errno_to_libusb(errno);
608
609         if ((ioctl(fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
610                 return _errno_to_libusb(errno);
611
612         if (IS_XFERIN(transfer)) {
613                 if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
614                         if ((ioctl(fd, USB_SET_SHORT_XFER, &nr)) < 0)
615                                 return _errno_to_libusb(errno);
616
617                 nr = read(fd, transfer->buffer, transfer->length);
618         } else {
619                 nr = write(fd, transfer->buffer, transfer->length);
620         }
621
622         if (nr < 0)
623                 return _errno_to_libusb(errno);
624
625         itransfer->transferred = nr;
626
627         return (0);
628 }