Google
 

Open Sound System
The Hitchhiker's Guide to OSS 4.1 Internals

Do you have problems with sound/audio application development? Don't panic! Click here for help!

SunOS/udi.c

USB device interface (udi.h) routines for Solaris

Description




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

Copyright (C) 4Front Technologies, 2007. All rights reserved.

Back to index OSS web site


Copyright (C) 4Front Technologies, 2007. All rights reserved.
Back to index OSS web site