The composite USB device is basically functional (more testing needed)

git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4343 7fd9a85b-ad96-42d3-883c-3090e2eb8679
This commit is contained in:
patacongo 2012-01-27 18:33:41 +00:00
parent b8e32a94f3
commit f0d2b3cca3
4 changed files with 252 additions and 241 deletions

View File

@ -1207,277 +1207,283 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver,
uvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n",
ctrl->type, ctrl->req, value, index, len);
switch (ctrl->type & USB_REQ_TYPE_MASK)
if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)
{
/***********************************************************************
* Standard Requests
***********************************************************************/
/***********************************************************************
* Standard Requests
***********************************************************************/
case USB_REQ_TYPE_STANDARD:
{
switch (ctrl->req)
switch (ctrl->req)
{
case USB_REQ_GETDESCRIPTOR:
{
case USB_REQ_GETDESCRIPTOR:
{
/* The value field specifies the descriptor type in the MS byte and the
* descriptor index in the LS byte (order is little endian)
/* The value field specifies the descriptor type in the MS byte and the
* descriptor index in the LS byte (order is little endian)
*/
switch (ctrl->value[1])
{
/* If the serial device is used in as part of a composite device,
* then the device descriptor is provided by logic in the composite
* device implementation.
*/
switch (ctrl->value[1])
{
/* If the serial device is used in as part of a composite device,
* then the device descriptor is provided by logic in the composite
* device implementation.
*/
#ifndef CONFIG_CDCACM_COMPOSITE
case USB_DESC_TYPE_DEVICE:
{
ret = USB_SIZEOF_DEVDESC;
memcpy(ctrlreq->buf, cdcacm_getdevdesc(), ret);
}
break;
case USB_DESC_TYPE_DEVICE:
{
ret = USB_SIZEOF_DEVDESC;
memcpy(ctrlreq->buf, cdcacm_getdevdesc(), ret);
}
break;
#endif
/* If the serial device is used in as part of a composite device,
* then the device qualifier descriptor is provided by logic in the
* composite device implementation.
*/
/* If the serial device is used in as part of a composite device,
* then the device qualifier descriptor is provided by logic in the
* composite device implementation.
*/
#if !defined(CONFIG_CDCACM_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED)
case USB_DESC_TYPE_DEVICEQUALIFIER:
{
ret = USB_SIZEOF_QUALDESC;
memcpy(ctrlreq->buf, cdcacm_getqualdesc(), ret);
}
break;
case USB_DESC_TYPE_DEVICEQUALIFIER:
{
ret = USB_SIZEOF_QUALDESC;
memcpy(ctrlreq->buf, cdcacm_getqualdesc(), ret);
}
break;
case USB_DESC_TYPE_OTHERSPEEDCONFIG:
case USB_DESC_TYPE_OTHERSPEEDCONFIG:
#endif
/* If the serial device is used in as part of a composite device,
* then the configuration descriptor is provided by logic in the
* composite device implementation.
*/
/* If the serial device is used in as part of a composite device,
* then the configuration descriptor is provided by logic in the
* composite device implementation.
*/
#ifndef CONFIG_CDCACM_COMPOSITE
case USB_DESC_TYPE_CONFIG:
{
case USB_DESC_TYPE_CONFIG:
{
#ifdef CONFIG_USBDEV_DUALSPEED
ret = cdcacm_mkcfgdesc(ctrlreq->buf, dev->speed, ctrl->req);
ret = cdcacm_mkcfgdesc(ctrlreq->buf, dev->speed, ctrl->req);
#else
ret = cdcacm_mkcfgdesc(ctrlreq->buf);
ret = cdcacm_mkcfgdesc(ctrlreq->buf);
#endif
}
break;
}
break;
#endif
/* If the serial device is used in as part of a composite device,
* then the language string descriptor is provided by logic in the
* composite device implementation.
/* If the serial device is used in as part of a composite device,
* then the language string descriptor is provided by logic in the
* composite device implementation.
*/
#ifndef CONFIG_CDCACM_COMPOSITE
case USB_DESC_TYPE_STRING:
{
/* index == language code. */
ret = cdcacm_mkstrdesc(ctrl->value[0], (struct usb_strdesc_s *)ctrlreq->buf);
}
break;
#endif
default:
{
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_GETUNKNOWNDESC), value);
}
break;
}
}
break;
case USB_REQ_SETCONFIGURATION:
{
if (ctrl->type == 0)
{
ret = cdcacm_setconfig(priv, value);
}
}
break;
/* If the serial device is used in as part of a composite device,
* then the overall composite class configuration is managed by logic
* in the composite device implementation.
*/
#ifndef CONFIG_CDCACM_COMPOSITE
case USB_REQ_GETCONFIGURATION:
{
if (ctrl->type == USB_DIR_IN)
{
*(uint8_t*)ctrlreq->buf = priv->config;
ret = 1;
}
}
break;
#endif
case USB_REQ_SETINTERFACE:
{
if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE &&
priv->config == CDCACM_CONFIGID)
{
if ((index == CDCACM_NOTIFID && value == CDCACM_NOTALTIFID) ||
(index == CDCACM_DATAIFID && value == CDCACM_DATAALTIFID))
{
cdcacm_resetconfig(priv);
cdcacm_setconfig(priv, priv->config);
ret = 0;
}
}
}
break;
case USB_REQ_GETINTERFACE:
{
if (ctrl->type == (USB_DIR_IN|USB_REQ_RECIPIENT_INTERFACE) &&
priv->config == CDCACM_CONFIGIDNONE)
{
if ((index == CDCACM_NOTIFID && value == CDCACM_NOTALTIFID) ||
(index == CDCACM_DATAIFID && value == CDCACM_DATAALTIFID))
{
*(uint8_t*) ctrlreq->buf = value;
ret = 1;
}
else
{
ret = -EDOM;
}
}
}
break;
default:
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req);
break;
}
}
else if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_CLASS)
{
/***********************************************************************
* CDC ACM-Specific Requests
***********************************************************************/
switch (ctrl->req)
{
/* ACM_GET_LINE_CODING requests current DTE rate, stop-bits, parity, and
* number-of-character bits. (Optional)
*/
case ACM_GET_LINE_CODING:
{
if (ctrl->type == (USB_DIR_IN|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE) &&
index == CDCACM_NOTIFID)
{
/* Return the current line status from the private data structure */
memcpy(ctrlreq->buf, &priv->linecoding, SIZEOF_CDC_LINECODING);
ret = SIZEOF_CDC_LINECODING;
}
else
{
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type);
}
}
break;
/* ACM_SET_LINE_CODING configures DTE rate, stop-bits, parity, and
* number-of-character bits. (Optional)
*/
case ACM_SET_LINE_CODING:
{
if (ctrl->type == (USB_DIR_OUT|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE) &&
len == SIZEOF_CDC_LINECODING && index == CDCACM_NOTIFID)
{
/* Save the new line coding in the private data structure */
memcpy(&priv->linecoding, ctrlreq->buf, MIN(len, 7));
ret = 0;
/* If there is a registered callback to receive line status info, then
* callout now.
*/
#ifndef CONFIG_CDCACM_COMPOSITE
case USB_DESC_TYPE_STRING:
if (priv->callback)
{
/* index == language code. */
ret = cdcacm_mkstrdesc(ctrl->value[0], (struct usb_strdesc_s *)ctrlreq->buf);
priv->callback(CDCACM_EVENT_LINECODING);
}
break;
#endif
}
else
{
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type);
}
}
break;
default:
/* ACM_SET_CTRL_LINE_STATE: RS-232 signal used to tell the DCE device the
* DTE device is now present. (Optional)
*/
case ACM_SET_CTRL_LINE_STATE:
{
if (ctrl->type == (USB_DIR_OUT|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE) &&
index == CDCACM_NOTIFID)
{
/* Save the control line state in the private data structure. Only bits
* 0 and 1 have meaning.
*/
priv->ctrlline = value & 3;
ret = 0;
/* If there is a registered callback to receive control line status info,
* then callout now.
*/
if (priv->callback)
{
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_GETUNKNOWNDESC), value);
priv->callback(CDCACM_EVENT_CTRLLINE);
}
break;
}
}
break;
case USB_REQ_SETCONFIGURATION:
{
if (ctrl->type == 0)
{
ret = cdcacm_setconfig(priv, value);
}
}
break;
/* If the serial device is used in as part of a composite device,
* then the overall composite class configuration is managed by logic
* in the composite device implementation.
*/
#ifndef CONFIG_CDCACM_COMPOSITE
case USB_REQ_GETCONFIGURATION:
{
if (ctrl->type == USB_DIR_IN)
{
*(uint8_t*)ctrlreq->buf = priv->config;
ret = 1;
}
}
break;
#endif
case USB_REQ_SETINTERFACE:
{
if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE &&
priv->config == CDCACM_CONFIGID)
{
if ((index == CDCACM_NOTIFID && value == CDCACM_NOTALTIFID) ||
(index == CDCACM_DATAIFID && value == CDCACM_DATAALTIFID))
{
cdcacm_resetconfig(priv);
cdcacm_setconfig(priv, priv->config);
ret = 0;
}
}
}
break;
case USB_REQ_GETINTERFACE:
{
if (ctrl->type == (USB_DIR_IN|USB_REQ_RECIPIENT_INTERFACE) &&
priv->config == CDCACM_CONFIGIDNONE)
{
if ((index == CDCACM_NOTIFID && value == CDCACM_NOTALTIFID) ||
(index == CDCACM_DATAIFID && value == CDCACM_DATAALTIFID))
{
*(uint8_t*) ctrlreq->buf = value;
ret = 1;
}
else
{
ret = -EDOM;
}
}
}
break;
default:
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req);
break;
}
}
break;
/************************************************************************
* CDC ACM-Specific Requests
************************************************************************/
/* ACM_GET_LINE_CODING requests current DTE rate, stop-bits, parity, and
* number-of-character bits. (Optional)
*/
case ACM_GET_LINE_CODING:
{
if (ctrl->type == (USB_DIR_IN|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE) &&
index == CDCACM_NOTIFID)
{
/* Return the current line status from the private data structure */
memcpy(ctrlreq->buf, &priv->linecoding, SIZEOF_CDC_LINECODING);
ret = SIZEOF_CDC_LINECODING;
}
else
{
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type);
}
}
break;
/* ACM_SET_LINE_CODING configures DTE rate, stop-bits, parity, and
* number-of-character bits. (Optional)
*/
case ACM_SET_LINE_CODING:
{
if (ctrl->type == (USB_DIR_OUT|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE) &&
len == SIZEOF_CDC_LINECODING && index == CDCACM_NOTIFID)
{
/* Save the new line coding in the private data structure */
memcpy(&priv->linecoding, ctrlreq->buf, MIN(len, 7));
ret = 0;
/* If there is a registered callback to receive line status info, then
* callout now.
*/
if (priv->callback)
}
else
{
priv->callback(CDCACM_EVENT_LINECODING);
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type);
}
}
else
break;
/* Sends special carrier*/
case ACM_SEND_BREAK:
{
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type);
}
}
break;
/* ACM_SET_CTRL_LINE_STATE: RS-232 signal used to tell the DCE device the
* DTE device is now present. (Optional)
*/
case ACM_SET_CTRL_LINE_STATE:
{
if (ctrl->type == (USB_DIR_OUT|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE) &&
index == CDCACM_NOTIFID)
{
/* Save the control line state in the private data structure. Only bits
* 0 and 1 have meaning.
*/
priv->ctrlline = value & 3;
ret = 0;
/* If there is a registered callback to receive control line status info,
* then callout now.
*/
if (priv->callback)
if (ctrl->type == (USB_DIR_OUT|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE) &&
index == CDCACM_NOTIFID)
{
priv->callback(CDCACM_EVENT_CTRLLINE);
/* If there is a registered callback to handle the SendBreak request,
* then callout now.
*/
ret = 0;
if (priv->callback)
{
priv->callback(CDCACM_EVENT_SENDBREAK);
}
}
else
{
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type);
}
}
else
{
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type);
}
}
break;
break;
/* Sends special carrier*/
case ACM_SEND_BREAK:
{
if (ctrl->type == (USB_DIR_OUT|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE) &&
index == CDCACM_NOTIFID)
{
/* If there is a registered callback to handle the SendBreak request,
* then callout now.
*/
ret = 0;
if (priv->callback)
{
priv->callback(CDCACM_EVENT_SENDBREAK);
}
}
else
{
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type);
}
}
break;
default:
default:
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->req);
break;
}
}
else
{
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDTYPE), ctrl->type);
break;
}
/* Respond to the setup command if data was returned. On an error return

View File

@ -189,13 +189,13 @@ static int composite_classsetup(FAR struct composite_dev_s *priv,
index = GETUINT16(ctrl->index);
interface = (uint8_t)(index & 0xff);
if (interface >= DEV1_FIRSTINTERFACE && interface <= (DEV1_FIRSTINTERFACE + DEV1_NINTERFACES))
if (interface >= DEV1_FIRSTINTERFACE && interface < (DEV1_FIRSTINTERFACE + DEV1_NINTERFACES))
{
ret = CLASS_SETUP(priv->dev1, dev, ctrl);
}
else if (interface >= DEV2_FIRSTINTERFACE && interface <= (DEV2_FIRSTINTERFACE + DEV2_NINTERFACES))
else if (interface >= DEV2_FIRSTINTERFACE && interface < (DEV2_FIRSTINTERFACE + DEV2_NINTERFACES))
{
ret = CLASS_SETUP(priv->dev1, dev, ctrl);
ret = CLASS_SETUP(priv->dev2, dev, ctrl);
}
return ret;
@ -505,7 +505,7 @@ static int composite_setup(FAR struct usbdevclass_driver_s *driver,
if (ret >= 0)
{
ret = CLASS_SETUP(priv->dev1, dev, ctrl);
ret = CLASS_SETUP(priv->dev2, dev, ctrl);
if (ret >= 0)
{
priv->config = value;

View File

@ -710,7 +710,7 @@ static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver,
break;
}
}
else
else if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_CLASS)
{
/**********************************************************************
* Bulk-Only Mass Storage Class Requests
@ -775,10 +775,14 @@ static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver,
break;
default:
usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_BADREQUEST), index);
usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_BADREQUEST), ctrl->req);
break;
}
}
else
{
usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_UNSUPPORTEDTYPE), ctrl->type);
}
/* Respond to the setup command if data was returned. On an error return
* value (ret < 0), the USB driver will stall EP0.

View File

@ -382,6 +382,7 @@
#define USBMSC_TRACEERR_WRITE6READONLY 0x0075
#define USBMSC_TRACEERR_WRSHUTDOWN 0x0076
#define USBMSC_TRACEERR_WRUNEXPECTED 0x0077
#define USBMSC_TRACEERR_UNSUPPORTEDTYPE 0x0078
/****************************************************************************
* Public Types