1 /*
2 *
3 * Copyright (c) 2016, Oracle and/or its affiliates.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library 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 GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include <config.h>
21
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <strings.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <aio.h>
33 #include <libdevinfo.h>
34 #include <sys/usb/clients/ugen/usb_ugen.h>
35 #include <sys/usb/usba.h>
36 #include <sys/pci.h>
37
38 #include "libusbi.h"
39 #include "sunos_usb.h"
40
41 /*
42 * Backend functions
43 */
44 static int sunos_init(struct libusb_context *);
45 static void sunos_exit(void);
46 static int sunos_get_device_list(struct libusb_context *,
47 struct discovered_devs **);
48 static int sunos_open(struct libusb_device_handle *);
49 static void sunos_close(struct libusb_device_handle *);
50 static int sunos_get_device_descriptor(struct libusb_device *,
51 uint8_t*, int *);
52 static int sunos_get_active_config_descriptor(struct libusb_device *,
53 uint8_t*, size_t, int *);
54 static int sunos_get_config_descriptor(struct libusb_device *, uint8_t,
55 uint8_t*, size_t, int *);
56 static int sunos_get_configuration(struct libusb_device_handle *, int *);
57 static int sunos_set_configuration(struct libusb_device_handle *, int);
58 static int sunos_claim_interface(struct libusb_device_handle *, int);
59 static int sunos_release_interface(struct libusb_device_handle *, int);
60 static int sunos_set_interface_altsetting(struct libusb_device_handle *,
61 int, int);
62 static int sunos_clear_halt(struct libusb_device_handle *, uint8_t);
63 static int sunos_reset_device(struct libusb_device_handle *);
64 static void sunos_destroy_device(struct libusb_device *);
65 static int sunos_submit_transfer(struct usbi_transfer *);
66 static int sunos_cancel_transfer(struct usbi_transfer *);
67 static void sunos_clear_transfer_priv(struct usbi_transfer *);
68 static int sunos_handle_transfer_completion(struct usbi_transfer *);
69 static int sunos_clock_gettime(int, struct timespec *);
70
71 /*
72 * Private functions
73 */
74 static int _errno_to_libusb(int);
75 static int sunos_usb_get_status(int fd);
76
sunos_init(struct libusb_context * ctx)77 static int sunos_init(struct libusb_context *ctx)
78 {
79 return (LIBUSB_SUCCESS);
80 }
81
sunos_exit(void)82 static void sunos_exit(void)
83 {
84 usbi_dbg("");
85 }
86
87 static int
sunos_fill_in_dev_info(di_node_t node,struct libusb_device * dev)88 sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev)
89 {
90 int proplen;
91 int n, *addr, *port_prop;
92 char *phypath;
93 uint8_t *rdata;
94 struct libusb_device_descriptor *descr;
95 sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv;
96
97 /* Device descriptors */
98 proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
99 "usb-dev-descriptor", &rdata);
100 if (proplen <= 0) {
101
102 return (LIBUSB_ERROR_IO);
103 }
104
105 descr = (struct libusb_device_descriptor *)rdata;
106 bcopy(descr, &dpriv->dev_descr, LIBUSB_DT_DEVICE_SIZE);
107 dpriv->dev_descr.bcdUSB = libusb_cpu_to_le16(descr->bcdUSB);
108 dpriv->dev_descr.idVendor = libusb_cpu_to_le16(descr->idVendor);
109 dpriv->dev_descr.idProduct = libusb_cpu_to_le16(descr->idProduct);
110 dpriv->dev_descr.bcdDevice = libusb_cpu_to_le16(descr->bcdDevice);
111
112 /* Raw configuration descriptors */
113 proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
114 "usb-raw-cfg-descriptors", &rdata);
115 if (proplen <= 0) {
116 usbi_dbg("can't find raw config descriptors");
117
118 return (LIBUSB_ERROR_IO);
119 }
120 dpriv->raw_cfgdescr = calloc(1, proplen);
121 if (dpriv->raw_cfgdescr == NULL) {
122 return (LIBUSB_ERROR_NO_MEM);
123 } else {
124 bcopy(rdata, dpriv->raw_cfgdescr, proplen);
125 dpriv->cfgvalue = ((struct libusb_config_descriptor *)
126 rdata)->bConfigurationValue;
127 }
128
129 n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &port_prop);
130
131 if ((n != 1) || (*port_prop <= 0)) {
132 return (LIBUSB_ERROR_IO);
133 }
134 dev->port_number = *port_prop;
135
136 /* device physical path */
137 phypath = di_devfs_path(node);
138 if (phypath) {
139 dpriv->phypath = strdup(phypath);
140 di_devfs_path_free(phypath);
141 } else {
142 free(dpriv->raw_cfgdescr);
143
144 return (LIBUSB_ERROR_IO);
145 }
146
147 /* address */
148 n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "assigned-address", &addr);
149 if (n != 1 || *addr == 0) {
150 usbi_dbg("can't get address");
151 } else {
152 dev->device_address = *addr;
153 }
154
155 /* speed */
156 if (di_prop_exists(DDI_DEV_T_ANY, node, "low-speed") == 1) {
157 dev->speed = LIBUSB_SPEED_LOW;
158 } else if (di_prop_exists(DDI_DEV_T_ANY, node, "high-speed") == 1) {
159 dev->speed = LIBUSB_SPEED_HIGH;
160 } else if (di_prop_exists(DDI_DEV_T_ANY, node, "full-speed") == 1) {
161 dev->speed = LIBUSB_SPEED_FULL;
162 } else if (di_prop_exists(DDI_DEV_T_ANY, node, "super-speed") == 1) {
163 dev->speed = LIBUSB_SPEED_SUPER;
164 }
165
166 usbi_dbg("vid=%x pid=%x, path=%s, bus_nmber=0x%x, port_number=%d, "
167 "speed=%d", dpriv->dev_descr.idVendor, dpriv->dev_descr.idProduct,
168 dpriv->phypath, dev->bus_number, dev->port_number, dev->speed);
169
170 return (LIBUSB_SUCCESS);
171 }
172
173
174 static int
sunos_add_devices(di_devlink_t link,void * arg)175 sunos_add_devices(di_devlink_t link, void *arg)
176 {
177 struct devlink_cbarg *largs = (struct devlink_cbarg *)arg;
178 struct node_args *nargs;
179 di_node_t myself, pnode;
180 uint64_t session_id = 0;
181 uint16_t bdf = 0;
182 struct libusb_device *dev;
183 sunos_dev_priv_t *devpriv;
184 const char *path, *newpath;
185 int n, i;
186 int *addr_prop;
187 uint8_t bus_number = 0;
188
189 nargs = (struct node_args *)largs->nargs;
190 myself = largs->myself;
191 if (nargs->last_ugenpath) {
192 /* the same node's links */
193 return (DI_WALK_CONTINUE);
194 }
195
196 /*
197 * Construct session ID.
198 * session ID = ...parent hub addr|hub addr|dev addr.
199 */
200 pnode = myself;
201 i = 0;
202 while (pnode != DI_NODE_NIL) {
203 if (di_prop_exists(DDI_DEV_T_ANY, pnode, "root-hub") == 1) {
204 /* walk to root */
205 uint32_t *regbuf = NULL;
206 uint32_t reg;
207
208 n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode, "reg",
209 (int **)®buf);
210 reg = regbuf[0];
211 bdf = (PCI_REG_BUS_G(reg) << 8) |
212 (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
213 session_id |= (bdf << i * 8);
214
215 /* same as 'unit-address' property */
216 bus_number =
217 (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
218
219 usbi_dbg("device bus address=%s:%x",
220 di_bus_addr(pnode), bus_number);
221
222 break;
223 }
224
225 /* usb_addr */
226 n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode,
227 "assigned-address", &addr_prop);
228 if ((n != 1) || (addr_prop[0] == 0)) {
229 usbi_dbg("cannot get valid usb_addr");
230
231 return (DI_WALK_CONTINUE);
232 }
233
234 session_id |= ((addr_prop[0] & 0xff) << i * 8);
235 if (++i > 7)
236 break;
237
238 pnode = di_parent_node(pnode);
239 }
240
241 path = di_devlink_path(link);
242 dev = usbi_get_device_by_session_id(nargs->ctx, session_id);
243 if (dev == NULL) {
244 dev = usbi_alloc_device(nargs->ctx, session_id);
245 if (dev == NULL) {
246 usbi_dbg("can't alloc device");
247
248 return (DI_WALK_TERMINATE);
249 }
250 devpriv = (sunos_dev_priv_t *)dev->os_priv;
251 if ((newpath = strrchr(path, '/')) == NULL) {
252 libusb_unref_device(dev);
253
254 return (DI_WALK_TERMINATE);
255 }
256 devpriv->ugenpath = strndup(path, strlen(path) -
257 strlen(newpath));
258 dev->bus_number = bus_number;
259
260 if (sunos_fill_in_dev_info(myself, dev) != LIBUSB_SUCCESS) {
261 libusb_unref_device(dev);
262
263 return (DI_WALK_TERMINATE);
264 }
265 if (usbi_sanitize_device(dev) < 0) {
266 libusb_unref_device(dev);
267 usbi_dbg("sanatize failed: ");
268 return (DI_WALK_TERMINATE);
269 }
270 } else {
271 usbi_dbg("Dev %s exists", path);
272 }
273
274 devpriv = (sunos_dev_priv_t *)dev->os_priv;
275 if (nargs->last_ugenpath == NULL) {
276 /* first device */
277 nargs->last_ugenpath = devpriv->ugenpath;
278
279 if (discovered_devs_append(*(nargs->discdevs), dev) == NULL) {
280 usbi_dbg("cannot append device");
281 }
282
283 /*
284 * we alloc and hence ref this dev. We don't need to ref it
285 * hereafter. Front end or app should take care of their ref.
286 */
287 libusb_unref_device(dev);
288 }
289
290 usbi_dbg("Device %s %s id=0x%llx, devcount:%d, bdf=%x",
291 devpriv->ugenpath, path, (uint64_t)session_id,
292 (*nargs->discdevs)->len, bdf);
293
294 return (DI_WALK_CONTINUE);
295 }
296
297 static int
sunos_walk_minor_node_link(di_node_t node,void * args)298 sunos_walk_minor_node_link(di_node_t node, void *args)
299 {
300 di_minor_t minor = DI_MINOR_NIL;
301 char *minor_path;
302 struct devlink_cbarg arg;
303 struct node_args *nargs = (struct node_args *)args;
304 di_devlink_handle_t devlink_hdl = nargs->dlink_hdl;
305
306 /* walk each minor to find ugen devices */
307 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
308 minor_path = di_devfs_minor_path(minor);
309 arg.nargs = args;
310 arg.myself = node;
311 arg.minor = minor;
312 (void) di_devlink_walk(devlink_hdl,
313 "^usb/[0-9a-f]+[.][0-9a-f]+", minor_path,
314 DI_PRIMARY_LINK, (void *)&arg, sunos_add_devices);
315 di_devfs_path_free(minor_path);
316 }
317
318 /* switch to a different node */
319 nargs->last_ugenpath = NULL;
320
321 return (DI_WALK_CONTINUE);
322 }
323
324 int
sunos_get_device_list(struct libusb_context * ctx,struct discovered_devs ** discdevs)325 sunos_get_device_list(struct libusb_context * ctx,
326 struct discovered_devs **discdevs)
327 {
328 di_node_t root_node;
329 struct node_args args;
330 di_devlink_handle_t devlink_hdl;
331
332 args.ctx = ctx;
333 args.discdevs = discdevs;
334 args.last_ugenpath = NULL;
335 if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
336 usbi_dbg("di_int() failed: %s", strerror(errno));
337 return (LIBUSB_ERROR_IO);
338 }
339
340 if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
341 di_fini(root_node);
342 usbi_dbg("di_devlink_init() failed: %s", strerror(errno));
343
344 return (LIBUSB_ERROR_IO);
345 }
346 args.dlink_hdl = devlink_hdl;
347
348 /* walk each node to find USB devices */
349 if (di_walk_node(root_node, DI_WALK_SIBFIRST, &args,
350 sunos_walk_minor_node_link) == -1) {
351 usbi_dbg("di_walk_node() failed: %s", strerror(errno));
352 di_fini(root_node);
353
354 return (LIBUSB_ERROR_IO);
355 }
356
357 di_fini(root_node);
358 di_devlink_fini(&devlink_hdl);
359
360 usbi_dbg("%d devices", (*discdevs)->len);
361
362 return ((*discdevs)->len);
363 }
364
365 static int
sunos_usb_open_ep0(sunos_dev_handle_priv_t * hpriv,sunos_dev_priv_t * dpriv)366 sunos_usb_open_ep0(sunos_dev_handle_priv_t *hpriv, sunos_dev_priv_t *dpriv)
367 {
368 char filename[PATH_MAX + 1];
369
370 if (hpriv->eps[0].datafd > 0) {
371
372 return (LIBUSB_SUCCESS);
373 }
374 snprintf(filename, PATH_MAX, "%s/cntrl0", dpriv->ugenpath);
375
376 usbi_dbg("opening %s", filename);
377 hpriv->eps[0].datafd = open(filename, O_RDWR);
378 if (hpriv->eps[0].datafd < 0) {
379 return(_errno_to_libusb(errno));
380 }
381
382 snprintf(filename, PATH_MAX, "%s/cntrl0stat", dpriv->ugenpath);
383 hpriv->eps[0].statfd = open(filename, O_RDONLY);
384 if (hpriv->eps[0].statfd < 0) {
385 close(hpriv->eps[0].datafd);
386 hpriv->eps[0].datafd = -1;
387
388 return(_errno_to_libusb(errno));
389 }
390
391 return (LIBUSB_SUCCESS);
392 }
393
394 static void
sunos_usb_close_all_eps(sunos_dev_handle_priv_t * hdev)395 sunos_usb_close_all_eps(sunos_dev_handle_priv_t *hdev)
396 {
397 int i;
398
399 /* not close ep0 */
400 for (i = 1; i < USB_MAXENDPOINTS; i++) {
401 if (hdev->eps[i].datafd != -1) {
402 (void) close(hdev->eps[i].datafd);
403 hdev->eps[i].datafd = -1;
404 }
405 if (hdev->eps[i].statfd != -1) {
406 (void) close(hdev->eps[i].statfd);
407 hdev->eps[i].statfd = -1;
408 }
409 }
410 }
411
412 static void
sunos_usb_close_ep0(sunos_dev_handle_priv_t * hdev,sunos_dev_priv_t * dpriv)413 sunos_usb_close_ep0(sunos_dev_handle_priv_t *hdev, sunos_dev_priv_t *dpriv)
414 {
415 if (hdev->eps[0].datafd >= 0) {
416 close(hdev->eps[0].datafd);
417 close(hdev->eps[0].statfd);
418 hdev->eps[0].datafd = -1;
419 hdev->eps[0].statfd = -1;
420 }
421 }
422
423 static uchar_t
sunos_usb_ep_index(uint8_t ep_addr)424 sunos_usb_ep_index(uint8_t ep_addr)
425 {
426 return ((ep_addr & LIBUSB_ENDPOINT_ADDRESS_MASK) +
427 ((ep_addr & LIBUSB_ENDPOINT_DIR_MASK) ? 16 : 0));
428 }
429
430 static int
sunos_find_interface(struct libusb_device_handle * hdev,uint8_t endpoint,uint8_t * interface)431 sunos_find_interface(struct libusb_device_handle *hdev,
432 uint8_t endpoint, uint8_t *interface)
433 {
434 struct libusb_config_descriptor *config;
435 int r;
436 int iface_idx;
437
438 r = libusb_get_active_config_descriptor(hdev->dev, &config);
439 if (r < 0) {
440 return (LIBUSB_ERROR_INVALID_PARAM);
441 }
442
443 for (iface_idx = 0; iface_idx < config->bNumInterfaces; iface_idx++) {
444 const struct libusb_interface *iface =
445 &config->interface[iface_idx];
446 int altsetting_idx;
447
448 for (altsetting_idx = 0; altsetting_idx < iface->num_altsetting;
449 altsetting_idx++) {
450 const struct libusb_interface_descriptor *altsetting =
451 &iface->altsetting[altsetting_idx];
452 int ep_idx;
453
454 for (ep_idx = 0; ep_idx < altsetting->bNumEndpoints;
455 ep_idx++) {
456 const struct libusb_endpoint_descriptor *ep =
457 &altsetting->endpoint[ep_idx];
458 if (ep->bEndpointAddress == endpoint) {
459 *interface = iface_idx;
460 libusb_free_config_descriptor(config);
461
462 return (LIBUSB_SUCCESS);
463 }
464 }
465 }
466 }
467 libusb_free_config_descriptor(config);
468
469 return (LIBUSB_ERROR_INVALID_PARAM);
470 }
471
472 static int
sunos_check_device_and_status_open(struct libusb_device_handle * hdl,uint8_t ep_addr,int ep_type)473 sunos_check_device_and_status_open(struct libusb_device_handle *hdl,
474 uint8_t ep_addr, int ep_type)
475 {
476 char filename[PATH_MAX + 1], statfilename[PATH_MAX + 1];
477 char cfg_num[16], alt_num[16];
478 int fd, fdstat, mode;
479 uint8_t ifc = 0;
480 uint8_t ep_index;
481 sunos_dev_handle_priv_t *hpriv;
482
483 usbi_dbg("open ep 0x%02x", ep_addr);
484 hpriv = (sunos_dev_handle_priv_t *)hdl->os_priv;
485 ep_index = sunos_usb_ep_index(ep_addr);
486 /* ep already opened */
487 if ((hpriv->eps[ep_index].datafd > 0) &&
488 (hpriv->eps[ep_index].statfd > 0)) {
489 usbi_dbg("ep 0x%02x already opened, return success",
490 ep_addr);
491
492 return (0);
493 }
494
495 if (sunos_find_interface(hdl, ep_addr, &ifc) < 0) {
496 usbi_dbg("can't find interface for endpoint 0x%02x",
497 ep_addr);
498
499 return (LIBUSB_ERROR_ACCESS);
500 }
501
502 /* create filename */
503 if (hpriv->config_index > 0) {
504 (void) snprintf(cfg_num, sizeof (cfg_num), "cfg%d",
505 hpriv->config_index + 1);
506 } else {
507 bzero(cfg_num, sizeof (cfg_num));
508 }
509
510 if (hpriv->altsetting[ifc] > 0) {
511 (void) snprintf(alt_num, sizeof (alt_num), ".%d",
512 hpriv->altsetting[ifc]);
513 } else {
514 bzero(alt_num, sizeof (alt_num));
515 }
516
517 (void) snprintf(filename, PATH_MAX, "%s/%sif%d%s%s%d",
518 hpriv->dpriv->ugenpath, cfg_num, ifc, alt_num,
519 (ep_addr & LIBUSB_ENDPOINT_DIR_MASK) ? "in" :
520 "out", (ep_addr & LIBUSB_ENDPOINT_ADDRESS_MASK));
521 (void) snprintf(statfilename, PATH_MAX, "%sstat", filename);
522
523 /*
524 * for interrupt IN endpoints, we need to enable one xfer
525 * mode before opening the endpoint
526 */
527 if ((ep_type == LIBUSB_TRANSFER_TYPE_INTERRUPT) &&
528 (ep_addr & LIBUSB_ENDPOINT_IN)) {
529 char control = USB_EP_INTR_ONE_XFER;
530 int count;
531
532 /* open the status device node for the ep first RDWR */
533 if ((fdstat = open(statfilename, O_RDWR)) == -1) {
534 usbi_dbg("can't open %s RDWR: %d",
535 statfilename, errno);
536 } else {
537 count = write(fdstat, &control, sizeof (control));
538 if (count != 1) {
539 /* this should have worked */
540 usbi_dbg("can't write to %s: %d",
541 statfilename, errno);
542 (void) close(fdstat);
543
544 return (errno);
545 }
546 /* close status node and open xfer node first */
547 close (fdstat);
548 }
549 }
550
551 /* open the xfer node first in case alt needs to be changed */
552 if (ep_type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
553 mode = O_RDWR;
554 } else if (ep_addr & LIBUSB_ENDPOINT_IN) {
555 mode = O_RDONLY;
556 } else {
557 mode = O_WRONLY;
558 }
559
560 /*
561 * IMPORTANT: must open data xfer node first and then open stat node
562 * Otherwise, it will fail on multi-config or multi-altsetting devices
563 * with "Device Busy" error. See ugen_epxs_switch_cfg_alt() and
564 * ugen_epxs_check_alt_switch() in ugen driver source code.
565 */
566 if ((fd = open(filename, mode)) == -1) {
567 usbi_dbg("can't open %s: %d(%s)", filename, errno,
568 strerror(errno));
569
570 return (errno);
571 }
572 /* open the status node */
573 if ((fdstat = open(statfilename, O_RDONLY)) == -1) {
574 usbi_dbg("can't open %s: %d", statfilename, errno);
575
576 (void) close(fd);
577
578 return (errno);
579 }
580
581 hpriv->eps[ep_index].datafd = fd;
582 hpriv->eps[ep_index].statfd = fdstat;
583 usbi_dbg("ep=0x%02x datafd=%d, statfd=%d", ep_addr, fd, fdstat);
584
585 return (0);
586 }
587
588 int
sunos_open(struct libusb_device_handle * handle)589 sunos_open(struct libusb_device_handle *handle)
590 {
591 sunos_dev_handle_priv_t *hpriv;
592 sunos_dev_priv_t *dpriv;
593 int i;
594 int ret;
595
596 hpriv = (sunos_dev_handle_priv_t *)handle->os_priv;
597 dpriv = (sunos_dev_priv_t *)handle->dev->os_priv;
598 hpriv->dpriv = dpriv;
599
600 /* set all file descriptors to "closed" */
601 for (i = 0; i < USB_MAXENDPOINTS; i++) {
602 hpriv->eps[i].datafd = -1;
603 hpriv->eps[i].statfd = -1;
604 }
605
606 if ((ret = sunos_usb_open_ep0(hpriv, dpriv)) != LIBUSB_SUCCESS) {
607 usbi_dbg("fail: %d", ret);
608 return (ret);
609 }
610
611 return (LIBUSB_SUCCESS);
612 }
613
614 void
sunos_close(struct libusb_device_handle * handle)615 sunos_close(struct libusb_device_handle *handle)
616 {
617 sunos_dev_handle_priv_t *hpriv;
618 sunos_dev_priv_t *dpriv;
619
620 usbi_dbg("");
621 if (!handle) {
622 return;
623 }
624
625 hpriv = (sunos_dev_handle_priv_t *)handle->os_priv;
626 if (!hpriv) {
627 return;
628 }
629 dpriv = (sunos_dev_priv_t *)handle->dev->os_priv;
630 if (!dpriv) {
631 return;
632 }
633
634 sunos_usb_close_all_eps(hpriv);
635 sunos_usb_close_ep0(hpriv, dpriv);
636 }
637
638 int
sunos_get_device_descriptor(struct libusb_device * dev,uint8_t * buf,int * host_endian)639 sunos_get_device_descriptor(struct libusb_device *dev, uint8_t *buf,
640 int *host_endian)
641 {
642 sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv;
643
644 memcpy(buf, &dpriv->dev_descr, LIBUSB_DT_DEVICE_SIZE);
645 *host_endian = 0;
646
647 return (LIBUSB_SUCCESS);
648 }
649
650 int
sunos_get_active_config_descriptor(struct libusb_device * dev,uint8_t * buf,size_t len,int * host_endian)651 sunos_get_active_config_descriptor(struct libusb_device *dev,
652 uint8_t *buf, size_t len, int *host_endian)
653 {
654 sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv;
655 struct libusb_config_descriptor *cfg;
656 int proplen;
657 di_node_t node;
658 uint8_t *rdata;
659
660 /*
661 * Keep raw configuration descriptors updated, in case config
662 * has ever been changed through setCfg.
663 */
664 if ((node = di_init(dpriv->phypath, DINFOCPYALL)) == DI_NODE_NIL) {
665 usbi_dbg("di_int() failed: %s", strerror(errno));
666 return (LIBUSB_ERROR_IO);
667 }
668 proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
669 "usb-raw-cfg-descriptors", &rdata);
670 if (proplen <= 0) {
671 usbi_dbg("can't find raw config descriptors");
672
673 return (LIBUSB_ERROR_IO);
674 }
675 dpriv->raw_cfgdescr = realloc(dpriv->raw_cfgdescr, proplen);
676 if (dpriv->raw_cfgdescr == NULL) {
677 return (LIBUSB_ERROR_NO_MEM);
678 } else {
679 bcopy(rdata, dpriv->raw_cfgdescr, proplen);
680 dpriv->cfgvalue = ((struct libusb_config_descriptor *)
681 rdata)->bConfigurationValue;
682 }
683 di_fini(node);
684
685 cfg = (struct libusb_config_descriptor *)dpriv->raw_cfgdescr;
686 len = MIN(len, libusb_le16_to_cpu(cfg->wTotalLength));
687 memcpy(buf, dpriv->raw_cfgdescr, len);
688 *host_endian = 0;
689 usbi_dbg("path:%s len %d", dpriv->phypath, len);
690
691 return (len);
692 }
693
694 int
sunos_get_config_descriptor(struct libusb_device * dev,uint8_t idx,uint8_t * buf,size_t len,int * host_endian)695 sunos_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
696 uint8_t *buf, size_t len, int *host_endian)
697 {
698 /* XXX */
699 return(sunos_get_active_config_descriptor(dev, buf, len, host_endian));
700 }
701
702 int
sunos_get_configuration(struct libusb_device_handle * handle,int * config)703 sunos_get_configuration(struct libusb_device_handle *handle, int *config)
704 {
705 sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)handle->dev->os_priv;
706
707 *config = dpriv->cfgvalue;
708
709 usbi_dbg("bConfigurationValue %d", *config);
710
711 return (LIBUSB_SUCCESS);
712 }
713
714 int
sunos_set_configuration(struct libusb_device_handle * handle,int config)715 sunos_set_configuration(struct libusb_device_handle *handle, int config)
716 {
717 sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)handle->dev->os_priv;
718 sunos_dev_handle_priv_t *hpriv;
719
720 usbi_dbg("bConfigurationValue %d", config);
721 hpriv = (sunos_dev_handle_priv_t *)handle->os_priv;
722
723 if (dpriv->ugenpath == NULL)
724 return (LIBUSB_ERROR_NOT_SUPPORTED);
725
726 if (config < 1 || config > dpriv->dev_descr.bNumConfigurations)
727 return (LIBUSB_ERROR_INVALID_PARAM);
728
729 dpriv->cfgvalue = config;
730 hpriv->config_index = config - 1;
731
732 return (LIBUSB_SUCCESS);
733 }
734
735 int
sunos_claim_interface(struct libusb_device_handle * handle,int iface)736 sunos_claim_interface(struct libusb_device_handle *handle, int iface)
737 {
738 usbi_dbg("iface %d", iface);
739 if (iface < 0) {
740 return (LIBUSB_ERROR_INVALID_PARAM);
741 }
742
743 return (LIBUSB_SUCCESS);
744 }
745
746 int
sunos_release_interface(struct libusb_device_handle * handle,int iface)747 sunos_release_interface(struct libusb_device_handle *handle, int iface)
748 {
749 sunos_dev_handle_priv_t *hpriv =
750 (sunos_dev_handle_priv_t *)handle->os_priv;
751
752 usbi_dbg("iface %d", iface);
753 if (iface < 0) {
754 return (LIBUSB_ERROR_INVALID_PARAM);
755 }
756
757 /* XXX: can we release it? */
758 hpriv->altsetting[iface] = 0;
759
760 return (LIBUSB_SUCCESS);
761 }
762
763 int
sunos_set_interface_altsetting(struct libusb_device_handle * handle,int iface,int altsetting)764 sunos_set_interface_altsetting(struct libusb_device_handle *handle, int iface,
765 int altsetting)
766 {
767 sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)handle->dev->os_priv;
768 sunos_dev_handle_priv_t *hpriv =
769 (sunos_dev_handle_priv_t *)handle->os_priv;
770
771 usbi_dbg("iface %d, setting %d", iface, altsetting);
772
773 if (iface < 0 || altsetting < 0) {
774 return (LIBUSB_ERROR_INVALID_PARAM);
775 }
776 if (dpriv->ugenpath == NULL)
777 return (LIBUSB_ERROR_NOT_FOUND);
778
779 /* XXX: can we switch altsetting? */
780 hpriv->altsetting[iface] = altsetting;
781
782 return (LIBUSB_SUCCESS);
783 }
784
785 static void
usb_dump_data(unsigned char * data,size_t size)786 usb_dump_data(unsigned char *data, size_t size)
787 {
788 int i;
789
790 if (getenv("LIBUSB_DEBUG") == NULL) {
791 return;
792 }
793
794 (void) fprintf(stderr, "data dump:");
795 for (i = 0; i < size; i++) {
796 if (i % 16 == 0) {
797 (void) fprintf(stderr, "\n%08x ", i);
798 }
799 (void) fprintf(stderr, "%02x ", (uchar_t)data[i]);
800 }
801 (void) fprintf(stderr, "\n");
802 }
803
804 static void
sunos_async_callback(union sigval arg)805 sunos_async_callback(union sigval arg)
806 {
807 struct sunos_transfer_priv *tpriv =
808 (struct sunos_transfer_priv *)arg.sival_ptr;
809 struct libusb_transfer *xfer = tpriv->transfer;
810 struct aiocb *aiocb = &tpriv->aiocb;
811 int ret;
812 sunos_dev_handle_priv_t *hpriv;
813 uint8_t ep;
814
815 hpriv = (sunos_dev_handle_priv_t *)xfer->dev_handle->os_priv;
816 ep = sunos_usb_ep_index(xfer->endpoint);
817
818 ret = aio_error(aiocb);
819 if (ret != 0) {
820 xfer->status = sunos_usb_get_status(hpriv->eps[ep].statfd);
821 } else {
822 xfer->actual_length =
823 LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer)->transferred =
824 aio_return(aiocb);
825 }
826
827 usb_dump_data(xfer->buffer, xfer->actual_length);
828
829 usbi_dbg("ret=%d, len=%d, actual_len=%d", ret, xfer->length,
830 xfer->actual_length);
831
832 /* async notification */
833 usbi_signal_transfer_completion(LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer));
834 }
835
836 static int
sunos_do_async_io(struct libusb_transfer * transfer)837 sunos_do_async_io(struct libusb_transfer *transfer)
838 {
839 int ret = -1;
840 struct aiocb *aiocb;
841 sunos_dev_handle_priv_t *hpriv;
842 uint8_t ep;
843 struct sunos_transfer_priv *tpriv;
844
845 usbi_dbg("");
846
847 tpriv = usbi_transfer_get_os_priv(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer));
848 hpriv = (sunos_dev_handle_priv_t *)transfer->dev_handle->os_priv;
849 ep = sunos_usb_ep_index(transfer->endpoint);
850
851 tpriv->transfer = transfer;
852 aiocb = &tpriv->aiocb;
853 bzero(aiocb, sizeof (*aiocb));
854 aiocb->aio_fildes = hpriv->eps[ep].datafd;
855 aiocb->aio_buf = transfer->buffer;
856 aiocb->aio_nbytes = transfer->length;
857 aiocb->aio_lio_opcode =
858 ((transfer->endpoint & LIBUSB_ENDPOINT_DIR_MASK) ==
859 LIBUSB_ENDPOINT_IN) ? LIO_READ:LIO_WRITE;
860 aiocb->aio_sigevent.sigev_notify = SIGEV_THREAD;
861 aiocb->aio_sigevent.sigev_value.sival_ptr = tpriv;
862 aiocb->aio_sigevent.sigev_notify_function = sunos_async_callback;
863
864 if (aiocb->aio_lio_opcode == LIO_READ) {
865 ret = aio_read(aiocb);
866 } else {
867 ret = aio_write(aiocb);
868 }
869
870 return (ret);
871 }
872
873 /* return the number of bytes read/written */
874 static int
usb_do_io(int fd,int stat_fd,char * data,size_t size,int flag,int * status)875 usb_do_io(int fd, int stat_fd, char *data, size_t size, int flag, int *status)
876 {
877 int error;
878 int ret = -1;
879
880 usbi_dbg("usb_do_io(): datafd=%d statfd=%d size=0x%x flag=%s",
881 fd, stat_fd, size, flag? "WRITE":"READ");
882
883 switch (flag) {
884 case READ:
885 errno = 0;
886 ret = read(fd, data, size);
887 usb_dump_data(data, size);
888 break;
889 case WRITE:
890 usb_dump_data(data, size);
891 errno = 0;
892 ret = write(fd, data, size);
893 break;
894 }
895
896 usbi_dbg("usb_do_io(): amount=%d", ret);
897
898 if (ret < 0) {
899 int save_errno = errno;
900
901 usbi_dbg("TID=%x io %s errno=%d(%s) ret=%d", pthread_self(),
902 flag?"WRITE":"READ", errno, strerror(errno), ret);
903
904 /* sunos_usb_get_status will do a read and overwrite errno */
905 error = sunos_usb_get_status(stat_fd);
906 usbi_dbg("io status=%d errno=%d(%s)", error,
907 save_errno, strerror(save_errno));
908
909 if (status) {
910 *status = save_errno;
911 }
912
913 return (save_errno);
914
915 } else if (status) {
916 *status = 0;
917 }
918
919 return (ret);
920 }
921
922 static int
solaris_submit_ctrl_on_default(struct libusb_transfer * transfer)923 solaris_submit_ctrl_on_default(struct libusb_transfer *transfer)
924 {
925 int ret = -1, setup_ret;
926 int status;
927 sunos_dev_handle_priv_t *hpriv;
928 struct libusb_device_handle *hdl = transfer->dev_handle;
929 uint16_t wLength;
930 uint8_t *data = transfer->buffer;
931
932 hpriv = (sunos_dev_handle_priv_t *)hdl->os_priv;
933 wLength = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
934
935 if (hpriv->eps[0].datafd == -1) {
936 usbi_dbg("ep0 not opened");
937
938 return (LIBUSB_ERROR_NOT_FOUND);
939 }
940
941 if ((data[0] & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) {
942 usbi_dbg("IN request");
943 ret = usb_do_io(hpriv->eps[0].datafd,
944 hpriv->eps[0].statfd, (char *)data, LIBUSB_CONTROL_SETUP_SIZE,
945 WRITE, (int *)&status);
946 } else {
947 usbi_dbg("OUT request");
948 ret = usb_do_io(hpriv->eps[0].datafd, hpriv->eps[0].statfd,
949 transfer->buffer, transfer->length, WRITE,
950 (int *)&transfer->status);
951 }
952
953 setup_ret = ret;
954 if (ret < LIBUSB_CONTROL_SETUP_SIZE) {
955 usbi_dbg("error sending control msg: %d", ret);
956
957 return (LIBUSB_ERROR_IO);
958 }
959
960 ret = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
961
962 /* Read the remaining bytes for IN request */
963 if ((wLength) && ((data[0] & LIBUSB_ENDPOINT_DIR_MASK) ==
964 LIBUSB_ENDPOINT_IN)) {
965 usbi_dbg("DATA: %d", transfer->length - setup_ret);
966 ret = usb_do_io(hpriv->eps[0].datafd,
967 hpriv->eps[0].statfd,
968 (char *)transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE,
969 wLength, READ, (int *)&transfer->status);
970 }
971
972 if (ret >= 0) {
973 transfer->actual_length = ret;
974 LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->transferred = ret;
975 }
976 usbi_dbg("Done: ctrl data bytes %d", ret);
977
978 /* sync transfer handling */
979 ret = usbi_handle_transfer_completion(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer),
980 transfer->status);
981
982 return (ret);
983 }
984
985 int
sunos_clear_halt(struct libusb_device_handle * handle,uint8_t endpoint)986 sunos_clear_halt(struct libusb_device_handle *handle, uint8_t endpoint)
987 {
988 int ret;
989
990 usbi_dbg("endpoint=0x%02x", endpoint);
991
992 ret = libusb_control_transfer(handle, LIBUSB_ENDPOINT_OUT |
993 LIBUSB_RECIPIENT_ENDPOINT | LIBUSB_REQUEST_TYPE_STANDARD,
994 LIBUSB_REQUEST_CLEAR_FEATURE, 0, endpoint, NULL, 0, 1000);
995
996 usbi_dbg("ret=%d", ret);
997
998 return (ret);
999 }
1000
1001 int
sunos_reset_device(struct libusb_device_handle * handle)1002 sunos_reset_device(struct libusb_device_handle *handle)
1003 {
1004 usbi_dbg("");
1005
1006 return (LIBUSB_ERROR_NOT_SUPPORTED);
1007 }
1008
1009 void
sunos_destroy_device(struct libusb_device * dev)1010 sunos_destroy_device(struct libusb_device *dev)
1011 {
1012 sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv;
1013
1014 usbi_dbg("");
1015
1016 free(dpriv->raw_cfgdescr);
1017 free(dpriv->ugenpath);
1018 free(dpriv->phypath);
1019 }
1020
1021 int
sunos_submit_transfer(struct usbi_transfer * itransfer)1022 sunos_submit_transfer(struct usbi_transfer *itransfer)
1023 {
1024 struct libusb_transfer *transfer;
1025 struct libusb_device_handle *hdl;
1026 int err = 0;
1027
1028 transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
1029 hdl = transfer->dev_handle;
1030
1031 err = sunos_check_device_and_status_open(hdl,
1032 transfer->endpoint, transfer->type);
1033 if (err < 0) {
1034
1035 return (_errno_to_libusb(err));
1036 }
1037
1038 switch (transfer->type) {
1039 case LIBUSB_TRANSFER_TYPE_CONTROL:
1040 /* sync transfer */
1041 usbi_dbg("CTRL transfer: %d", transfer->length);
1042 err = solaris_submit_ctrl_on_default(transfer);
1043 break;
1044
1045 case LIBUSB_TRANSFER_TYPE_BULK:
1046 /* fallthru */
1047 case LIBUSB_TRANSFER_TYPE_INTERRUPT:
1048 if (transfer->type == LIBUSB_TRANSFER_TYPE_BULK)
1049 usbi_dbg("BULK transfer: %d", transfer->length);
1050 else
1051 usbi_dbg("INTR transfer: %d", transfer->length);
1052 err = sunos_do_async_io(transfer);
1053 break;
1054
1055 case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
1056 /* Isochronous/Stream is not supported */
1057
1058 /* fallthru */
1059 case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
1060 if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS)
1061 usbi_dbg("ISOC transfer: %d", transfer->length);
1062 else
1063 usbi_dbg("BULK STREAM transfer: %d", transfer->length);
1064 err = LIBUSB_ERROR_NOT_SUPPORTED;
1065 break;
1066 }
1067
1068 return (err);
1069 }
1070
1071 int
sunos_cancel_transfer(struct usbi_transfer * itransfer)1072 sunos_cancel_transfer(struct usbi_transfer *itransfer)
1073 {
1074 sunos_xfer_priv_t *tpriv;
1075 sunos_dev_handle_priv_t *hpriv;
1076 struct libusb_transfer *transfer;
1077 struct aiocb *aiocb;
1078 uint8_t ep;
1079 int ret;
1080
1081 tpriv = usbi_transfer_get_os_priv(itransfer);
1082 aiocb = &tpriv->aiocb;
1083 transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
1084 hpriv = (sunos_dev_handle_priv_t *)transfer->dev_handle->os_priv;
1085 ep = sunos_usb_ep_index(transfer->endpoint);
1086
1087 ret = aio_cancel(hpriv->eps[ep].datafd, aiocb);
1088
1089 usbi_dbg("aio->fd=%d fd=%d ret = %d, %s", aiocb->aio_fildes,
1090 hpriv->eps[ep].datafd, ret, (ret == AIO_CANCELED)?
1091 strerror(0):strerror(errno));
1092
1093 if (ret != AIO_CANCELED) {
1094 ret = _errno_to_libusb(errno);
1095 } else {
1096 /*
1097 * we don't need to call usbi_handle_transfer_cancellation(),
1098 * because we'll handle everything in sunos_async_callback.
1099 */
1100 ret = LIBUSB_SUCCESS;
1101 }
1102
1103 return (ret);
1104 }
1105
1106 void
sunos_clear_transfer_priv(struct usbi_transfer * itransfer)1107 sunos_clear_transfer_priv(struct usbi_transfer *itransfer)
1108 {
1109 usbi_dbg("");
1110
1111 /* Nothing to do */
1112 }
1113
1114 int
sunos_handle_transfer_completion(struct usbi_transfer * itransfer)1115 sunos_handle_transfer_completion(struct usbi_transfer *itransfer)
1116 {
1117 return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
1118 }
1119
1120 int
sunos_clock_gettime(int clkid,struct timespec * tp)1121 sunos_clock_gettime(int clkid, struct timespec *tp)
1122 {
1123 usbi_dbg("clock %d", clkid);
1124
1125 if (clkid == USBI_CLOCK_REALTIME)
1126 return clock_gettime(CLOCK_REALTIME, tp);
1127
1128 if (clkid == USBI_CLOCK_MONOTONIC)
1129 return clock_gettime(CLOCK_MONOTONIC, tp);
1130
1131 return (LIBUSB_ERROR_INVALID_PARAM);
1132 }
1133
1134 int
_errno_to_libusb(int err)1135 _errno_to_libusb(int err)
1136 {
1137 usbi_dbg("error: %s (%d)", strerror(err), err);
1138
1139 switch (err) {
1140 case EIO:
1141 return (LIBUSB_ERROR_IO);
1142 case EACCES:
1143 return (LIBUSB_ERROR_ACCESS);
1144 case ENOENT:
1145 return (LIBUSB_ERROR_NO_DEVICE);
1146 case ENOMEM:
1147 return (LIBUSB_ERROR_NO_MEM);
1148 case ETIMEDOUT:
1149 return (LIBUSB_ERROR_TIMEOUT);
1150 }
1151
1152 return (LIBUSB_ERROR_OTHER);
1153 }
1154
1155 /*
1156 * sunos_usb_get_status:
1157 * gets status of endpoint
1158 *
1159 * Returns: ugen's last cmd status
1160 */
1161 static int
sunos_usb_get_status(int fd)1162 sunos_usb_get_status(int fd)
1163 {
1164 int status, ret;
1165
1166 usbi_dbg("sunos_usb_get_status(): fd=%d", fd);
1167
1168 ret = read(fd, &status, sizeof (status));
1169 if (ret == sizeof (status)) {
1170 switch (status) {
1171 case USB_LC_STAT_NOERROR:
1172 usbi_dbg("No Error");
1173 break;
1174 case USB_LC_STAT_CRC:
1175 usbi_dbg("CRC Timeout Detected\n");
1176 break;
1177 case USB_LC_STAT_BITSTUFFING:
1178 usbi_dbg("Bit Stuffing Violation\n");
1179 break;
1180 case USB_LC_STAT_DATA_TOGGLE_MM:
1181 usbi_dbg("Data Toggle Mismatch\n");
1182 break;
1183 case USB_LC_STAT_STALL:
1184 usbi_dbg("End Point Stalled\n");
1185 break;
1186 case USB_LC_STAT_DEV_NOT_RESP:
1187 usbi_dbg("Device is Not Responding\n");
1188 break;
1189 case USB_LC_STAT_PID_CHECKFAILURE:
1190 usbi_dbg("PID Check Failure\n");
1191 break;
1192 case USB_LC_STAT_UNEXP_PID:
1193 usbi_dbg("Unexpected PID\n");
1194 break;
1195 case USB_LC_STAT_DATA_OVERRUN:
1196 usbi_dbg("Data Exceeded Size\n");
1197 break;
1198 case USB_LC_STAT_DATA_UNDERRUN:
1199 usbi_dbg("Less data received\n");
1200 break;
1201 case USB_LC_STAT_BUFFER_OVERRUN:
1202 usbi_dbg("Buffer Size Exceeded\n");
1203 break;
1204 case USB_LC_STAT_BUFFER_UNDERRUN:
1205 usbi_dbg("Buffer Underrun\n");
1206 break;
1207 case USB_LC_STAT_TIMEOUT:
1208 usbi_dbg("Command Timed Out\n");
1209 break;
1210 case USB_LC_STAT_NOT_ACCESSED:
1211 usbi_dbg("Not Accessed by h/w\n");
1212 break;
1213 case USB_LC_STAT_UNSPECIFIED_ERR:
1214 usbi_dbg("Unspecified Error\n");
1215 break;
1216 case USB_LC_STAT_NO_BANDWIDTH:
1217 usbi_dbg("No Bandwidth\n");
1218 break;
1219 case USB_LC_STAT_HW_ERR:
1220 usbi_dbg("Host Controller h/w Error\n");
1221 break;
1222 case USB_LC_STAT_SUSPENDED:
1223 usbi_dbg("Device was Suspended\n");
1224 break;
1225 case USB_LC_STAT_DISCONNECTED:
1226 usbi_dbg("Device was Disconnected\n");
1227 break;
1228 case USB_LC_STAT_INTR_BUF_FULL:
1229 usbi_dbg("Interrupt buffer was full\n");
1230 break;
1231 case USB_LC_STAT_INVALID_REQ:
1232 usbi_dbg("Request was Invalid\n");
1233 break;
1234 case USB_LC_STAT_INTERRUPTED:
1235 usbi_dbg("Request was Interrupted\n");
1236 break;
1237 case USB_LC_STAT_NO_RESOURCES:
1238 usbi_dbg("No resources available for "
1239 "request\n");
1240 break;
1241 case USB_LC_STAT_INTR_POLLING_FAILED:
1242 usbi_dbg("Failed to Restart Poll");
1243 break;
1244 default:
1245 usbi_dbg("Error Not Determined %d\n",
1246 status);
1247 break;
1248 }
1249 } else {
1250 usbi_dbg("read stat error: %s",strerror(errno));
1251 status = -1;
1252 }
1253
1254 return (status);
1255 }
1256
1257 const struct usbi_os_backend sunos_backend = {
1258 .name = "Solaris",
1259 .caps = 0,
1260 .init = sunos_init,
1261 .exit = sunos_exit,
1262 .get_device_list = sunos_get_device_list,
1263 .get_device_descriptor = sunos_get_device_descriptor,
1264 .get_active_config_descriptor = sunos_get_active_config_descriptor,
1265 .get_config_descriptor = sunos_get_config_descriptor,
1266 .hotplug_poll = NULL,
1267 .open = sunos_open,
1268 .close = sunos_close,
1269 .get_configuration = sunos_get_configuration,
1270 .set_configuration = sunos_set_configuration,
1271
1272 .claim_interface = sunos_claim_interface,
1273 .release_interface = sunos_release_interface,
1274 .set_interface_altsetting = sunos_set_interface_altsetting,
1275 .clear_halt = sunos_clear_halt,
1276 .reset_device = sunos_reset_device, /* TODO */
1277 .alloc_streams = NULL,
1278 .free_streams = NULL,
1279 .kernel_driver_active = NULL,
1280 .detach_kernel_driver = NULL,
1281 .attach_kernel_driver = NULL,
1282 .destroy_device = sunos_destroy_device,
1283 .submit_transfer = sunos_submit_transfer,
1284 .cancel_transfer = sunos_cancel_transfer,
1285 .handle_events = NULL,
1286 .clear_transfer_priv = sunos_clear_transfer_priv,
1287 .handle_transfer_completion = sunos_handle_transfer_completion,
1288 .clock_gettime = sunos_clock_gettime,
1289 .device_priv_size = sizeof(sunos_dev_priv_t),
1290 .device_handle_priv_size = sizeof(sunos_dev_handle_priv_t),
1291 .transfer_priv_size = sizeof(sunos_xfer_priv_t),
1292 };
1293