Misc: Trim and consolidate header file usage
[platform/upstream/libusb.git] / libusb / os / sunos_usb.c
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 <wait.h>
32 #include <unistd.h>
33 #include <aio.h>
34 #include <libdevinfo.h>
35 #include <sys/nvpair.h>
36 #include <sys/devctl.h>
37 #include <sys/usb/clients/ugen/usb_ugen.h>
38 #include <sys/usb/usba.h>
39 #include <sys/pci.h>
40 #include <inttypes.h>
41
42 #include "libusbi.h"
43 #include "sunos_usb.h"
44
45 #define UPDATEDRV_PATH  "/usr/sbin/update_drv"
46 #define UPDATEDRV       "update_drv"
47
48 #define DEFAULT_LISTSIZE        6
49
50 typedef struct {
51         int     nargs;
52         int     listsize;
53         char    **string;
54 } string_list_t;
55
56 /*
57  * Backend functions
58  */
59 static int sunos_init(struct libusb_context *);
60 static void sunos_exit(struct libusb_context *);
61 static int sunos_get_device_list(struct libusb_context *,
62     struct discovered_devs **);
63 static int sunos_open(struct libusb_device_handle *);
64 static void sunos_close(struct libusb_device_handle *);
65 static int sunos_get_device_descriptor(struct libusb_device *,
66     uint8_t*, int *);
67 static int sunos_get_active_config_descriptor(struct libusb_device *,
68     uint8_t*, size_t, int *);
69 static int sunos_get_config_descriptor(struct libusb_device *, uint8_t,
70     uint8_t*, size_t, int *);
71 static int sunos_get_configuration(struct libusb_device_handle *, int *);
72 static int sunos_set_configuration(struct libusb_device_handle *, int);
73 static int sunos_claim_interface(struct libusb_device_handle *, int);
74 static int sunos_release_interface(struct libusb_device_handle *, int);
75 static int sunos_set_interface_altsetting(struct libusb_device_handle *,
76     int, int);
77 static int sunos_clear_halt(struct libusb_device_handle *, uint8_t);
78 static int sunos_reset_device(struct libusb_device_handle *);
79 static void sunos_destroy_device(struct libusb_device *);
80 static int sunos_submit_transfer(struct usbi_transfer *);
81 static int sunos_cancel_transfer(struct usbi_transfer *);
82 static void sunos_clear_transfer_priv(struct usbi_transfer *);
83 static int sunos_handle_transfer_completion(struct usbi_transfer *);
84 static int sunos_clock_gettime(int, struct timespec *);
85 static int sunos_kernel_driver_active(struct libusb_device_handle *, int interface);
86 static int sunos_detach_kernel_driver (struct libusb_device_handle *dev, int interface_number);
87 static int sunos_attach_kernel_driver (struct libusb_device_handle *dev, int interface_number);
88 static int sunos_usb_open_ep0(sunos_dev_handle_priv_t *hpriv, sunos_dev_priv_t *dpriv);
89 static int sunos_usb_ioctl(struct libusb_device *dev, int cmd);
90
91 static struct devctl_iocdata iocdata;
92 static int sunos_get_link(di_devlink_t devlink, void *arg)
93 {
94         walk_link_t *larg = (walk_link_t *)arg;
95         const char *p;
96         const char *q;
97
98         if (larg->path) {
99                 char *content = (char *)di_devlink_content(devlink);
100                 char *start = strstr(content, "/devices/");
101                 start += strlen("/devices");
102                 usbi_dbg("%s", start);
103
104                 /* line content must have minor node */
105                 if (start == NULL ||
106                     strncmp(start, larg->path, larg->len) != 0 ||
107                     start[larg->len] != ':')
108                         return (DI_WALK_CONTINUE);
109         }
110
111         p = di_devlink_path(devlink);
112         q = strrchr(p, '/');
113         usbi_dbg("%s", q);
114
115         *(larg->linkpp) = strndup(p, strlen(p) - strlen(q));
116
117         return (DI_WALK_TERMINATE);
118 }
119
120
121 static int sunos_physpath_to_devlink(
122         const char *node_path, const char *match, char **link_path)
123 {
124         walk_link_t larg;
125         di_devlink_handle_t hdl;
126
127         *link_path = NULL;
128         larg.linkpp = link_path;
129         if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
130                 usbi_dbg("di_devlink_init failure");
131                 return (-1);
132         }
133
134         larg.len = strlen(node_path);
135         larg.path = (char *)node_path;
136
137         (void) di_devlink_walk(hdl, match, NULL, DI_PRIMARY_LINK,
138             (void *)&larg, sunos_get_link);
139
140         (void) di_devlink_fini(&hdl);
141
142         if (*link_path == NULL) {
143                 usbi_dbg("there is no devlink for this path");
144                 return (-1);
145         }
146
147         return 0;
148 }
149
150 static int
151 sunos_usb_ioctl(struct libusb_device *dev, int cmd)
152 {
153         int fd;
154         nvlist_t *nvlist;
155         char *end;
156         char *phypath;
157         char *hubpath;
158         char path_arg[PATH_MAX];
159         sunos_dev_priv_t *dpriv;
160         devctl_ap_state_t devctl_ap_state;
161
162         dpriv = (sunos_dev_priv_t *)dev->os_priv;
163         phypath = dpriv->phypath;
164
165         end = strrchr(phypath, '/');
166         if (end == NULL)
167                 return (-1);
168         hubpath = strndup(phypath, end - phypath);
169         if (hubpath == NULL)
170                 return (-1);
171
172         end = strrchr(hubpath, '@');
173         if (end == NULL) {
174                 free(hubpath);
175                 return (-1);
176         }
177         end++;
178         usbi_dbg("unitaddr: %s", end);
179
180         nvlist_alloc(&nvlist, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
181         nvlist_add_int32(nvlist, "port", dev->port_number);
182         //find the hub path
183         snprintf(path_arg, sizeof(path_arg), "/devices%s:hubd", hubpath);
184         usbi_dbg("ioctl hub path: %s", path_arg);
185
186         fd = open(path_arg, O_RDONLY);
187         if (fd < 0) {
188                 usbi_err(DEVICE_CTX(dev), "open failed: errno %d (%s)", errno, strerror(errno));
189                 nvlist_free(nvlist);
190                 free(hubpath);
191                 return (-1);
192         }
193
194         memset(&iocdata, 0, sizeof(iocdata));
195         memset(&devctl_ap_state, 0, sizeof(devctl_ap_state));
196
197         nvlist_pack(nvlist, (char **)&iocdata.nvl_user, &iocdata.nvl_usersz, NV_ENCODE_NATIVE, 0);
198
199         iocdata.cmd = DEVCTL_AP_GETSTATE;
200         iocdata.flags = 0;
201         iocdata.c_nodename = "hub";
202         iocdata.c_unitaddr = end;
203         iocdata.cpyout_buf = &devctl_ap_state;
204         usbi_dbg("%p, %" PRIuPTR, iocdata.nvl_user, iocdata.nvl_usersz);
205
206         errno = 0;
207         if (ioctl(fd, DEVCTL_AP_GETSTATE, &iocdata) == -1) {
208                 usbi_err(DEVICE_CTX(dev), "ioctl failed: fd %d, cmd %x, errno %d (%s)",
209                          fd, DEVCTL_AP_GETSTATE, errno, strerror(errno));
210         } else {
211                 usbi_dbg("dev rstate: %d", devctl_ap_state.ap_rstate);
212                 usbi_dbg("dev ostate: %d", devctl_ap_state.ap_ostate);
213         }
214
215         errno = 0;
216         iocdata.cmd = cmd;
217         if (ioctl(fd, (int)cmd, &iocdata) != 0) {
218                 usbi_err(DEVICE_CTX(dev), "ioctl failed: fd %d, cmd %x, errno %d (%s)",
219                          fd, cmd, errno, strerror(errno));
220                 sleep(2);
221         }
222
223         close(fd);
224         free(iocdata.nvl_user);
225         nvlist_free(nvlist);
226         free(hubpath);
227
228         return (-errno);
229 }
230
231 static int
232 sunos_kernel_driver_active(struct libusb_device_handle *dev, int interface)
233 {
234         sunos_dev_priv_t *dpriv;
235         dpriv = (sunos_dev_priv_t *)dev->dev->os_priv;
236
237         usbi_dbg("%s", dpriv->ugenpath);
238
239         return (dpriv->ugenpath == NULL);
240 }
241
242 /*
243  * Private functions
244  */
245 static int _errno_to_libusb(int);
246 static int sunos_usb_get_status(int fd);
247
248 static int sunos_init(struct libusb_context *ctx)
249 {
250         return (LIBUSB_SUCCESS);
251 }
252
253 static void sunos_exit(struct libusb_context *ctx)
254 {
255         usbi_dbg("");
256 }
257
258 static string_list_t *
259 sunos_new_string_list(void)
260 {
261         string_list_t *list;
262
263         list = calloc(1, sizeof (string_list_t));
264         if (list == NULL)
265                 return (NULL);
266         list->string = calloc(DEFAULT_LISTSIZE, sizeof (char *));
267         if (list->string == NULL)
268                 return (NULL);
269         list->nargs = 0;
270         list->listsize = DEFAULT_LISTSIZE;
271
272         return (list);
273 }
274
275 static int
276 sunos_append_to_string_list(string_list_t *list, const char *arg)
277 {
278         char    *str = strdup(arg);
279
280         if (str == NULL)
281                 return (-1);
282
283         if ((list->nargs + 1) == list->listsize) { /* +1 is for NULL */
284                 char    **tmp = realloc(list->string,
285                     sizeof (char *) * (list->listsize + 1));
286                 if (tmp == NULL) {
287                         free(str);
288                         return (-1);
289                 }
290                 list->string = tmp;
291                 list->string[list->listsize++] = NULL;
292         }
293         list->string[list->nargs++] = str;
294
295         return (0);
296 }
297
298 static void
299 sunos_free_string_list(string_list_t *list)
300 {
301         int     i;
302
303         for (i = 0; i < list->nargs; i++) {
304                 free(list->string[i]);
305         }
306
307         free(list->string);
308         free(list);
309 }
310
311 static char **
312 sunos_build_argv_list(string_list_t *list)
313 {
314         return (list->string);
315 }
316
317
318 static int
319 sunos_exec_command(struct libusb_context *ctx, const char *path,
320         string_list_t *list)
321 {
322         pid_t pid;
323         int status;
324         int waitstat;
325         int exit_status;
326         char **argv_list;
327
328         argv_list = sunos_build_argv_list(list);
329         if (argv_list == NULL)
330                 return (-1);
331
332         pid = fork();
333         if (pid == 0) {
334                 /* child */
335                 execv(path, argv_list);
336                 _exit(127);
337         } else if (pid > 0) {
338                 /* parent */
339                 do {
340                         waitstat = waitpid(pid, &status, 0);
341                 } while ((waitstat == -1 && errno == EINTR) ||
342                          (waitstat == 0 && !WIFEXITED(status) && !WIFSIGNALED(status)));
343
344                 if (waitstat == 0) {
345                         if (WIFEXITED(status))
346                                 exit_status = WEXITSTATUS(status);
347                         else
348                                 exit_status = WTERMSIG(status);
349                 } else {
350                         usbi_err(ctx, "waitpid failed: errno %d (%s)", errno, strerror(errno));
351                         exit_status = -1;
352                 }
353         } else {
354                 /* fork failed */
355                 usbi_err(ctx, "fork failed: errno %d (%s)", errno, strerror(errno));
356                 exit_status = -1;
357         }
358
359         return (exit_status);
360 }
361
362 static int
363 sunos_detach_kernel_driver(struct libusb_device_handle *dev_handle,
364         int interface_number)
365 {
366         struct libusb_context *ctx = HANDLE_CTX(dev_handle);
367         string_list_t *list;
368         char path_arg[PATH_MAX];
369         sunos_dev_priv_t *dpriv;
370         int r;
371
372         dpriv = (sunos_dev_priv_t *)dev_handle->dev->os_priv;
373         snprintf(path_arg, sizeof(path_arg), "\'\"%s\"\'", dpriv->phypath);
374         usbi_dbg("%s", path_arg);
375
376         list = sunos_new_string_list();
377         if (list == NULL)
378                 return (LIBUSB_ERROR_NO_MEM);
379
380         /* attach ugen driver */
381         r = 0;
382         r |= sunos_append_to_string_list(list, UPDATEDRV);
383         r |= sunos_append_to_string_list(list, "-a"); /* add rule */
384         r |= sunos_append_to_string_list(list, "-i"); /* specific device */
385         r |= sunos_append_to_string_list(list, path_arg); /* physical path */
386         r |= sunos_append_to_string_list(list, "ugen");
387         if (r) {
388                 sunos_free_string_list(list);
389                 return (LIBUSB_ERROR_NO_MEM);
390         }
391
392         r = sunos_exec_command(ctx, UPDATEDRV_PATH, list);
393         sunos_free_string_list(list);
394         if (r < 0)
395                 return (LIBUSB_ERROR_OTHER);
396
397         /* reconfigure the driver node */
398         r = 0;
399         r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_DISCONNECT);
400         r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
401         if (r)
402                 usbi_warn(HANDLE_CTX(dev_handle), "one or more ioctls failed");
403
404         snprintf(path_arg, sizeof(path_arg), "^usb/%x.%x",
405             libusb_le16_to_cpu(dpriv->dev_descr.idVendor),
406             libusb_le16_to_cpu(dpriv->dev_descr.idProduct));
407         sunos_physpath_to_devlink(dpriv->phypath, path_arg, &dpriv->ugenpath);
408
409         if (access(dpriv->ugenpath, F_OK) == -1) {
410                 usbi_err(HANDLE_CTX(dev_handle), "fail to detach kernel driver");
411                 return (LIBUSB_ERROR_IO);
412         }
413
414         return sunos_usb_open_ep0((sunos_dev_handle_priv_t *)dev_handle->os_priv, dpriv);
415 }
416
417 static int
418 sunos_attach_kernel_driver(struct libusb_device_handle *dev_handle,
419         int interface_number)
420 {
421         struct libusb_context *ctx = HANDLE_CTX(dev_handle);
422         string_list_t *list;
423         char path_arg[PATH_MAX];
424         sunos_dev_priv_t *dpriv;
425         int r;
426
427         /* we open the dev in detach driver, so we need close it first. */
428         sunos_close(dev_handle);
429
430         dpriv = (sunos_dev_priv_t *)dev_handle->dev->os_priv;
431         snprintf(path_arg, sizeof(path_arg), "\'\"%s\"\'", dpriv->phypath);
432         usbi_dbg("%s", path_arg);
433
434         list = sunos_new_string_list();
435         if (list == NULL)
436                 return (LIBUSB_ERROR_NO_MEM);
437
438         /* detach ugen driver */
439         r = 0;
440         r |= sunos_append_to_string_list(list, UPDATEDRV);
441         r |= sunos_append_to_string_list(list, "-d"); /* add rule */
442         r |= sunos_append_to_string_list(list, "-i"); /* specific device */
443         r |= sunos_append_to_string_list(list, path_arg); /* physical path */
444         r |= sunos_append_to_string_list(list, "ugen");
445         if (r) {
446                 sunos_free_string_list(list);
447                 return (LIBUSB_ERROR_NO_MEM);
448         }
449
450         r = sunos_exec_command(ctx, UPDATEDRV_PATH, list);
451         sunos_free_string_list(list);
452         if (r < 0)
453                 return (LIBUSB_ERROR_OTHER);
454
455         /* reconfigure the driver node */
456         r = 0;
457         r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
458         r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_DISCONNECT);
459         r |= sunos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
460         if (r)
461                 usbi_warn(HANDLE_CTX(dev_handle), "one or more ioctls failed");
462
463         return 0;
464 }
465
466 static int
467 sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev)
468 {
469         int     proplen;
470         int     *i, n, *addr, *port_prop;
471         char    *phypath;
472         uint8_t *rdata;
473         struct libusb_device_descriptor *descr;
474         sunos_dev_priv_t        *dpriv = (sunos_dev_priv_t *)dev->os_priv;
475         char    match_str[PATH_MAX];
476
477         /* Device descriptors */
478         proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
479             "usb-dev-descriptor", &rdata);
480         if (proplen <= 0) {
481
482                 return (LIBUSB_ERROR_IO);
483         }
484
485         descr = (struct libusb_device_descriptor *)rdata;
486         bcopy(descr, &dpriv->dev_descr, LIBUSB_DT_DEVICE_SIZE);
487         dpriv->dev_descr.bcdUSB = libusb_cpu_to_le16(descr->bcdUSB);
488         dpriv->dev_descr.idVendor = libusb_cpu_to_le16(descr->idVendor);
489         dpriv->dev_descr.idProduct = libusb_cpu_to_le16(descr->idProduct);
490         dpriv->dev_descr.bcdDevice = libusb_cpu_to_le16(descr->bcdDevice);
491
492         /* Raw configuration descriptors */
493         proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
494             "usb-raw-cfg-descriptors", &rdata);
495         if (proplen <= 0) {
496                 usbi_dbg("can't find raw config descriptors");
497
498                 return (LIBUSB_ERROR_IO);
499         }
500         dpriv->raw_cfgdescr = calloc(1, proplen);
501         if (dpriv->raw_cfgdescr == NULL) {
502                 return (LIBUSB_ERROR_NO_MEM);
503         } else {
504                 bcopy(rdata, dpriv->raw_cfgdescr, proplen);
505                 dpriv->cfgvalue = ((struct libusb_config_descriptor *)
506                     rdata)->bConfigurationValue;
507         }
508
509         n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &port_prop);
510
511         if ((n != 1) || (*port_prop <= 0)) {
512                 return (LIBUSB_ERROR_IO);
513         }
514         dev->port_number = *port_prop;
515
516         /* device physical path */
517         phypath = di_devfs_path(node);
518         if (phypath) {
519                 dpriv->phypath = strdup(phypath);
520                 snprintf(match_str, sizeof(match_str), "^usb/%x.%x",
521                     libusb_le16_to_cpu(dpriv->dev_descr.idVendor),
522                     libusb_le16_to_cpu(dpriv->dev_descr.idProduct));
523                 usbi_dbg("match is %s", match_str);
524                 sunos_physpath_to_devlink(dpriv->phypath, match_str,  &dpriv->ugenpath);
525                 di_devfs_path_free(phypath);
526
527         } else {
528                 free(dpriv->raw_cfgdescr);
529
530                 return (LIBUSB_ERROR_IO);
531         }
532
533         /* address */
534         n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "assigned-address", &addr);
535         if (n != 1 || *addr == 0) {
536                 usbi_dbg("can't get address");
537         } else {
538                 dev->device_address = *addr;
539         }
540
541         /* speed */
542         if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "low-speed", &i) >= 0) {
543                 dev->speed = LIBUSB_SPEED_LOW;
544         } else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "high-speed", &i) >= 0) {
545                 dev->speed = LIBUSB_SPEED_HIGH;
546         } else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "full-speed", &i) >= 0) {
547                 dev->speed = LIBUSB_SPEED_FULL;
548         } else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "super-speed", &i) >= 0) {
549                 dev->speed = LIBUSB_SPEED_SUPER;
550         }
551
552         usbi_dbg("vid=%x pid=%x, path=%s, bus_nmber=0x%x, port_number=%d, "
553             "speed=%d",
554             libusb_le16_to_cpu(dpriv->dev_descr.idVendor),
555             libusb_le16_to_cpu(dpriv->dev_descr.idProduct),
556             dpriv->phypath, dev->bus_number, dev->port_number, dev->speed);
557
558         return (LIBUSB_SUCCESS);
559 }
560
561 static int
562 sunos_add_devices(di_devlink_t link, void *arg)
563 {
564         struct devlink_cbarg    *largs = (struct devlink_cbarg *)arg;
565         struct node_args        *nargs;
566         di_node_t               myself, dn;
567         uint64_t                session_id = 0;
568         uint64_t                sid = 0;
569         uint64_t                bdf = 0;
570         struct libusb_device    *dev;
571         sunos_dev_priv_t        *devpriv;
572         int                     n, *j;
573         int                     i = 0;
574         int                     *addr_prop;
575         uint8_t                 bus_number = 0;
576         uint32_t *              regbuf = NULL;
577         uint32_t                reg;
578
579         nargs = (struct node_args *)largs->nargs;
580         myself = largs->myself;
581
582         /*
583          * Construct session ID.
584          * session ID = dev_addr | hub addr |parent hub addr|...|root hub bdf
585          *              8 bits       8bits          8 bits               16bits
586          */
587         if (myself == DI_NODE_NIL)
588                 return (DI_WALK_CONTINUE);
589
590         dn = myself;
591         /* find the root hub */
592         while (di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "root-hub", &j) != 0) {
593                 usbi_dbg("find_root_hub:%s", di_devfs_path(dn));
594                 n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn,
595                                 "assigned-address", &addr_prop);
596                 session_id |= ((addr_prop[0] & 0xff) << i++ * 8);
597                 dn = di_parent_node(dn);
598         }
599
600         /* dn is the root hub node */
601         n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "reg", (int **)&regbuf);
602         reg = regbuf[0];
603         bdf = (PCI_REG_BUS_G(reg) << 8) | (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
604         /* bdf must larger than i*8 bits */
605         session_id |= (bdf << i * 8);
606         bus_number = (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
607
608         usbi_dbg("device bus address=%s:%x, name:%s",
609             di_bus_addr(myself), bus_number, di_node_name(dn));
610         usbi_dbg("session id org:%" PRIx64, session_id);
611
612         /* dn is the usb device */
613         for (dn = di_child_node(myself); dn != DI_NODE_NIL; dn = di_sibling_node(dn)) {
614                 usbi_dbg("device path:%s", di_devfs_path(dn));
615                 /* skip hub devices, because its driver can not been unload */
616                 if (di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "usb-port-count", &addr_prop) != -1)
617                         continue;
618                 /* usb_addr */
619                 n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn,
620                     "assigned-address", &addr_prop);
621                 if ((n != 1) || (addr_prop[0] == 0)) {
622                         usbi_dbg("cannot get valid usb_addr");
623                         continue;
624                 }
625
626                 sid = (session_id << 8) | (addr_prop[0] & 0xff) ;
627                 usbi_dbg("session id %" PRIX64, sid);
628
629                 dev = usbi_get_device_by_session_id(nargs->ctx, sid);
630                 if (dev == NULL) {
631                         dev = usbi_alloc_device(nargs->ctx, sid);
632                         if (dev == NULL) {
633                                 usbi_dbg("can't alloc device");
634                                 continue;
635                         }
636                         devpriv = (sunos_dev_priv_t *)dev->os_priv;
637                         dev->bus_number = bus_number;
638
639                         if (sunos_fill_in_dev_info(dn, dev) != LIBUSB_SUCCESS) {
640                                 libusb_unref_device(dev);
641                                 usbi_dbg("get infomation fail");
642                                 continue;
643                         }
644                         if (usbi_sanitize_device(dev) < 0) {
645                                 libusb_unref_device(dev);
646                                 usbi_dbg("sanatize failed: ");
647                                 return (DI_WALK_TERMINATE);
648                         }
649                 } else {
650                         devpriv = (sunos_dev_priv_t *)dev->os_priv;
651                         usbi_dbg("Dev %s exists", devpriv->ugenpath);
652                 }
653
654                 if (discovered_devs_append(*(nargs->discdevs), dev) == NULL) {
655                         usbi_dbg("cannot append device");
656                 }
657
658                 /*
659                  * we alloc and hence ref this dev. We don't need to ref it
660                  * hereafter. Front end or app should take care of their ref.
661                  */
662                 libusb_unref_device(dev);
663
664                 usbi_dbg("Device %s %s id=0x%" PRIx64 ", devcount:%" PRIuPTR
665                     ", bdf=%" PRIx64,
666                     devpriv->ugenpath, di_devfs_path(dn), (uint64_t)sid,
667                     (*nargs->discdevs)->len, bdf);
668         }
669
670         return (DI_WALK_CONTINUE);
671 }
672
673 static int
674 sunos_walk_minor_node_link(di_node_t node, void *args)
675 {
676         di_minor_t minor = DI_MINOR_NIL;
677         char *minor_path;
678         struct devlink_cbarg arg;
679         struct node_args *nargs = (struct node_args *)args;
680         di_devlink_handle_t devlink_hdl = nargs->dlink_hdl;
681
682         /* walk each minor to find usb devices */
683         while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
684                 minor_path = di_devfs_minor_path(minor);
685                 arg.nargs = args;
686                 arg.myself = node;
687                 arg.minor = minor;
688                 (void) di_devlink_walk(devlink_hdl,
689                     "^usb/hub[0-9]+", minor_path,
690                     DI_PRIMARY_LINK, (void *)&arg, sunos_add_devices);
691                 di_devfs_path_free(minor_path);
692         }
693
694         /* switch to a different node */
695         nargs->last_ugenpath = NULL;
696
697         return (DI_WALK_CONTINUE);
698 }
699
700 int
701 sunos_get_device_list(struct libusb_context * ctx,
702         struct discovered_devs **discdevs)
703 {
704         di_node_t root_node;
705         struct node_args args;
706         di_devlink_handle_t devlink_hdl;
707
708         args.ctx = ctx;
709         args.discdevs = discdevs;
710         args.last_ugenpath = NULL;
711         if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
712                 usbi_dbg("di_int() failed: errno %d (%s)", errno, strerror(errno));
713                 return (LIBUSB_ERROR_IO);
714         }
715
716         if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
717                 di_fini(root_node);
718                 usbi_dbg("di_devlink_init() failed: errno %d (%s)", errno, strerror(errno));
719
720                 return (LIBUSB_ERROR_IO);
721         }
722         args.dlink_hdl = devlink_hdl;
723
724         /* walk each node to find USB devices */
725         if (di_walk_node(root_node, DI_WALK_SIBFIRST, &args,
726             sunos_walk_minor_node_link) == -1) {
727                 usbi_dbg("di_walk_node() failed: errno %d (%s)", errno, strerror(errno));
728                 di_fini(root_node);
729
730                 return (LIBUSB_ERROR_IO);
731         }
732
733         di_fini(root_node);
734         di_devlink_fini(&devlink_hdl);
735
736         usbi_dbg("%" PRIuPTR " devices", (*discdevs)->len);
737
738         return ((*discdevs)->len);
739 }
740
741 static int
742 sunos_usb_open_ep0(sunos_dev_handle_priv_t *hpriv, sunos_dev_priv_t *dpriv)
743 {
744         char filename[PATH_MAX + 1];
745
746         if (hpriv->eps[0].datafd > 0) {
747
748                 return (LIBUSB_SUCCESS);
749         }
750         snprintf(filename, PATH_MAX, "%s/cntrl0", dpriv->ugenpath);
751
752         usbi_dbg("opening %s", filename);
753         hpriv->eps[0].datafd = open(filename, O_RDWR);
754         if (hpriv->eps[0].datafd < 0) {
755                 return(_errno_to_libusb(errno));
756         }
757
758         snprintf(filename, PATH_MAX, "%s/cntrl0stat", dpriv->ugenpath);
759         hpriv->eps[0].statfd = open(filename, O_RDONLY);
760         if (hpriv->eps[0].statfd < 0) {
761                 close(hpriv->eps[0].datafd);
762                 hpriv->eps[0].datafd = -1;
763
764                 return(_errno_to_libusb(errno));
765         }
766
767         return (LIBUSB_SUCCESS);
768 }
769
770 static void
771 sunos_usb_close_all_eps(sunos_dev_handle_priv_t *hdev)
772 {
773         int i;
774
775         /* not close ep0 */
776         for (i = 1; i < USB_MAXENDPOINTS; i++) {
777                 if (hdev->eps[i].datafd != -1) {
778                         (void) close(hdev->eps[i].datafd);
779                         hdev->eps[i].datafd = -1;
780                 }
781                 if (hdev->eps[i].statfd != -1) {
782                         (void) close(hdev->eps[i].statfd);
783                         hdev->eps[i].statfd = -1;
784                 }
785         }
786 }
787
788 static void
789 sunos_usb_close_ep0(sunos_dev_handle_priv_t *hdev, sunos_dev_priv_t *dpriv)
790 {
791         if (hdev->eps[0].datafd >= 0) {
792                 close(hdev->eps[0].datafd);
793                 close(hdev->eps[0].statfd);
794                 hdev->eps[0].datafd = -1;
795                 hdev->eps[0].statfd = -1;
796         }
797 }
798
799 static uchar_t
800 sunos_usb_ep_index(uint8_t ep_addr)
801 {
802         return ((ep_addr & LIBUSB_ENDPOINT_ADDRESS_MASK) +
803             ((ep_addr & LIBUSB_ENDPOINT_DIR_MASK) ? 16 : 0));
804 }
805
806 static int
807 sunos_find_interface(struct libusb_device_handle *hdev,
808     uint8_t endpoint, uint8_t *interface)
809 {
810         struct libusb_config_descriptor *config;
811         int r;
812         int iface_idx;
813
814         r = libusb_get_active_config_descriptor(hdev->dev, &config);
815         if (r < 0) {
816                 return (LIBUSB_ERROR_INVALID_PARAM);
817         }
818
819         for (iface_idx = 0; iface_idx < config->bNumInterfaces; iface_idx++) {
820                 const struct libusb_interface *iface =
821                     &config->interface[iface_idx];
822                 int altsetting_idx;
823
824                 for (altsetting_idx = 0; altsetting_idx < iface->num_altsetting;
825                     altsetting_idx++) {
826                         const struct libusb_interface_descriptor *altsetting =
827                             &iface->altsetting[altsetting_idx];
828                         int ep_idx;
829
830                         for (ep_idx = 0; ep_idx < altsetting->bNumEndpoints;
831                             ep_idx++) {
832                                 const struct libusb_endpoint_descriptor *ep =
833                                         &altsetting->endpoint[ep_idx];
834                                 if (ep->bEndpointAddress == endpoint) {
835                                         *interface = iface_idx;
836                                         libusb_free_config_descriptor(config);
837
838                                         return (LIBUSB_SUCCESS);
839                                 }
840                         }
841                 }
842         }
843         libusb_free_config_descriptor(config);
844
845         return (LIBUSB_ERROR_INVALID_PARAM);
846 }
847
848 static int
849 sunos_check_device_and_status_open(struct libusb_device_handle *hdl,
850     uint8_t ep_addr, int ep_type)
851 {
852         char    filename[PATH_MAX + 1], statfilename[PATH_MAX + 1];
853         char    cfg_num[16], alt_num[16];
854         int     fd, fdstat, mode;
855         uint8_t ifc = 0;
856         uint8_t ep_index;
857         sunos_dev_handle_priv_t *hpriv;
858
859         usbi_dbg("open ep 0x%02x", ep_addr);
860         hpriv = (sunos_dev_handle_priv_t *)hdl->os_priv;
861         ep_index = sunos_usb_ep_index(ep_addr);
862         /* ep already opened */
863         if ((hpriv->eps[ep_index].datafd > 0) &&
864             (hpriv->eps[ep_index].statfd > 0)) {
865                 usbi_dbg("ep 0x%02x already opened, return success",
866                         ep_addr);
867
868                 return (0);
869         }
870
871         if (sunos_find_interface(hdl, ep_addr, &ifc) < 0) {
872                 usbi_dbg("can't find interface for endpoint 0x%02x",
873                     ep_addr);
874
875                 return (EACCES);
876         }
877
878         /* create filename */
879         if (hpriv->config_index > 0) {
880                 (void) snprintf(cfg_num, sizeof (cfg_num), "cfg%d",
881                     hpriv->config_index + 1);
882         } else {
883                 bzero(cfg_num, sizeof (cfg_num));
884         }
885
886         if (hpriv->altsetting[ifc] > 0) {
887                 (void) snprintf(alt_num, sizeof (alt_num), ".%d",
888                     hpriv->altsetting[ifc]);
889         } else {
890                 bzero(alt_num, sizeof (alt_num));
891         }
892
893         (void) snprintf(filename, PATH_MAX, "%s/%sif%d%s%s%d",
894             hpriv->dpriv->ugenpath, cfg_num, ifc, alt_num,
895             (ep_addr & LIBUSB_ENDPOINT_DIR_MASK) ? "in" :
896             "out", (ep_addr & LIBUSB_ENDPOINT_ADDRESS_MASK));
897         (void) snprintf(statfilename, PATH_MAX, "%sstat", filename);
898
899         /*
900          * In case configuration has been switched, the xfer endpoint needs
901          * to be opened before the status endpoint, due to a ugen issue.
902          * However, to enable the one transfer mode for an Interrupt-In pipe,
903          * the status endpoint needs to be opened before the xfer endpoint.
904          * So, open the xfer mode first and close it immediately
905          * as a workaround. This will handle the configuration switch.
906          * Then, open the status endpoint.  If for an Interrupt-in pipe,
907          * write the USB_EP_INTR_ONE_XFER control to the status endpoint
908          * to enable the one transfer mode.  Then, re-open the xfer mode.
909          */
910         if (ep_type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
911                 mode = O_RDWR;
912         } else if (ep_addr & LIBUSB_ENDPOINT_IN) {
913                 mode = O_RDONLY;
914         } else {
915                 mode = O_WRONLY;
916         }
917         /* Open the xfer endpoint first */
918         if ((fd = open(filename, mode)) == -1) {
919                 usbi_dbg("can't open %s: errno %d (%s)", filename, errno,
920                     strerror(errno));
921
922                 return (errno);
923         }
924         /* And immediately close the xfer endpoint */
925         (void) close(fd);
926
927         /*
928          * Open the status endpoint.
929          * If for an Interrupt-IN pipe, need to enable the one transfer mode
930          * by writing USB_EP_INTR_ONE_XFER control to the status endpoint
931          * before opening the xfer endpoint
932          */
933         if ((ep_type == LIBUSB_TRANSFER_TYPE_INTERRUPT) &&
934             (ep_addr & LIBUSB_ENDPOINT_IN)) {
935                 char    control = USB_EP_INTR_ONE_XFER;
936                 int     count;
937
938                 /* Open the status endpoint with RDWR */
939                 if ((fdstat = open(statfilename, O_RDWR)) == -1) {
940                         usbi_dbg("can't open %s RDWR: errno %d (%s)",
941                                 statfilename, errno, strerror(errno));
942
943                         return (errno);
944                 } else {
945                         count = write(fdstat, &control, sizeof (control));
946                         if (count != 1) {
947                                 /* this should have worked */
948                                 usbi_dbg("can't write to %s: errno %d (%s)",
949                                         statfilename, errno, strerror(errno));
950                                 (void) close(fdstat);
951
952                                 return (errno);
953                         }
954                 }
955         } else {
956                 if ((fdstat = open(statfilename, O_RDONLY)) == -1) {
957                         usbi_dbg("can't open %s: errno %d (%s)", statfilename, errno,
958                                 strerror(errno));
959
960                         return (errno);
961                 }
962         }
963
964         /* Re-open the xfer endpoint */
965         if ((fd = open(filename, mode)) == -1) {
966                 usbi_dbg("can't open %s: errno %d (%s)", filename, errno,
967                         strerror(errno));
968                 (void) close(fdstat);
969
970                 return (errno);
971         }
972
973         hpriv->eps[ep_index].datafd = fd;
974         hpriv->eps[ep_index].statfd = fdstat;
975         usbi_dbg("ep=0x%02x datafd=%d, statfd=%d", ep_addr, fd, fdstat);
976
977         return (0);
978 }
979
980 int
981 sunos_open(struct libusb_device_handle *handle)
982 {
983         sunos_dev_handle_priv_t *hpriv;
984         sunos_dev_priv_t        *dpriv;
985         int     i;
986         int     ret;
987
988         hpriv = (sunos_dev_handle_priv_t *)handle->os_priv;
989         dpriv = (sunos_dev_priv_t *)handle->dev->os_priv;
990         hpriv->dpriv = dpriv;
991
992         /* set all file descriptors to "closed" */
993         for (i = 0; i < USB_MAXENDPOINTS; i++) {
994                 hpriv->eps[i].datafd = -1;
995                 hpriv->eps[i].statfd = -1;
996         }
997
998         if (sunos_kernel_driver_active(handle, 0)) {
999                 /* pretend we can open the device */
1000                 return (LIBUSB_SUCCESS);
1001         }
1002
1003         if ((ret = sunos_usb_open_ep0(hpriv, dpriv)) != LIBUSB_SUCCESS) {
1004                 usbi_dbg("fail: %d", ret);
1005                 return (ret);
1006         }
1007
1008         return (LIBUSB_SUCCESS);
1009 }
1010
1011 void
1012 sunos_close(struct libusb_device_handle *handle)
1013 {
1014         sunos_dev_handle_priv_t *hpriv;
1015         sunos_dev_priv_t *dpriv;
1016
1017         usbi_dbg("");
1018         if (!handle) {
1019                 return;
1020         }
1021
1022         hpriv = (sunos_dev_handle_priv_t *)handle->os_priv;
1023         if (!hpriv) {
1024                 return;
1025         }
1026         dpriv = (sunos_dev_priv_t *)handle->dev->os_priv;
1027         if (!dpriv) {
1028                 return;
1029         }
1030
1031         sunos_usb_close_all_eps(hpriv);
1032         sunos_usb_close_ep0(hpriv, dpriv);
1033 }
1034
1035 int
1036 sunos_get_device_descriptor(struct libusb_device *dev, uint8_t *buf,
1037     int *host_endian)
1038 {
1039         sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv;
1040
1041         memcpy(buf, &dpriv->dev_descr, LIBUSB_DT_DEVICE_SIZE);
1042         *host_endian = 0;
1043
1044         return (LIBUSB_SUCCESS);
1045 }
1046
1047 int
1048 sunos_get_active_config_descriptor(struct libusb_device *dev,
1049     uint8_t *buf, size_t len, int *host_endian)
1050 {
1051         sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv;
1052         struct libusb_config_descriptor *cfg;
1053         int proplen;
1054         di_node_t node;
1055         uint8_t *rdata;
1056
1057         /*
1058          * Keep raw configuration descriptors updated, in case config
1059          * has ever been changed through setCfg.
1060          */
1061         if ((node = di_init(dpriv->phypath, DINFOCPYALL)) == DI_NODE_NIL) {
1062                 usbi_dbg("di_int() failed: errno %d (%s)", errno,
1063                         strerror(errno));
1064                 return (LIBUSB_ERROR_IO);
1065         }
1066         proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
1067             "usb-raw-cfg-descriptors", &rdata);
1068         if (proplen <= 0) {
1069                 usbi_dbg("can't find raw config descriptors");
1070
1071                 return (LIBUSB_ERROR_IO);
1072         }
1073         dpriv->raw_cfgdescr = realloc(dpriv->raw_cfgdescr, proplen);
1074         if (dpriv->raw_cfgdescr == NULL) {
1075                 return (LIBUSB_ERROR_NO_MEM);
1076         } else {
1077                 bcopy(rdata, dpriv->raw_cfgdescr, proplen);
1078                 dpriv->cfgvalue = ((struct libusb_config_descriptor *)
1079                     rdata)->bConfigurationValue;
1080         }
1081         di_fini(node);
1082
1083         cfg = (struct libusb_config_descriptor *)dpriv->raw_cfgdescr;
1084         len = MIN(len, libusb_le16_to_cpu(cfg->wTotalLength));
1085         memcpy(buf, dpriv->raw_cfgdescr, len);
1086         *host_endian = 0;
1087         usbi_dbg("path:%s len %" PRIuPTR, dpriv->phypath, len);
1088
1089         return (len);
1090 }
1091
1092 int
1093 sunos_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
1094     uint8_t *buf, size_t len, int *host_endian)
1095 {
1096         /* XXX */
1097         return(sunos_get_active_config_descriptor(dev, buf, len, host_endian));
1098 }
1099
1100 int
1101 sunos_get_configuration(struct libusb_device_handle *handle, int *config)
1102 {
1103         sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)handle->dev->os_priv;
1104
1105         *config = dpriv->cfgvalue;
1106
1107         usbi_dbg("bConfigurationValue %d", *config);
1108
1109         return (LIBUSB_SUCCESS);
1110 }
1111
1112 int
1113 sunos_set_configuration(struct libusb_device_handle *handle, int config)
1114 {
1115         sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)handle->dev->os_priv;
1116         sunos_dev_handle_priv_t *hpriv;
1117
1118         usbi_dbg("bConfigurationValue %d", config);
1119         hpriv = (sunos_dev_handle_priv_t *)handle->os_priv;
1120
1121         if (dpriv->ugenpath == NULL)
1122                 return (LIBUSB_ERROR_NOT_SUPPORTED);
1123
1124         if (config < 1 || config > dpriv->dev_descr.bNumConfigurations)
1125                 return (LIBUSB_ERROR_INVALID_PARAM);
1126
1127         dpriv->cfgvalue = config;
1128         hpriv->config_index = config - 1;
1129
1130         return (LIBUSB_SUCCESS);
1131 }
1132
1133 int
1134 sunos_claim_interface(struct libusb_device_handle *handle, int iface)
1135 {
1136         usbi_dbg("iface %d", iface);
1137         if (iface < 0) {
1138                 return (LIBUSB_ERROR_INVALID_PARAM);
1139         }
1140
1141         return (LIBUSB_SUCCESS);
1142 }
1143
1144 int
1145 sunos_release_interface(struct libusb_device_handle *handle, int iface)
1146 {
1147         sunos_dev_handle_priv_t *hpriv =
1148             (sunos_dev_handle_priv_t *)handle->os_priv;
1149
1150         usbi_dbg("iface %d", iface);
1151         if (iface < 0) {
1152                 return (LIBUSB_ERROR_INVALID_PARAM);
1153         }
1154
1155         /* XXX: can we release it? */
1156         hpriv->altsetting[iface] = 0;
1157
1158         return (LIBUSB_SUCCESS);
1159 }
1160
1161 int
1162 sunos_set_interface_altsetting(struct libusb_device_handle *handle, int iface,
1163     int altsetting)
1164 {
1165         sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)handle->dev->os_priv;
1166         sunos_dev_handle_priv_t *hpriv =
1167             (sunos_dev_handle_priv_t *)handle->os_priv;
1168
1169         usbi_dbg("iface %d, setting %d", iface, altsetting);
1170
1171         if (iface < 0 || altsetting < 0) {
1172                 return (LIBUSB_ERROR_INVALID_PARAM);
1173         }
1174         if (dpriv->ugenpath == NULL)
1175                 return (LIBUSB_ERROR_NOT_FOUND);
1176
1177         /* XXX: can we switch altsetting? */
1178         hpriv->altsetting[iface] = altsetting;
1179
1180         return (LIBUSB_SUCCESS);
1181 }
1182
1183 static void
1184 usb_dump_data(unsigned char *data, size_t size)
1185 {
1186         int i;
1187
1188         if (getenv("LIBUSB_DEBUG") == NULL) {
1189                 return;
1190         }
1191
1192         (void) fprintf(stderr, "data dump:");
1193         for (i = 0; i < size; i++) {
1194                 if (i % 16 == 0) {
1195                         (void) fprintf(stderr, "\n%08x  ", i);
1196                 }
1197                 (void) fprintf(stderr, "%02x ", (uchar_t)data[i]);
1198         }
1199         (void) fprintf(stderr, "\n");
1200 }
1201
1202 static void
1203 sunos_async_callback(union sigval arg)
1204 {
1205         struct sunos_transfer_priv *tpriv =
1206             (struct sunos_transfer_priv *)arg.sival_ptr;
1207         struct libusb_transfer *xfer = tpriv->transfer;
1208         struct aiocb *aiocb = &tpriv->aiocb;
1209         int ret;
1210         sunos_dev_handle_priv_t *hpriv;
1211         uint8_t ep;
1212         libusb_device_handle *dev_handle;
1213
1214         dev_handle = xfer->dev_handle;
1215
1216         /* libusb can forcibly interrupt transfer in do_close() */
1217         if (dev_handle != NULL) {
1218                 hpriv = (sunos_dev_handle_priv_t *)dev_handle->os_priv;
1219                 ep = sunos_usb_ep_index(xfer->endpoint);
1220
1221                 ret = aio_error(aiocb);
1222                 if (ret != 0) {
1223                         xfer->status = sunos_usb_get_status(hpriv->eps[ep].statfd);
1224                 } else {
1225                         xfer->actual_length =
1226                             LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer)->transferred =
1227                             aio_return(aiocb);
1228                 }
1229
1230                 usb_dump_data(xfer->buffer, xfer->actual_length);
1231
1232                 usbi_dbg("ret=%d, len=%d, actual_len=%d", ret, xfer->length,
1233                     xfer->actual_length);
1234
1235                 /* async notification */
1236                 usbi_signal_transfer_completion(LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer));
1237         }
1238 }
1239
1240 static int
1241 sunos_do_async_io(struct libusb_transfer *transfer)
1242 {
1243         int ret = -1;
1244         struct aiocb *aiocb;
1245         sunos_dev_handle_priv_t *hpriv;
1246         uint8_t ep;
1247         struct sunos_transfer_priv *tpriv;
1248
1249         usbi_dbg("");
1250
1251         tpriv = usbi_transfer_get_os_priv(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer));
1252         hpriv = (sunos_dev_handle_priv_t *)transfer->dev_handle->os_priv;
1253         ep = sunos_usb_ep_index(transfer->endpoint);
1254
1255         tpriv->transfer = transfer;
1256         aiocb = &tpriv->aiocb;
1257         bzero(aiocb, sizeof (*aiocb));
1258         aiocb->aio_fildes = hpriv->eps[ep].datafd;
1259         aiocb->aio_buf = transfer->buffer;
1260         aiocb->aio_nbytes = transfer->length;
1261         aiocb->aio_lio_opcode =
1262             ((transfer->endpoint & LIBUSB_ENDPOINT_DIR_MASK) ==
1263             LIBUSB_ENDPOINT_IN) ? LIO_READ:LIO_WRITE;
1264         aiocb->aio_sigevent.sigev_notify = SIGEV_THREAD;
1265         aiocb->aio_sigevent.sigev_value.sival_ptr = tpriv;
1266         aiocb->aio_sigevent.sigev_notify_function = sunos_async_callback;
1267
1268         if (aiocb->aio_lio_opcode == LIO_READ) {
1269                 ret = aio_read(aiocb);
1270         } else {
1271                 ret = aio_write(aiocb);
1272         }
1273
1274         return (ret);
1275 }
1276
1277 /* return the number of bytes read/written */
1278 static int
1279 usb_do_io(int fd, int stat_fd, char *data, size_t size, int flag, int *status)
1280 {
1281         int error;
1282         int ret = -1;
1283
1284         usbi_dbg("usb_do_io(): datafd=%d statfd=%d size=0x%" PRIxPTR " flag=%s",
1285             fd, stat_fd, size, flag? "WRITE":"READ");
1286
1287         switch (flag) {
1288         case READ:
1289                 errno = 0;
1290                 ret = read(fd, data, size);
1291                 usb_dump_data(data, size);
1292                 break;
1293         case WRITE:
1294                 usb_dump_data(data, size);
1295                 errno = 0;
1296                 ret = write(fd, data, size);
1297                 break;
1298         }
1299
1300         usbi_dbg("usb_do_io(): amount=%d", ret);
1301
1302         if (ret < 0) {
1303                 int save_errno = errno;
1304
1305                 usbi_dbg("TID=%x io %s errno %d (%s)", pthread_self(),
1306                     flag?"WRITE":"READ", errno, strerror(errno));
1307
1308                 /* sunos_usb_get_status will do a read and overwrite errno */
1309                 error = sunos_usb_get_status(stat_fd);
1310                 usbi_dbg("io status=%d errno %d (%s)", error,
1311                         save_errno, strerror(save_errno));
1312
1313                 if (status) {
1314                         *status = save_errno;
1315                 }
1316
1317                 return (save_errno);
1318
1319         } else if (status) {
1320                 *status = 0;
1321         }
1322
1323         return (ret);
1324 }
1325
1326 static int
1327 solaris_submit_ctrl_on_default(struct libusb_transfer *transfer)
1328 {
1329         int             ret = -1, setup_ret;
1330         int             status;
1331         sunos_dev_handle_priv_t *hpriv;
1332         struct          libusb_device_handle *hdl = transfer->dev_handle;
1333         uint16_t        wLength;
1334         uint8_t         *data = transfer->buffer;
1335
1336         hpriv = (sunos_dev_handle_priv_t *)hdl->os_priv;
1337         wLength = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
1338
1339         if (hpriv->eps[0].datafd == -1) {
1340                 usbi_dbg("ep0 not opened");
1341
1342                 return (LIBUSB_ERROR_NOT_FOUND);
1343         }
1344
1345         if ((data[0] & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) {
1346                 usbi_dbg("IN request");
1347                 ret = usb_do_io(hpriv->eps[0].datafd,
1348                     hpriv->eps[0].statfd, (char *)data, LIBUSB_CONTROL_SETUP_SIZE,
1349                     WRITE, (int *)&status);
1350         } else {
1351                 usbi_dbg("OUT request");
1352                 ret = usb_do_io(hpriv->eps[0].datafd, hpriv->eps[0].statfd,
1353                     transfer->buffer, transfer->length, WRITE,
1354                     (int *)&transfer->status);
1355         }
1356
1357         setup_ret = ret;
1358         if (ret < LIBUSB_CONTROL_SETUP_SIZE) {
1359                 usbi_dbg("error sending control msg: %d", ret);
1360
1361                 return (LIBUSB_ERROR_IO);
1362         }
1363
1364         ret = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
1365
1366         /* Read the remaining bytes for IN request */
1367         if ((wLength) && ((data[0] & LIBUSB_ENDPOINT_DIR_MASK) ==
1368             LIBUSB_ENDPOINT_IN)) {
1369                 usbi_dbg("DATA: %d", transfer->length - setup_ret);
1370                 ret = usb_do_io(hpriv->eps[0].datafd,
1371                         hpriv->eps[0].statfd,
1372                         (char *)transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE,
1373                         wLength, READ, (int *)&transfer->status);
1374         }
1375
1376         if (ret >= 0) {
1377                 transfer->actual_length = ret;
1378                 LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->transferred = ret;
1379         }
1380         usbi_dbg("Done: ctrl data bytes %d", ret);
1381
1382         /**
1383          * Sync transfer handling.
1384          * We should release transfer lock here and later get it back
1385          * as usbi_handle_transfer_completion() takes its own transfer lock.
1386          */
1387         usbi_mutex_unlock(&LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->lock);
1388         ret = usbi_handle_transfer_completion(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer),
1389             transfer->status);
1390         usbi_mutex_lock(&LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->lock);
1391
1392         return (ret);
1393 }
1394
1395 int
1396 sunos_clear_halt(struct libusb_device_handle *handle, uint8_t endpoint)
1397 {
1398         int ret;
1399
1400         usbi_dbg("endpoint=0x%02x", endpoint);
1401
1402         ret = libusb_control_transfer(handle, LIBUSB_ENDPOINT_OUT |
1403             LIBUSB_RECIPIENT_ENDPOINT | LIBUSB_REQUEST_TYPE_STANDARD,
1404             LIBUSB_REQUEST_CLEAR_FEATURE, 0, endpoint, NULL, 0, 1000);
1405
1406         usbi_dbg("ret=%d", ret);
1407
1408         return (ret);
1409 }
1410
1411 int
1412 sunos_reset_device(struct libusb_device_handle *handle)
1413 {
1414         usbi_dbg("");
1415
1416         return (LIBUSB_ERROR_NOT_SUPPORTED);
1417 }
1418
1419 void
1420 sunos_destroy_device(struct libusb_device *dev)
1421 {
1422         sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv;
1423         usbi_dbg("destroy everyting");
1424         free(dpriv->raw_cfgdescr);
1425         free(dpriv->ugenpath);
1426         free(dpriv->phypath);
1427 }
1428
1429 int
1430 sunos_submit_transfer(struct usbi_transfer *itransfer)
1431 {
1432         struct  libusb_transfer *transfer;
1433         struct  libusb_device_handle *hdl;
1434         int     err = 0;
1435
1436         transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
1437         hdl = transfer->dev_handle;
1438
1439         err = sunos_check_device_and_status_open(hdl,
1440             transfer->endpoint, transfer->type);
1441         if (err < 0) {
1442
1443                 return (_errno_to_libusb(err));
1444         }
1445
1446         switch (transfer->type) {
1447         case LIBUSB_TRANSFER_TYPE_CONTROL:
1448                 /* sync transfer */
1449                 usbi_dbg("CTRL transfer: %d", transfer->length);
1450                 err = solaris_submit_ctrl_on_default(transfer);
1451                 break;
1452
1453         case LIBUSB_TRANSFER_TYPE_BULK:
1454                 /* fallthru */
1455         case LIBUSB_TRANSFER_TYPE_INTERRUPT:
1456                 if (transfer->type == LIBUSB_TRANSFER_TYPE_BULK)
1457                         usbi_dbg("BULK transfer: %d", transfer->length);
1458                 else
1459                         usbi_dbg("INTR transfer: %d", transfer->length);
1460                 err = sunos_do_async_io(transfer);
1461                 break;
1462
1463         case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
1464                 /* Isochronous/Stream is not supported */
1465
1466                 /* fallthru */
1467         case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
1468                 if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS)
1469                         usbi_dbg("ISOC transfer: %d", transfer->length);
1470                 else
1471                         usbi_dbg("BULK STREAM transfer: %d", transfer->length);
1472                 err = LIBUSB_ERROR_NOT_SUPPORTED;
1473                 break;
1474         }
1475
1476         return (err);
1477 }
1478
1479 int
1480 sunos_cancel_transfer(struct usbi_transfer *itransfer)
1481 {
1482         sunos_xfer_priv_t       *tpriv;
1483         sunos_dev_handle_priv_t *hpriv;
1484         struct libusb_transfer  *transfer;
1485         struct aiocb    *aiocb;
1486         uint8_t         ep;
1487         int             ret;
1488
1489         tpriv = usbi_transfer_get_os_priv(itransfer);
1490         aiocb = &tpriv->aiocb;
1491         transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
1492         hpriv = (sunos_dev_handle_priv_t *)transfer->dev_handle->os_priv;
1493         ep = sunos_usb_ep_index(transfer->endpoint);
1494
1495         ret = aio_cancel(hpriv->eps[ep].datafd, aiocb);
1496
1497         usbi_dbg("aio->fd=%d fd=%d ret = %d, %s", aiocb->aio_fildes,
1498             hpriv->eps[ep].datafd, ret, (ret == AIO_CANCELED)?
1499             strerror(0):strerror(errno));
1500
1501         if (ret != AIO_CANCELED) {
1502                 ret = _errno_to_libusb(errno);
1503         } else {
1504         /*
1505          * we don't need to call usbi_handle_transfer_cancellation(),
1506          * because we'll handle everything in sunos_async_callback.
1507          */
1508                 ret = LIBUSB_SUCCESS;
1509         }
1510
1511         return (ret);
1512 }
1513
1514 void
1515 sunos_clear_transfer_priv(struct usbi_transfer *itransfer)
1516 {
1517         usbi_dbg("");
1518
1519         /* Nothing to do */
1520 }
1521
1522 int
1523 sunos_handle_transfer_completion(struct usbi_transfer *itransfer)
1524 {
1525         return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
1526 }
1527
1528 int
1529 sunos_clock_gettime(int clkid, struct timespec *tp)
1530 {
1531         if (clkid == USBI_CLOCK_REALTIME)
1532                 return clock_gettime(CLOCK_REALTIME, tp);
1533
1534         if (clkid == USBI_CLOCK_MONOTONIC)
1535                 return clock_gettime(CLOCK_MONOTONIC, tp);
1536
1537         return (LIBUSB_ERROR_INVALID_PARAM);
1538 }
1539
1540 int
1541 _errno_to_libusb(int err)
1542 {
1543         usbi_dbg("error: %s (%d)", strerror(err), err);
1544
1545         switch (err) {
1546         case EIO:
1547                 return (LIBUSB_ERROR_IO);
1548         case EACCES:
1549                 return (LIBUSB_ERROR_ACCESS);
1550         case ENOENT:
1551                 return (LIBUSB_ERROR_NO_DEVICE);
1552         case ENOMEM:
1553                 return (LIBUSB_ERROR_NO_MEM);
1554         case ETIMEDOUT:
1555                 return (LIBUSB_ERROR_TIMEOUT);
1556         }
1557
1558         return (LIBUSB_ERROR_OTHER);
1559 }
1560
1561 /*
1562  * sunos_usb_get_status:
1563  *      gets status of endpoint
1564  *
1565  * Returns: ugen's last cmd status
1566  */
1567 static int
1568 sunos_usb_get_status(int fd)
1569 {
1570         int status, ret;
1571
1572         usbi_dbg("sunos_usb_get_status(): fd=%d", fd);
1573
1574         ret = read(fd, &status, sizeof (status));
1575         if (ret == sizeof (status)) {
1576                 switch (status) {
1577                 case USB_LC_STAT_NOERROR:
1578                         usbi_dbg("No Error");
1579                         break;
1580                 case USB_LC_STAT_CRC:
1581                         usbi_dbg("CRC Timeout Detected\n");
1582                         break;
1583                 case USB_LC_STAT_BITSTUFFING:
1584                         usbi_dbg("Bit Stuffing Violation\n");
1585                         break;
1586                 case USB_LC_STAT_DATA_TOGGLE_MM:
1587                         usbi_dbg("Data Toggle Mismatch\n");
1588                         break;
1589                 case USB_LC_STAT_STALL:
1590                         usbi_dbg("End Point Stalled\n");
1591                         break;
1592                 case USB_LC_STAT_DEV_NOT_RESP:
1593                         usbi_dbg("Device is Not Responding\n");
1594                         break;
1595                 case USB_LC_STAT_PID_CHECKFAILURE:
1596                         usbi_dbg("PID Check Failure\n");
1597                         break;
1598                 case USB_LC_STAT_UNEXP_PID:
1599                         usbi_dbg("Unexpected PID\n");
1600                         break;
1601                 case USB_LC_STAT_DATA_OVERRUN:
1602                         usbi_dbg("Data Exceeded Size\n");
1603                         break;
1604                 case USB_LC_STAT_DATA_UNDERRUN:
1605                         usbi_dbg("Less data received\n");
1606                         break;
1607                 case USB_LC_STAT_BUFFER_OVERRUN:
1608                         usbi_dbg("Buffer Size Exceeded\n");
1609                         break;
1610                 case USB_LC_STAT_BUFFER_UNDERRUN:
1611                         usbi_dbg("Buffer Underrun\n");
1612                         break;
1613                 case USB_LC_STAT_TIMEOUT:
1614                         usbi_dbg("Command Timed Out\n");
1615                         break;
1616                 case USB_LC_STAT_NOT_ACCESSED:
1617                         usbi_dbg("Not Accessed by h/w\n");
1618                         break;
1619                 case USB_LC_STAT_UNSPECIFIED_ERR:
1620                         usbi_dbg("Unspecified Error\n");
1621                         break;
1622                 case USB_LC_STAT_NO_BANDWIDTH:
1623                         usbi_dbg("No Bandwidth\n");
1624                         break;
1625                 case USB_LC_STAT_HW_ERR:
1626                         usbi_dbg("Host Controller h/w Error\n");
1627                         break;
1628                 case USB_LC_STAT_SUSPENDED:
1629                         usbi_dbg("Device was Suspended\n");
1630                         break;
1631                 case USB_LC_STAT_DISCONNECTED:
1632                         usbi_dbg("Device was Disconnected\n");
1633                         break;
1634                 case USB_LC_STAT_INTR_BUF_FULL:
1635                         usbi_dbg("Interrupt buffer was full\n");
1636                         break;
1637                 case USB_LC_STAT_INVALID_REQ:
1638                         usbi_dbg("Request was Invalid\n");
1639                         break;
1640                 case USB_LC_STAT_INTERRUPTED:
1641                         usbi_dbg("Request was Interrupted\n");
1642                         break;
1643                 case USB_LC_STAT_NO_RESOURCES:
1644                         usbi_dbg("No resources available for "
1645                             "request\n");
1646                         break;
1647                 case USB_LC_STAT_INTR_POLLING_FAILED:
1648                         usbi_dbg("Failed to Restart Poll");
1649                         break;
1650                 default:
1651                         usbi_dbg("Error Not Determined %d\n",
1652                             status);
1653                         break;
1654                 }
1655         } else {
1656                 usbi_dbg("read stat error: %s",strerror(errno));
1657                 status = -1;
1658         }
1659
1660         return (status);
1661 }
1662
1663 #ifdef USBI_TIMERFD_AVAILABLE
1664 static clockid_t op_get_timerfd_clockid(void)
1665 {
1666        return CLOCK_MONOTONIC;
1667 }
1668 #endif
1669
1670 const struct usbi_os_backend usbi_backend = {
1671         .name = "Solaris",
1672         .caps = 0,
1673         .init = sunos_init,
1674         .exit = sunos_exit,
1675         .get_device_list = sunos_get_device_list,
1676         .get_device_descriptor = sunos_get_device_descriptor,
1677         .get_active_config_descriptor = sunos_get_active_config_descriptor,
1678         .get_config_descriptor = sunos_get_config_descriptor,
1679         .hotplug_poll = NULL,
1680         .open = sunos_open,
1681         .close = sunos_close,
1682         .get_configuration = sunos_get_configuration,
1683         .set_configuration = sunos_set_configuration,
1684
1685         .claim_interface = sunos_claim_interface,
1686         .release_interface = sunos_release_interface,
1687         .set_interface_altsetting = sunos_set_interface_altsetting,
1688         .clear_halt = sunos_clear_halt,
1689         .reset_device = sunos_reset_device, /* TODO */
1690         .alloc_streams = NULL,
1691         .free_streams = NULL,
1692         .kernel_driver_active = sunos_kernel_driver_active,
1693         .detach_kernel_driver = sunos_detach_kernel_driver,
1694         .attach_kernel_driver = sunos_attach_kernel_driver,
1695         .destroy_device = sunos_destroy_device,
1696         .submit_transfer = sunos_submit_transfer,
1697         .cancel_transfer = sunos_cancel_transfer,
1698         .handle_events = NULL,
1699         .clear_transfer_priv = sunos_clear_transfer_priv,
1700         .handle_transfer_completion = sunos_handle_transfer_completion,
1701         .clock_gettime = sunos_clock_gettime,
1702 #ifdef USBI_TIMERFD_AVAILABLE
1703         .get_timerfd_clockid = op_get_timerfd_clockid,
1704 #endif
1705         .device_priv_size = sizeof(sunos_dev_priv_t),
1706         .device_handle_priv_size = sizeof(sunos_dev_handle_priv_t),
1707         .transfer_priv_size = sizeof(sunos_xfer_priv_t),
1708 };