summaryrefslogtreecommitdiff
path: root/kernel/OS/SunOS/udi.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/OS/SunOS/udi.c')
-rw-r--r--kernel/OS/SunOS/udi.c1365
1 files changed, 1365 insertions, 0 deletions
diff --git a/kernel/OS/SunOS/udi.c b/kernel/OS/SunOS/udi.c
new file mode 100644
index 0000000..ad4d4fa
--- /dev/null
+++ b/kernel/OS/SunOS/udi.c
@@ -0,0 +1,1365 @@
+/*
+ * Purpose: USB device interface (udi.h) routines for Solaris
+ */
+/*
+ *
+ * This file is part of Open Sound System.
+ *
+ * Copyright (C) 4Front Technologies 1996-2008.
+ *
+ * This this source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ */
+#if !defined(SOL9)
+#include "oss_config.h"
+#include <udi.h>
+
+#define USBDRV_MAJOR_VER 2
+#define USBDRV_MINOR_VER 0
+#include <sys/usb/usba.h>
+#include <sys/strsubr.h>
+
+#undef IO_DEBUG
+int udi_usb_trace = 0;
+
+#define MAX_DEVICE_SLOTS 20
+
+struct udi_usb_devc
+{
+ oss_device_t *osdev;
+ usb_client_dev_data_t *dev_data;
+ char *name;
+
+ const struct usb_device_id *id;
+ const udi_usb_devinfo *udi_usb_dev;
+ char devpath[32];
+
+ int enabled;
+
+ struct usb_interface *iface;
+ udi_usb_driver *drv;
+ void *client_devc;
+ void (*client_disconnect) (void *devc);
+};
+
+#define MAX_DEVC 32
+
+int
+udi_attach_usbdriver (oss_device_t * osdev, const udi_usb_devinfo * devlist,
+ udi_usb_driver * driver)
+{
+ int err, i, nalt, vendor, product, busaddr;
+ udi_usb_devc *usbdev;
+ dev_info_t *dip = osdev->dip;
+ char *name;
+ unsigned long osid;
+ //usb_alt_if_data_t *altif_data;
+ usb_client_dev_data_t *dev_data;
+
+ if (dip==NULL)
+ {
+ cmn_err(CE_WARN, "dip==NULL\n");
+ return 0;
+ }
+
+ name = ddi_get_name (osdev->dip);
+
+ if (strcmp (name, "oss_usb") == 0)
+ {
+ oss_register_device (osdev, "USB audio/MIDI device");
+ return 1;
+ }
+
+ /*
+ * Select the default configuration
+ */
+ if ((err = usb_set_cfg (osdev->dip, USB_DEV_DEFAULT_CONFIG_INDEX,
+ USB_FLAGS_SLEEP, NULL, NULL)) == USB_SUCCESS)
+ {
+ cmn_err (CE_CONT, "usb_set_cfg returned %d\n", err);
+ }
+
+ busaddr = ddi_prop_get_int (DDI_DEV_T_ANY, osdev->dip,
+ DDI_PROP_NOTPROM, "assigned-address", 1234);
+ if ((usbdev = KERNEL_MALLOC (sizeof (*usbdev))) == NULL)
+ {
+ cmn_err (CE_WARN, "udi_attach_usbdriver: Out of memory\n");
+ return 0;
+ }
+
+ memset (usbdev, 0, sizeof (*usbdev));
+ osdev->usbdev = usbdev;
+ usbdev->osdev = osdev;
+
+ if ((err = usb_client_attach (dip, USBDRV_VERSION, 0)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_client_attach failed, err=%d\n", err);
+ KERNEL_FREE (usbdev);
+ return 0;
+ }
+
+ if ((err =
+ usb_get_dev_data (osdev->dip, &usbdev->dev_data, USB_PARSE_LVL_CFG,
+ 0)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_get_dev_data failed, err=%d\n", err);
+ KERNEL_FREE (usbdev);
+ return 0;
+ }
+ dev_data = usbdev->dev_data;
+
+ osdev->iblock_cookie = dev_data->dev_iblock_cookie;
+
+ sprintf (usbdev->devpath, "usb%x,%x@port%d", udi_usbdev_get_vendor (usbdev),
+ udi_usbdev_get_product (usbdev), busaddr);
+ oss_register_device (osdev, "USB audio/MIDI device");
+ sprintf (osdev->nick, "usb%x_%x_%d", udi_usbdev_get_vendor (usbdev),
+ udi_usbdev_get_product (usbdev), busaddr);
+
+#if 0
+ if (udi_usb_trace > 5)
+ usb_print_descr_tree (osdev->dip, dev_data);
+#endif
+
+ nalt = 1;
+ if (nalt >= dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if].if_n_alt)
+ nalt = 0;
+
+ //altif_data = &dev_data->dev_curr_cfg->
+ // cfg_if[dev_data->dev_curr_if].if_alt[nalt];
+
+ usbdev->name = usbdev->dev_data->dev_product;
+ vendor = udi_usbdev_get_vendor (usbdev);
+ product = udi_usbdev_get_product (usbdev);
+
+ /* inum = usbdev->dev_data->dev_curr_if; */
+ osid = (vendor << 16) | product;
+ osdev->osid = (void *) osid;
+
+ sprintf (osdev->handle, "usb%x,%x.%d:%d", vendor, product,
+ dev_data->dev_curr_if, osdev->instance);
+
+ for (i = 0; devlist[i].vendor != -1; i++)
+ if (devlist[i].vendor == vendor && devlist[i].product == product)
+ {
+ usbdev->name = devlist[i].name;
+ usbdev->udi_usb_dev = &devlist[i];
+ oss_register_device (osdev, usbdev->name);
+ break;
+ }
+
+ if ((usbdev->client_devc = driver->attach (usbdev, osdev)) == NULL)
+ {
+ cmn_err (CE_WARN, "Client attach failed, err=%d\n", err);
+ udi_unload_usbdriver (osdev);
+ return 0;
+ }
+
+ usbdev->client_disconnect = driver->disconnect;
+
+ return 1;
+}
+
+static char *
+usb_errstr (int err)
+{
+
+ static struct errmsg_
+ {
+ int err;
+ char *str;
+ } errs[] =
+ {
+ {
+ USB_FAILURE, "USB_FAILURE"},
+ {
+ USB_NO_RESOURCES, "USB_NO_RESOURCES"},
+ {
+ USB_NO_BANDWIDTH, "USB_NO_BANDWIDTH"},
+ {
+ USB_NOT_SUPPORTED, "USB_NOT_SUPPORTED"},
+ {
+ USB_PIPE_ERROR, "USB_PIPE_ERROR"},
+ {
+ USB_INVALID_PIPE, "USB_INVALID_PIPE"},
+ {
+ USB_NO_FRAME_NUMBER, "USB_NO_FRAME_NUMBER"},
+ {
+ USB_INVALID_START_FRAME, "USB_INVALID_START_FRAME"},
+ {
+ USB_HC_HARDWARE_ERROR, "USB_HC_HARDWARE_ERROR"},
+ {
+ USB_INVALID_REQUEST, "USB_INVALID_REQUEST"},
+ {
+ USB_INVALID_CONTEXT, "USB_INVALID_CONTEXT"},
+ {
+ USB_INVALID_VERSION, "USB_INVALID_VERSION"},
+ {
+ USB_INVALID_ARGS, "USB_INVALID_ARGS"},
+ {
+ USB_INVALID_PERM, "USB_INVALID_PERM"},
+ {
+ USB_BUSY, "USB_BUSY"},
+ {
+ 0, NULL}
+ };
+
+ int i;
+ static char msg[20];
+
+ for (i = 0; errs[i].err != 0; i++)
+ if (errs[i].err == err)
+ {
+ return errs[i].str;
+ }
+
+ sprintf (msg, "Err %d", err);
+ return msg;
+}
+
+static char *
+usb_cb_err (int err)
+{
+
+ static struct errmsg_
+ {
+ int err;
+ char *str;
+ } errs[] =
+ {
+ {
+ USB_CB_STALL_CLEARED, "USB_CB_STALL_CLEARED"},
+ {
+ USB_CB_FUNCTIONAL_STALL, "USB_CB_FUNCTIONAL_STALL"},
+ {
+ USB_CB_PROTOCOL_STALL, "USB_CB_PROTOCOL_STALL"},
+ {
+ USB_CB_RESET_PIPE, "USB_CB_RESET_PIPE"},
+ {
+ USB_CB_ASYNC_REQ_FAILED, "USB_CB_ASYNC_REQ_FAILED"},
+ {
+ USB_CB_NO_RESOURCES, "USB_CB_NO_RESOURCES"},
+ {
+ USB_CB_SUBMIT_FAILED, "USB_CB_SUBMIT_FAILED"},
+ {
+ USB_CB_INTR_CONTEXT, "USB_CB_INTR_CONTEXT"},
+ {
+ USB_FAILURE, "USB_FAILURE"},
+ {
+ USB_NO_RESOURCES, "USB_NO_RESOURCES"},
+ {
+ USB_NO_BANDWIDTH, "USB_NO_BANDWIDTH"},
+ {
+ USB_NOT_SUPPORTED, "USB_NOT_SUPPORTED"},
+ {
+ USB_PIPE_ERROR, "USB_PIPE_ERROR"},
+ {
+ USB_INVALID_PIPE, "USB_INVALID_PIPE"},
+ {
+ USB_NO_FRAME_NUMBER, "USB_NO_FRAME_NUMBER"},
+ {
+ USB_INVALID_START_FRAME, "USB_INVALID_START_FRAME"},
+ {
+ USB_HC_HARDWARE_ERROR, "USB_HC_HARDWARE_ERROR"},
+ {
+ USB_INVALID_REQUEST, "USB_INVALID_REQUEST"},
+ {
+ USB_INVALID_CONTEXT, "USB_INVALID_CONTEXT"},
+ {
+ USB_INVALID_VERSION, "USB_INVALID_VERSION"},
+ {
+ USB_INVALID_ARGS, "USB_INVALID_ARGS"},
+ {
+ USB_INVALID_PERM, "USB_INVALID_PERM"},
+ {
+ USB_BUSY, "USB_BUSY"},
+ {
+ 0, NULL}
+ };
+
+ int i;
+ static char msg[20];
+
+ if (err == 0)
+ return "USB_CB_NO_INFO";
+
+ for (i = 0; errs[i].err != 0; i++)
+ {
+ if (errs[i].err == err)
+ {
+ return errs[i].str;
+ }
+ }
+
+ sprintf (msg, "CB Err %d", err);
+ return msg;
+}
+
+static char *
+usb_cr_err (int err)
+{
+
+ static struct errmsg_
+ {
+ int err;
+ char *str;
+ } errs[] =
+ {
+ {
+ USB_CR_CRC, "USB_CR_CRC"},
+ {
+ USB_CR_BITSTUFFING, "USB_CR_BITSTUFFING"},
+ {
+ USB_CR_DATA_TOGGLE_MM, "USB_CR_DATA_TOGGLE_MM"},
+ {
+ USB_CR_STALL, "USB_CR_STALL"},
+ {
+ USB_CR_DEV_NOT_RESP, "USB_CR_DEV_NOT_RESP"},
+ {
+ USB_CR_PID_CHECKFAILURE, "USB_CR_PID_CHECKFAILURE"},
+ {
+ USB_CR_UNEXP_PID, "USB_CR_UNEXP_PID"},
+ {
+ USB_CR_DATA_OVERRUN, "USB_CR_DATA_OVERRUN"},
+ {
+ USB_CR_DATA_UNDERRUN, "USB_CR_DATA_UNDERRUN"},
+ {
+ USB_CR_BUFFER_OVERRUN, "USB_CR_BUFFER_OVERRUN"},
+ {
+ USB_CR_BUFFER_UNDERRUN, "USB_CR_BUFFER_UNDERRUN"},
+ {
+ USB_CR_TIMEOUT, "USB_CR_TIMEOUT"},
+ {
+ USB_CR_NOT_ACCESSED, "USB_CR_NOT_ACCESSED"},
+ {
+ USB_CR_NO_RESOURCES, "USB_CR_NO_RESOURCES"},
+ {
+ USB_CR_UNSPECIFIED_ERR, "USB_CR_UNSPECIFIED_ERR"},
+ {
+ USB_CR_STOPPED_POLLING, "USB_CR_STOPPED_POLLING"},
+ {
+ USB_CR_PIPE_CLOSING, "USB_CR_PIPE_CLOSING"},
+ {
+ USB_CR_PIPE_RESET, "USB_CR_PIPE_RESET"},
+ {
+ USB_CR_NOT_SUPPORTED, "USB_CR_NOT_SUPPORTED"},
+ {
+ USB_CR_FLUSHED, "USB_CR_FLUSHED"},
+ {
+ USB_CR_HC_HARDWARE_ERR, "USB_CR_HC_HARDWARE_ERR"},
+ {
+ 0, NULL}
+ };
+
+ int i;
+ static char msg[20];
+
+ if (err == 0)
+ return "USB_CR_OK";
+
+ for (i = 0; errs[i].err != 0; i++)
+ {
+ if (errs[i].err == err)
+ {
+ return errs[i].str;
+ }
+ }
+
+ sprintf (msg, "CR Err %d", err);
+ return msg;
+}
+
+void
+udi_unload_usbdriver (oss_device_t * osdev)
+{
+ udi_usb_devc *usbdev = osdev->usbdev;
+
+ if (usbdev == NULL)
+ return;
+
+ if (usbdev->client_disconnect != NULL)
+ usbdev->client_disconnect (usbdev->client_devc);
+ usb_client_detach (osdev->dip, usbdev->dev_data);
+
+ KERNEL_FREE (usbdev);
+ osdev->usbdev = NULL;
+}
+
+/*
+ * Device access routines
+ */
+
+int
+udi_usbdev_get_class (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->dev_data->dev_curr_cfg->cfg_if[devc->dev_data->dev_curr_if].
+ if_alt[0].altif_descr.bInterfaceClass;
+}
+
+int
+udi_usbdev_get_subclass (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->dev_data->dev_curr_cfg->cfg_if[devc->dev_data->dev_curr_if].
+ if_alt[0].altif_descr.bInterfaceSubClass;
+}
+
+int
+udi_usbdev_get_vendor (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->dev_data->dev_descr->idVendor;
+}
+
+int
+udi_usbdev_get_product (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->dev_data->dev_descr->idProduct;
+}
+
+int
+udi_usbdev_get_inum (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->dev_data->dev_curr_if;
+}
+
+int
+udi_usbdev_set_interface (udi_usb_devc * usbdev, int inum, int altset)
+{
+ //udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ if (usb_set_alt_if (usbdev->osdev->dip, inum, altset, USB_FLAGS_SLEEP,
+ NULL, 0) != USB_SUCCESS)
+ {
+ return OSS_EIO;
+ }
+
+ return 0;
+}
+
+unsigned char *
+udi_usbdev_get_endpoint (udi_usb_devc * usbdev, int altsetting, int n,
+ int *len)
+{
+ usb_alt_if_data_t *altif_data;
+ usb_client_dev_data_t *dev_data;
+
+ *len = 0;
+
+ if (usbdev->dev_data == NULL)
+ {
+ cmn_err (CE_WARN, "Missing USB devdata\n");
+ return NULL;
+ }
+ dev_data = usbdev->dev_data;
+
+ if (altsetting < 0
+ || altsetting >=
+ dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if].if_n_alt)
+ {
+ return NULL;
+ }
+
+ altif_data = &dev_data->dev_curr_cfg->
+ cfg_if[dev_data->dev_curr_if].if_alt[altsetting];
+
+ if (altif_data == NULL)
+ return NULL;
+
+ if (n < 0 || n >= altif_data->altif_n_ep)
+ return NULL;
+
+ *len = altif_data->altif_ep[n].ep_descr.bLength;
+ return (unsigned char *) &altif_data->altif_ep[n].ep_descr;
+}
+
+int
+udi_usbdev_get_num_altsettings (udi_usb_devc * usbdev)
+{
+ //udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+ usb_client_dev_data_t *dev_data;
+
+ dev_data = usbdev->dev_data;
+ return dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if].if_n_alt;
+}
+
+unsigned char *
+udi_usbdev_get_altsetting (udi_usb_devc * usbdev, int nalt, int *size)
+{
+ int i, n;
+ usb_cvs_data_t *cvs;
+ usb_alt_if_data_t *altif_data;
+ usb_client_dev_data_t *dev_data;
+ static unsigned char buf[1024];
+
+ dev_data = usbdev->dev_data;
+ if ((unsigned long) dev_data <= 4096)
+ {
+ cmn_err (CE_WARN, "Internal error: dev_data==NULL)\n");
+ return NULL;
+ }
+
+ if (nalt < 0
+ || nalt >=
+ dev_data->dev_curr_cfg->cfg_if[dev_data->dev_curr_if].if_n_alt)
+ {
+ return NULL;
+ }
+
+ altif_data = &dev_data->dev_curr_cfg->
+ cfg_if[dev_data->dev_curr_if].if_alt[nalt];
+
+ if (altif_data == NULL)
+ return NULL;
+
+ n = 0;
+
+ for (i = 0; i < altif_data->altif_n_cvs; i++)
+ {
+ cvs = &altif_data->altif_cvs[i];
+ memcpy (buf + n, cvs->cvs_buf, cvs->cvs_buf_len);
+ n += cvs->cvs_buf_len;
+ }
+
+ cvs = &altif_data->altif_cvs[0];
+ if (cvs == NULL || cvs->cvs_buf == NULL)
+ return NULL;
+
+ *size = n;
+ return buf;
+}
+
+char *
+udi_usbdev_get_name (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->name;
+}
+
+char *
+udi_usbdev_get_altsetting_labels (udi_usb_devc * usbdev, int if_num,
+ int *default_alt, unsigned int *mask)
+{
+ int i;
+
+ *default_alt = 1;
+ *mask = 0xffffffff;
+
+ if (usbdev->udi_usb_dev == NULL) /* No device definitions available */
+ {
+ return NULL;
+ }
+
+ for (i = 0; usbdev->udi_usb_dev->altsettings[i].altsetting_labels != NULL;
+ i++)
+ if (i == if_num)
+ {
+ *default_alt = usbdev->udi_usb_dev->altsettings[i].default_altsetting;
+ *mask = usbdev->udi_usb_dev->altsettings[i].altsetting_mask;
+ if (*mask == 0)
+ *mask = 0xffffffff;
+ return usbdev->udi_usb_dev->altsettings[i].altsetting_labels;
+ }
+
+ return NULL; /* Not found */
+}
+
+char *
+udi_usbdev_get_string (udi_usb_devc * usbdev, int ix)
+{
+ static char str[256];
+
+ if (usb_get_string_descr
+ (usbdev->osdev->dip, USB_LANG_ID, ix, str,
+ sizeof (str) - 1) != USB_SUCCESS)
+ return NULL;
+ return str;
+}
+
+char *
+udi_usbdev_get_devpath (udi_usb_devc * usbdev)
+{
+ udi_usb_devc *devc = (udi_usb_devc *) usbdev;
+
+ return devc->devpath;
+}
+
+/*ARGSUSED*/
+int
+udi_usb_snd_control_msg (udi_usb_devc * usbdev, unsigned int endpoint,
+ unsigned char rq,
+ unsigned char rqtype,
+ unsigned short value,
+ unsigned short index,
+ void *buf, int len, int timeout)
+{
+
+ int err;
+
+ usb_ctrl_setup_t setup;
+ usb_cr_t completion_reason;
+ usb_cb_flags_t cb_flags;
+ mblk_t *data = NULL;
+
+ if (usbdev == NULL)
+ {
+ cmn_err (CE_CONT, "udi_usb_snd_control_msg: usbdev==NULL\n");
+ return OSS_EFAULT;
+ }
+
+ data = allocb_wait (len + 1, BPRI_HI, STR_NOSIG, NULL);
+
+ memcpy (data->b_wptr, buf, len);
+ data->b_wptr = data->b_rptr + len;
+
+ setup.bmRequestType = rqtype | USB_DEV_REQ_HOST_TO_DEV;
+ setup.bRequest = rq;
+ setup.wValue = value;
+ setup.wIndex = index;
+ setup.wLength = len;
+ setup.attrs = 0;
+
+ if ((err = usb_pipe_ctrl_xfer_wait (usbdev->dev_data->dev_default_ph,
+ &setup,
+ &data,
+ &completion_reason,
+ &cb_flags, 0)) != USB_SUCCESS)
+ {
+ char tmp[128], *s = tmp;
+ unsigned char *p = buf;
+ int i;
+
+ sprintf (s, "Msg (rq=0x%x, val=0x%04x, ix=0x%04x, len=%d): ", rq, value,
+ index, len);
+ for (i = 0; i < len; i++)
+ {
+ s += strlen (s);
+ sprintf (s, "%02x ", p[i]);
+ }
+ cmn_err (CE_CONT, "%s\n", tmp);
+
+ cmn_err (CE_NOTE, "usb_pipe_ctrl_xfer_wait write failed: %s (%s)\n",
+ usb_errstr (err), usb_cb_err (completion_reason));
+ cmn_err (CE_CONT, "bRq %x, wIx %x, wVal %x, wLen %d\n", rq, index,
+ value, len);
+ freemsg (data);
+ return OSS_EIO;
+ }
+
+ freemsg (data);
+ return len;
+}
+
+/*ARGSUSED*/
+int
+udi_usb_rcv_control_msg (udi_usb_devc * usbdev, unsigned int endpoint,
+ unsigned char rq,
+ unsigned char rqtype,
+ unsigned short value,
+ unsigned short index,
+ void *buf, int len, int timeout)
+{
+ int err, l;
+
+ usb_ctrl_setup_t setup;
+ usb_cr_t completion_reason;
+ usb_cb_flags_t cb_flags;
+ mblk_t *data = NULL;
+
+ if (usbdev == NULL)
+ {
+ cmn_err (CE_CONT, "udi_usb_rcv_control_msg: usbdev==NULL\n");
+ return OSS_EFAULT;
+ }
+
+ setup.bmRequestType = rqtype | USB_DEV_REQ_DEV_TO_HOST;
+ setup.bRequest = rq;
+ setup.wValue = value;
+ setup.wIndex = index;
+ setup.wLength = len;
+ setup.attrs = 0;
+
+ if ((err = usb_pipe_ctrl_xfer_wait (usbdev->dev_data->dev_default_ph,
+ &setup,
+ &data,
+ &completion_reason,
+ &cb_flags, 0)) != USB_SUCCESS)
+ {
+ char tmp[128], *s = tmp;
+
+ sprintf (s, "Msg (rq=0x%02x, val=0x%04x, ix=0x%04x, len=%d): ", rq,
+ value, index, len);
+ cmn_err (CE_CONT, "%s\n", tmp);
+ cmn_err (CE_NOTE, "usb_pipe_ctrl_xfer_wait read failed: %s (%s)\n",
+ usb_errstr (err), usb_cb_err (completion_reason));
+ freemsg (data);
+ return OSS_EIO;
+ }
+
+ /*LINTED*/ l = data->b_wptr - data->b_rptr;
+
+ memcpy (buf, data->b_rptr, l);
+ freemsg (data);
+
+ return l;
+}
+
+/* Endpoint/pipe access */
+
+struct _udi_endpoint_handle_t
+{
+ usb_pipe_handle_t pipe_handle;
+ unsigned char *ep_desc;
+ udi_usb_devc *usbdev;
+};
+
+udi_endpoint_handle_t *
+udi_open_endpoint (udi_usb_devc * usbdev, void *ep_desc)
+{
+ udi_endpoint_handle_t *h;
+ int err;
+ usb_pipe_policy_t policy;
+
+ if ((h = KERNEL_MALLOC (sizeof (*h))) == NULL)
+ return NULL;
+
+ policy.pp_max_async_reqs = 2;
+
+ if ((err = usb_pipe_open (usbdev->osdev->dip, ep_desc, &policy,
+ USB_FLAGS_SLEEP, &h->pipe_handle)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_open() failed %d (%s)\n", err,
+ usb_cb_err (err));
+ KERNEL_FREE (h);
+ return NULL;
+ }
+
+ h->ep_desc = ep_desc;
+ h->usbdev = usbdev;
+
+ return h;
+}
+
+void
+udi_close_endpoint (udi_endpoint_handle_t * h)
+{
+ usb_pipe_close (h->usbdev->osdev->dip, h->pipe_handle, USB_FLAGS_SLEEP,
+ NULL, 0);
+ KERNEL_FREE (h);
+}
+
+int
+udi_endpoint_get_num (udi_endpoint_handle_t * eph)
+{
+ return eph->ep_desc[2] & 0xff;
+}
+
+/* Request stuff */
+
+struct udi_usb_request
+{
+ dev_info_t *dip;
+ usb_pipe_handle_t pipe_handle;
+ udi_usb_complete_func_t callback;
+ void *callback_arg;
+ int active;
+ int xfer_type;
+ mblk_t *data;
+
+ /*
+ * Recording
+ */
+ int actlen;
+
+ usb_isoc_req_t *isoc_req;
+ usb_bulk_req_t *bulk_req;
+ usb_intr_req_t *intr_req;
+};
+
+ /*ARGSUSED*/
+ udi_usb_request_t
+ * udi_usb_alloc_request (udi_usb_devc * usbdev, udi_endpoint_handle_t * eph,
+ int nframes, int xfer_type)
+{
+ udi_usb_request_t *req;
+
+ if ((req = KERNEL_MALLOC (sizeof (*req))) == NULL)
+ {
+ cmn_err (CE_WARN, "udi_usb_alloc_request: Out of memory\n");
+ return NULL;
+ }
+
+ req->xfer_type = xfer_type;
+ req->dip = usbdev->osdev->dip;
+ req->pipe_handle = eph->pipe_handle;
+
+ switch (xfer_type)
+ {
+ case UDI_USBXFER_ISO_READ:
+ return req;
+ break;
+
+ case UDI_USBXFER_ISO_WRITE:
+ return req;
+ break;
+
+ case UDI_USBXFER_BULK_READ:
+ return req;
+ break;
+
+ case UDI_USBXFER_INTR_READ:
+ return req;
+ break;
+
+ case UDI_USBXFER_BULK_WRITE:
+ return req;
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Internal error - bad transfer type %d\n", xfer_type);
+ KERNEL_FREE (req);
+ return NULL;
+ }
+}
+
+void
+udi_usb_free_request (udi_usb_request_t * req)
+{
+ if (req == NULL)
+ return;
+
+ udi_usb_cancel_request (req);
+
+ if (req->active)
+ {
+ cmn_err (CE_WARN, "Warning: Freeing active request\n");
+ }
+
+ switch (req->xfer_type)
+ {
+ case UDI_USBXFER_ISO_WRITE:
+ req->isoc_req = NULL;
+ break;
+
+ case UDI_USBXFER_ISO_READ:
+ req->isoc_req = NULL;
+ break;
+
+ case UDI_USBXFER_BULK_WRITE:
+ req->bulk_req = NULL;
+ break;
+
+ case UDI_USBXFER_BULK_READ:
+ req->bulk_req = NULL;
+ break;
+
+ case UDI_USBXFER_INTR_READ:
+ req->intr_req = NULL;
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Internal error - bad transfer type %d\n",
+ req->xfer_type);
+ }
+
+ KERNEL_FREE (req);
+}
+
+/*ARGSUSED*/
+static void
+isoc_play_callback (usb_pipe_handle_t ph, usb_isoc_req_t * isoc_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) isoc_req->isoc_client_private;
+
+ usb_free_isoc_req (isoc_req);
+
+ req->isoc_req = NULL;
+ req->active = 0;
+
+ req->callback (req, req->callback_arg);
+}
+
+/*ARGSUSED*/
+static void
+isoc_rec_callback (usb_pipe_handle_t ph, usb_isoc_req_t * isoc_req)
+{
+ int i;
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) isoc_req->isoc_client_private;
+
+ req->data = isoc_req->isoc_data;
+
+ for (i = 0; i < isoc_req->isoc_pkts_count; i++)
+ {
+ int len;
+
+ len = isoc_req->isoc_pkt_descr[i].isoc_pkt_actual_length;
+
+ req->actlen = len;
+
+ req->callback (req, req->callback_arg);
+
+ req->data->b_rptr += len;
+ }
+
+ req->active = 0;
+ usb_free_isoc_req (isoc_req);
+}
+
+/*ARGSUSED*/
+static void
+isoc_exc_callback (usb_pipe_handle_t ph, usb_isoc_req_t * isoc_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) isoc_req->isoc_client_private;
+ usb_cr_t reason;
+
+ reason = isoc_req->isoc_completion_reason;
+
+ usb_free_isoc_req (isoc_req);
+ req->isoc_req = NULL;
+ req->active = 0;
+
+ if (reason && reason != USB_CR_FLUSHED && reason != USB_CR_PIPE_CLOSING)
+ cmn_err (CE_CONT, "USB isoc transfer completion status %s\n",
+ usb_cr_err (reason));
+}
+
+/*ARGSUSED*/
+void
+bulk_play_callback (usb_pipe_handle_t ph, usb_bulk_req_t * bulk_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) bulk_req->bulk_client_private;
+
+ usb_free_bulk_req (bulk_req);
+
+ req->bulk_req = NULL;
+ req->active = 0;
+
+ req->callback (req, req->callback_arg);
+}
+
+/*ARGSUSED*/
+void
+bulk_rec_callback (usb_pipe_handle_t ph, usb_bulk_req_t * bulk_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) bulk_req->bulk_client_private;
+
+ req->data = bulk_req->bulk_data;
+ req->actlen = bulk_req->bulk_len;
+ req->active = 0;
+
+ req->callback (req, req->callback_arg);
+ //usb_free_bulk_req (bulk_req);
+}
+
+/*ARGSUSED*/
+static void
+bulk_exc_callback (usb_pipe_handle_t ph, usb_bulk_req_t * bulk_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) bulk_req->bulk_client_private;
+ usb_cr_t reason;
+
+ reason = bulk_req->bulk_completion_reason;
+
+ usb_free_bulk_req (bulk_req);
+ req->bulk_req = NULL;
+ req->active = 0;
+
+ if (reason && reason != USB_CR_FLUSHED && reason != USB_CR_PIPE_CLOSING)
+ cmn_err (CE_CONT, "USB bulk transfer completion status %s\n",
+ usb_cr_err (reason));
+}
+
+/*ARGSUSED*/
+void
+intr_rec_callback (usb_pipe_handle_t ph, usb_intr_req_t * intr_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) intr_req->intr_client_private;
+
+ req->data = intr_req->intr_data;
+ req->actlen = intr_req->intr_len;
+ req->active = 0;
+
+ req->callback (req, req->callback_arg);
+ //usb_free_intr_req (intr_req);
+}
+
+/*ARGSUSED*/
+static void
+intr_exc_callback (usb_pipe_handle_t ph, usb_intr_req_t * intr_req)
+{
+ udi_usb_request_t *req =
+ (udi_usb_request_t *) intr_req->intr_client_private;
+ usb_cr_t reason;
+
+ reason = intr_req->intr_completion_reason;
+
+ usb_free_intr_req (intr_req);
+ req->intr_req = NULL;
+ req->active = 0;
+
+ if (reason && reason != USB_CR_FLUSHED && reason != USB_CR_PIPE_CLOSING)
+ cmn_err (CE_CONT, "USB intr transfer completion status %s\n",
+ usb_cr_err (reason));
+}
+
+/*ARGSUSED*/
+int
+udi_usb_submit_request (udi_usb_request_t * req,
+ udi_usb_complete_func_t callback, void *callback_arg,
+ udi_endpoint_handle_t * eph, int xfer_type,
+ void *data, int len)
+{
+ int err;
+
+ req->callback = callback;
+ req->callback_arg = callback_arg;
+
+ if (req->active)
+ return 0;
+
+ switch (xfer_type)
+ {
+ case UDI_USBXFER_ISO_WRITE:
+ {
+ usb_isoc_req_t *isoc_req;
+
+ if (req->isoc_req != NULL)
+ isoc_req = req->isoc_req;
+ else
+ {
+ req->data = allocb (len, BPRI_HI);
+ if (req->data == NULL)
+ {
+ cmn_err (CE_WARN, "allocb_wait (isoc) failed\n");
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+
+ if ((isoc_req = usb_alloc_isoc_req (req->dip, 1, 0, 0)) == NULL)
+ {
+ cmn_err (CE_WARN, "usb_alloc_isoc_req failed\n");
+ freemsg (req->data);
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+ req->isoc_req = isoc_req;
+ }
+
+ if (isoc_req == NULL)
+ {
+ cmn_err (CE_WARN, "req->isoc==NULL\n");
+ return OSS_EIO;
+ }
+
+ memcpy (req->data->b_wptr, data, len);
+ req->data->b_wptr += len;
+
+ isoc_req->isoc_data = req->data;
+ isoc_req->isoc_pkt_descr[0].isoc_pkt_length = len;
+ isoc_req->isoc_pkts_count = 1;
+ isoc_req->isoc_pkts_length = len;
+ isoc_req->isoc_attributes =
+ USB_ATTRS_ISOC_XFER_ASAP | USB_ATTRS_AUTOCLEARING;
+ isoc_req->isoc_cb = isoc_play_callback;
+ isoc_req->isoc_exc_cb = isoc_exc_callback;
+ isoc_req->isoc_client_private = (usb_opaque_t) req;
+
+ if ((err =
+ usb_pipe_isoc_xfer (req->pipe_handle, isoc_req,
+ 0)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_isoc_xfer failed (%s)\n",
+ usb_errstr (err));
+ return OSS_EIO;
+ }
+ req->active = 1;
+ }
+ break;
+
+ case UDI_USBXFER_ISO_READ:
+ {
+ usb_isoc_req_t *isoc_req;
+
+ if (req->isoc_req != NULL)
+ isoc_req = req->isoc_req;
+ else
+ {
+ if ((isoc_req =
+ usb_alloc_isoc_req (req->dip, 1, len,
+ USB_FLAGS_SLEEP)) == NULL)
+ {
+ cmn_err (CE_WARN, "usb_alloc_isoc_req failed\n");
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+ req->isoc_req = isoc_req;
+ }
+
+ if (isoc_req == NULL)
+ {
+ cmn_err (CE_WARN, "req->isoc==NULL\n");
+ return OSS_EIO;
+ }
+
+ isoc_req->isoc_attributes = USB_ATTRS_ISOC_XFER_ASAP;
+ isoc_req->isoc_cb = isoc_rec_callback;
+ isoc_req->isoc_exc_cb = isoc_exc_callback;
+ isoc_req->isoc_client_private = (usb_opaque_t) req;
+ isoc_req->isoc_pkt_descr[0].isoc_pkt_length = len;
+ isoc_req->isoc_pkts_count = 1;
+ isoc_req->isoc_pkts_length = len;
+ req->active = 1;
+
+ if ((err =
+ usb_pipe_isoc_xfer (req->pipe_handle, isoc_req,
+ USB_FLAGS_NOSLEEP)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_isoc_xfer failed (%s)\n",
+ usb_errstr (err));
+ return OSS_EIO;
+ }
+ }
+ break;
+
+ case UDI_USBXFER_BULK_WRITE:
+ {
+ usb_bulk_req_t *bulk_req;
+
+ if (req->bulk_req != NULL)
+ bulk_req = req->bulk_req;
+ else
+ {
+ req->data = allocb (len, BPRI_HI);
+ if (req->data == NULL)
+ {
+ cmn_err (CE_WARN, "allocb_wait (bulk) failed\n");
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+
+ if ((bulk_req = usb_alloc_bulk_req (req->dip, len, 0)) == NULL)
+ {
+ cmn_err (CE_WARN, "usb_alloc_bulk_req failed\n");
+ freemsg (req->data);
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+ req->bulk_req = bulk_req;
+ }
+
+ if (bulk_req == NULL)
+ {
+ cmn_err (CE_WARN, "req->bulk==NULL\n");
+ return OSS_EIO;
+ }
+
+ memcpy (req->data->b_wptr, data, len);
+ req->data->b_wptr += len;
+
+ bulk_req->bulk_data = req->data;
+ bulk_req->bulk_len = len;
+ bulk_req->bulk_timeout = 5; /* 5 seconds */
+ bulk_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
+ bulk_req->bulk_cb = bulk_play_callback;
+ bulk_req->bulk_exc_cb = bulk_exc_callback;
+ bulk_req->bulk_client_private = (usb_opaque_t) req;
+
+ if ((err =
+ usb_pipe_bulk_xfer (req->pipe_handle, bulk_req,
+ 0)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_bulk_xfer failed (%s)\n",
+ usb_errstr (err));
+ return OSS_EIO;
+ }
+ req->active = 1;
+ }
+ break;
+
+ case UDI_USBXFER_BULK_READ:
+ {
+ usb_bulk_req_t *bulk_req;
+
+ if (req->bulk_req != NULL)
+ bulk_req = req->bulk_req;
+ else
+ {
+#if 0
+ req->data = allocb (len, BPRI_HI);
+ if (req->data == NULL)
+ {
+ cmn_err (CE_WARN, "allocb_wait (bulk) failed\n");
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+#endif
+
+ if ((bulk_req =
+ usb_alloc_bulk_req (req->dip, len, USB_FLAGS_SLEEP)) == NULL)
+ {
+ cmn_err (CE_WARN, "usb_alloc_bulk_req failed\n");
+ freemsg (req->data);
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+ req->bulk_req = bulk_req;
+ }
+
+ if (bulk_req == NULL)
+ {
+ cmn_err (CE_WARN, "req->bulk==NULL\n");
+ return OSS_EIO;
+ }
+
+ bulk_req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK;
+ bulk_req->bulk_cb = bulk_rec_callback;
+ bulk_req->bulk_exc_cb = bulk_exc_callback;
+ bulk_req->bulk_client_private = (usb_opaque_t) req;
+ // bulk_req->bulk_data = data;
+ bulk_req->bulk_len = len;
+ bulk_req->bulk_timeout = 0x7fffffff; /* As long as possible */
+ req->active = 1;
+
+ if ((err =
+ usb_pipe_bulk_xfer (req->pipe_handle, bulk_req,
+ USB_FLAGS_NOSLEEP)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_bulk_xfer failed (%s)\n",
+ usb_errstr (err));
+ return OSS_EIO;
+ }
+ }
+ break;
+
+ case UDI_USBXFER_INTR_READ:
+ {
+ usb_intr_req_t *intr_req;
+
+ if (req->intr_req != NULL)
+ intr_req = req->intr_req;
+ else
+ {
+#if 0
+ req->data = allocb (len, BPRI_HI);
+ if (req->data == NULL)
+ {
+ cmn_err (CE_WARN, "allocb_wait (intr) failed\n");
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+#endif
+
+ if ((intr_req =
+ usb_alloc_intr_req (req->dip, len, USB_FLAGS_SLEEP)) == NULL)
+ {
+ cmn_err (CE_WARN, "usb_alloc_intr_req failed\n");
+ freemsg (req->data);
+ KERNEL_FREE (req);
+ return OSS_ENOMEM;
+ }
+ req->intr_req = intr_req;
+ }
+
+ if (intr_req == NULL)
+ {
+ cmn_err (CE_WARN, "req->intr==NULL\n");
+ return OSS_EIO;
+ }
+
+ intr_req->intr_attributes =
+ USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_ONE_XFER;
+ intr_req->intr_cb = intr_rec_callback;
+ intr_req->intr_exc_cb = intr_exc_callback;
+ intr_req->intr_client_private = (usb_opaque_t) req;
+ intr_req->intr_data = NULL;
+ intr_req->intr_len = len;
+ intr_req->intr_timeout = 0x7fffffff; /* As long as possible */
+ req->active = 1;
+
+ if ((err =
+ usb_pipe_intr_xfer (req->pipe_handle, intr_req,
+ 0)) != USB_SUCCESS)
+ {
+ cmn_err (CE_WARN, "usb_pipe_intr_xfer failed (%s)\n",
+ usb_errstr (err));
+ return OSS_EIO;
+ }
+ }
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Unimplemented transfer type %d\n", xfer_type);
+ return OSS_EIO;
+ }
+
+ return 0;
+}
+
+int
+udi_usb_request_actlen (udi_usb_request_t * request)
+{
+ return request->actlen;
+}
+
+unsigned char *
+udi_usb_request_actdata (udi_usb_request_t * request)
+{
+ return request->data->b_rptr;
+}
+
+void
+udi_usb_cancel_request (udi_usb_request_t * req)
+{
+ if (req == NULL || !req->active)
+ return;
+
+ req->active = 0;
+ usb_pipe_reset (req->dip, req->pipe_handle, USB_FLAGS_SLEEP, NULL, 0);
+
+ switch (req->xfer_type)
+ {
+ case UDI_USBXFER_ISO_WRITE:
+ break;
+
+ case UDI_USBXFER_ISO_READ:
+ usb_pipe_stop_isoc_polling (req->pipe_handle, USB_FLAGS_SLEEP);
+ //if (req->isoc_req!=NULL)
+ //usb_free_isoc_req(req->isoc_req);
+ req->isoc_req = NULL;
+ break;
+
+ case UDI_USBXFER_BULK_WRITE:
+ break;
+
+ case UDI_USBXFER_BULK_READ:
+ req->bulk_req = NULL;
+ break;
+
+ case UDI_USBXFER_INTR_READ:
+ req->intr_req = NULL;
+ break;
+
+ default:
+ cmn_err (CE_WARN, "Internal error - bad transfer type %d\n",
+ req->xfer_type);
+ }
+}
+#endif