• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 **)&regbuf);
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