Open Sound System |
Do you have problems with sound/audio application development? Don't panic! Click here for help! |
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