core: Change pointer type from 'unsigned char' to 'void'
[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         usb_config_descriptor_t *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 *, void *,
56     int *);
57 static int netbsd_get_active_config_descriptor(struct libusb_device *,
58     void *, size_t);
59 static int netbsd_get_config_descriptor(struct libusb_device *, uint8_t,
60     void *, size_t);
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                         if (_cache_active_config_descriptor(dev, fd)) {
166                                 err = errno;
167                                 goto error;
168                         }
169
170                         if ((err = usbi_sanitize_device(dev)))
171                                 goto error;
172                 }
173                 close(fd);
174
175                 if (discovered_devs_append(*discdevs, dev) == NULL)
176                         return (LIBUSB_ERROR_NO_MEM);
177
178                 libusb_unref_device(dev);
179         }
180
181         return (LIBUSB_SUCCESS);
182
183 error:
184         close(fd);
185         libusb_unref_device(dev);
186         return _errno_to_libusb(err);
187 }
188
189 int
190 netbsd_open(struct libusb_device_handle *handle)
191 {
192         struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
193         struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
194         int i;
195
196         dpriv->fd = open(dpriv->devnode, O_RDWR);
197         if (dpriv->fd < 0) {
198                 dpriv->fd = open(dpriv->devnode, O_RDONLY);
199                 if (dpriv->fd < 0)
200                         return _errno_to_libusb(errno);
201         }
202
203         for (i = 0; i < USB_MAX_ENDPOINTS; i++)
204                 hpriv->endpoints[i] = -1;
205
206         usbi_dbg("open %s: fd %d", dpriv->devnode, dpriv->fd);
207
208         return (LIBUSB_SUCCESS);
209 }
210
211 void
212 netbsd_close(struct libusb_device_handle *handle)
213 {
214         struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
215
216         usbi_dbg("close: fd %d", dpriv->fd);
217
218         close(dpriv->fd);
219         dpriv->fd = -1;
220 }
221
222 int
223 netbsd_get_device_descriptor(struct libusb_device *dev, void *buf,
224     int *host_endian)
225 {
226         struct device_priv *dpriv = usbi_get_device_priv(dev);
227
228         usbi_dbg(" ");
229
230         memcpy(buf, &dpriv->ddesc, LIBUSB_DT_DEVICE_SIZE);
231
232         return (LIBUSB_SUCCESS);
233 }
234
235 int
236 netbsd_get_active_config_descriptor(struct libusb_device *dev,
237     void *buf, size_t len)
238 {
239         struct device_priv *dpriv = usbi_get_device_priv(dev);
240
241         len = MIN(len, UGETW(dpriv->cdesc->wTotalLength));
242
243         usbi_dbg("len %d", len);
244
245         memcpy(buf, dpriv->cdesc, len);
246
247         return len;
248 }
249
250 int
251 netbsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
252     void *buf, size_t len)
253 {
254         struct device_priv *dpriv = usbi_get_device_priv(dev);
255         struct usb_full_desc ufd;
256         int fd, err;
257
258         usbi_dbg("index %d, len %d", idx, len);
259
260         /* A config descriptor may be requested before opening the device */
261         if (dpriv->fd >= 0) {
262                 fd = dpriv->fd;
263         } else {
264                 fd = open(dpriv->devnode, O_RDONLY);
265                 if (fd < 0)
266                         return _errno_to_libusb(errno);
267         }
268
269         ufd.ufd_config_index = idx;
270         ufd.ufd_size = len;
271         ufd.ufd_data = buf;
272
273         if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
274                 err = errno;
275                 if (dpriv->fd < 0)
276                         close(fd);
277                 return _errno_to_libusb(err);
278         }
279
280         if (dpriv->fd < 0)
281                 close(fd);
282
283         return len;
284 }
285
286 int
287 netbsd_get_configuration(struct libusb_device_handle *handle, int *config)
288 {
289         struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
290
291         usbi_dbg(" ");
292
293         if (ioctl(dpriv->fd, USB_GET_CONFIG, config) < 0)
294                 return _errno_to_libusb(errno);
295
296         usbi_dbg("configuration %d", *config);
297
298         return (LIBUSB_SUCCESS);
299 }
300
301 int
302 netbsd_set_configuration(struct libusb_device_handle *handle, int config)
303 {
304         struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
305
306         usbi_dbg("configuration %d", config);
307
308         if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0)
309                 return _errno_to_libusb(errno);
310
311         return _cache_active_config_descriptor(handle->dev, dpriv->fd);
312 }
313
314 int
315 netbsd_claim_interface(struct libusb_device_handle *handle, int iface)
316 {
317         struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
318         int i;
319
320         for (i = 0; i < USB_MAX_ENDPOINTS; i++)
321                 hpriv->endpoints[i] = -1;
322
323         return (LIBUSB_SUCCESS);
324 }
325
326 int
327 netbsd_release_interface(struct libusb_device_handle *handle, int iface)
328 {
329         struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
330         int i;
331
332         for (i = 0; i < USB_MAX_ENDPOINTS; i++)
333                 if (hpriv->endpoints[i] >= 0)
334                         close(hpriv->endpoints[i]);
335
336         return (LIBUSB_SUCCESS);
337 }
338
339 int
340 netbsd_set_interface_altsetting(struct libusb_device_handle *handle, int iface,
341     int altsetting)
342 {
343         struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
344         struct usb_alt_interface intf;
345
346         usbi_dbg("iface %d, setting %d", iface, altsetting);
347
348         memset(&intf, 0, sizeof(intf));
349
350         intf.uai_interface_index = iface;
351         intf.uai_alt_no = altsetting;
352
353         if (ioctl(dpriv->fd, USB_SET_ALTINTERFACE, &intf) < 0)
354                 return _errno_to_libusb(errno);
355
356         return (LIBUSB_SUCCESS);
357 }
358
359 int
360 netbsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
361 {
362         struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
363         struct usb_ctl_request req;
364
365         usbi_dbg(" ");
366
367         req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT;
368         req.ucr_request.bRequest = UR_CLEAR_FEATURE;
369         USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT);
370         USETW(req.ucr_request.wIndex, endpoint);
371         USETW(req.ucr_request.wLength, 0);
372
373         if (ioctl(dpriv->fd, USB_DO_REQUEST, &req) < 0)
374                 return _errno_to_libusb(errno);
375
376         return (LIBUSB_SUCCESS);
377 }
378
379 void
380 netbsd_destroy_device(struct libusb_device *dev)
381 {
382         struct device_priv *dpriv = usbi_get_device_priv(dev);
383
384         usbi_dbg(" ");
385
386         free(dpriv->cdesc);
387 }
388
389 int
390 netbsd_submit_transfer(struct usbi_transfer *itransfer)
391 {
392         struct libusb_transfer *transfer;
393         struct handle_priv *hpriv;
394         int err = 0;
395
396         usbi_dbg(" ");
397
398         transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
399         hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
400
401         switch (transfer->type) {
402         case LIBUSB_TRANSFER_TYPE_CONTROL:
403                 err = _sync_control_transfer(itransfer);
404                 break;
405         case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
406                 if (IS_XFEROUT(transfer)) {
407                         /* Isochronous write is not supported */
408                         err = LIBUSB_ERROR_NOT_SUPPORTED;
409                         break;
410                 }
411                 err = _sync_gen_transfer(itransfer);
412                 break;
413         case LIBUSB_TRANSFER_TYPE_BULK:
414         case LIBUSB_TRANSFER_TYPE_INTERRUPT:
415                 if (IS_XFEROUT(transfer) &&
416                     transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
417                         err = LIBUSB_ERROR_NOT_SUPPORTED;
418                         break;
419                 }
420                 err = _sync_gen_transfer(itransfer);
421                 break;
422         case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
423                 err = LIBUSB_ERROR_NOT_SUPPORTED;
424                 break;
425         }
426
427         if (err)
428                 return (err);
429
430         usbi_signal_transfer_completion(itransfer);
431
432         return (LIBUSB_SUCCESS);
433 }
434
435 int
436 netbsd_cancel_transfer(struct usbi_transfer *itransfer)
437 {
438         usbi_dbg(" ");
439
440         return (LIBUSB_ERROR_NOT_SUPPORTED);
441 }
442
443 int
444 netbsd_handle_transfer_completion(struct usbi_transfer *itransfer)
445 {
446         return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
447 }
448
449 int
450 _errno_to_libusb(int err)
451 {
452         switch (err) {
453         case EIO:
454                 return (LIBUSB_ERROR_IO);
455         case EACCES:
456                 return (LIBUSB_ERROR_ACCESS);
457         case ENOENT:
458                 return (LIBUSB_ERROR_NO_DEVICE);
459         case ENOMEM:
460                 return (LIBUSB_ERROR_NO_MEM);
461         case EWOULDBLOCK:
462         case ETIMEDOUT:
463                 return (LIBUSB_ERROR_TIMEOUT);
464         }
465
466         usbi_dbg("error: %s", strerror(err));
467
468         return (LIBUSB_ERROR_OTHER);
469 }
470
471 int
472 _cache_active_config_descriptor(struct libusb_device *dev, int fd)
473 {
474         struct device_priv *dpriv = usbi_get_device_priv(dev);
475         struct usb_config_desc ucd;
476         struct usb_full_desc ufd;
477         void *buf;
478         int len;
479
480         usbi_dbg("fd %d", fd);
481
482         ucd.ucd_config_index = USB_CURRENT_CONFIG_INDEX;
483
484         if ((ioctl(fd, USB_GET_CONFIG_DESC, &ucd)) < 0)
485                 return _errno_to_libusb(errno);
486
487         usbi_dbg("active bLength %d", ucd.ucd_desc.bLength);
488
489         len = UGETW(ucd.ucd_desc.wTotalLength);
490         buf = malloc((size_t)len);
491         if (buf == NULL)
492                 return (LIBUSB_ERROR_NO_MEM);
493
494         ufd.ufd_config_index = ucd.ucd_config_index;
495         ufd.ufd_size = len;
496         ufd.ufd_data = buf;
497
498         usbi_dbg("index %d, len %d", ufd.ufd_config_index, len);
499
500         if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
501                 free(buf);
502                 return _errno_to_libusb(errno);
503         }
504
505         if (dpriv->cdesc)
506                 free(dpriv->cdesc);
507         dpriv->cdesc = buf;
508
509         return (0);
510 }
511
512 int
513 _sync_control_transfer(struct usbi_transfer *itransfer)
514 {
515         struct libusb_transfer *transfer;
516         struct libusb_control_setup *setup;
517         struct device_priv *dpriv;
518         struct usb_ctl_request req;
519
520         transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
521         dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
522         setup = (struct libusb_control_setup *)transfer->buffer;
523
524         usbi_dbg("type %d request %d value %d index %d length %d timeout %d",
525             setup->bmRequestType, setup->bRequest,
526             libusb_le16_to_cpu(setup->wValue),
527             libusb_le16_to_cpu(setup->wIndex),
528             libusb_le16_to_cpu(setup->wLength), transfer->timeout);
529
530         req.ucr_request.bmRequestType = setup->bmRequestType;
531         req.ucr_request.bRequest = setup->bRequest;
532         /* Don't use USETW, libusb already deals with the endianness */
533         (*(uint16_t *)req.ucr_request.wValue) = setup->wValue;
534         (*(uint16_t *)req.ucr_request.wIndex) = setup->wIndex;
535         (*(uint16_t *)req.ucr_request.wLength) = setup->wLength;
536         req.ucr_data = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
537
538         if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
539                 req.ucr_flags = USBD_SHORT_XFER_OK;
540
541         if ((ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
542                 return _errno_to_libusb(errno);
543
544         if ((ioctl(dpriv->fd, USB_DO_REQUEST, &req)) < 0)
545                 return _errno_to_libusb(errno);
546
547         itransfer->transferred = req.ucr_actlen;
548
549         usbi_dbg("transferred %d", itransfer->transferred);
550
551         return (0);
552 }
553
554 int
555 _access_endpoint(struct libusb_transfer *transfer)
556 {
557         struct handle_priv *hpriv;
558         struct device_priv *dpriv;
559         char *s, devnode[16];
560         int fd, endpt;
561         mode_t mode;
562
563         hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
564         dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
565
566         endpt = UE_GET_ADDR(transfer->endpoint);
567         mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;
568
569         usbi_dbg("endpoint %d mode %d", endpt, mode);
570
571         if (hpriv->endpoints[endpt] < 0) {
572                 /* Pick the right node given the control one */
573                 strlcpy(devnode, dpriv->devnode, sizeof(devnode));
574                 s = strchr(devnode, '.');
575                 snprintf(s, 4, ".%02d", endpt);
576
577                 /* We may need to read/write to the same endpoint later. */
578                 if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
579                         if ((fd = open(devnode, mode)) < 0)
580                                 return (-1);
581
582                 hpriv->endpoints[endpt] = fd;
583         }
584
585         return (hpriv->endpoints[endpt]);
586 }
587
588 int
589 _sync_gen_transfer(struct usbi_transfer *itransfer)
590 {
591         struct libusb_transfer *transfer;
592         int fd, nr = 1;
593
594         transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
595
596         /*
597          * Bulk, Interrupt or Isochronous transfer depends on the
598          * endpoint and thus the node to open.
599          */
600         if ((fd = _access_endpoint(transfer)) < 0)
601                 return _errno_to_libusb(errno);
602
603         if ((ioctl(fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
604                 return _errno_to_libusb(errno);
605
606         if (IS_XFERIN(transfer)) {
607                 if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
608                         if ((ioctl(fd, USB_SET_SHORT_XFER, &nr)) < 0)
609                                 return _errno_to_libusb(errno);
610
611                 nr = read(fd, transfer->buffer, transfer->length);
612         } else {
613                 nr = write(fd, transfer->buffer, transfer->length);
614         }
615
616         if (nr < 0)
617                 return _errno_to_libusb(errno);
618
619         itransfer->transferred = nr;
620
621         return (0);
622 }