Commit 0ad72524 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Greg Kroah-Hartman

USB audio gadget: handle endpoint control requests at the function level

Now that control requests targeted at an endpoint can be handled at the
function level, move the UAC-specific control request handling code from
the audio gadget driver to the audio function driver.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 5242658d
...@@ -89,120 +89,6 @@ static const struct usb_descriptor_header *otg_desc[] = { ...@@ -89,120 +89,6 @@ static const struct usb_descriptor_header *otg_desc[] = {
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/**
* Handle USB audio endpoint set/get command in setup class request
*/
static int audio_set_endpoint_req(struct usb_configuration *c,
const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = c->cdev;
int value = -EOPNOTSUPP;
u16 ep = le16_to_cpu(ctrl->wIndex);
u16 len = le16_to_cpu(ctrl->wLength);
u16 w_value = le16_to_cpu(ctrl->wValue);
DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
ctrl->bRequest, w_value, len, ep);
switch (ctrl->bRequest) {
case UAC_SET_CUR:
value = 0;
break;
case UAC_SET_MIN:
break;
case UAC_SET_MAX:
break;
case UAC_SET_RES:
break;
case UAC_SET_MEM:
break;
default:
break;
}
return value;
}
static int audio_get_endpoint_req(struct usb_configuration *c,
const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = c->cdev;
int value = -EOPNOTSUPP;
u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
u16 len = le16_to_cpu(ctrl->wLength);
u16 w_value = le16_to_cpu(ctrl->wValue);
DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
ctrl->bRequest, w_value, len, ep);
switch (ctrl->bRequest) {
case UAC_GET_CUR:
case UAC_GET_MIN:
case UAC_GET_MAX:
case UAC_GET_RES:
value = 3;
break;
case UAC_GET_MEM:
break;
default:
break;
}
return value;
}
static int
audio_setup(struct usb_configuration *c, const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = c->cdev;
struct usb_request *req = cdev->req;
int value = -EOPNOTSUPP;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
/* composite driver infrastructure handles everything except
* Audio class messages; interface activation uses set_alt().
*/
switch (ctrl->bRequestType) {
case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
value = audio_set_endpoint_req(c, ctrl);
break;
case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
value = audio_get_endpoint_req(c, ctrl);
break;
default:
ERROR(cdev, "Invalid control req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
}
/* respond with data transfer or status phase? */
if (value >= 0) {
DBG(cdev, "Audio req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
req->zero = 0;
req->length = value;
value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
if (value < 0)
ERROR(cdev, "Audio response on err %d\n", value);
}
/* device either stalls (value < 0) or reports success */
return value;
}
/*-------------------------------------------------------------------------*/
static int __init audio_do_config(struct usb_configuration *c) static int __init audio_do_config(struct usb_configuration *c)
{ {
/* FIXME alloc iConfiguration string, set it in c->strings */ /* FIXME alloc iConfiguration string, set it in c->strings */
...@@ -220,7 +106,6 @@ static int __init audio_do_config(struct usb_configuration *c) ...@@ -220,7 +106,6 @@ static int __init audio_do_config(struct usb_configuration *c)
static struct usb_configuration audio_config_driver = { static struct usb_configuration audio_config_driver = {
.label = DRIVER_DESC, .label = DRIVER_DESC,
.bind = audio_do_config, .bind = audio_do_config,
.setup = audio_setup,
.bConfigurationValue = 1, .bConfigurationValue = 1,
/* .iConfiguration = DYNAMIC */ /* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_SELFPOWER, .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
......
...@@ -445,6 +445,70 @@ static int audio_get_intf_req(struct usb_function *f, ...@@ -445,6 +445,70 @@ static int audio_get_intf_req(struct usb_function *f,
return len; return len;
} }
static int audio_set_endpoint_req(struct usb_function *f,
const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = f->config->cdev;
int value = -EOPNOTSUPP;
u16 ep = le16_to_cpu(ctrl->wIndex);
u16 len = le16_to_cpu(ctrl->wLength);
u16 w_value = le16_to_cpu(ctrl->wValue);
DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
ctrl->bRequest, w_value, len, ep);
switch (ctrl->bRequest) {
case UAC_SET_CUR:
value = 0;
break;
case UAC_SET_MIN:
break;
case UAC_SET_MAX:
break;
case UAC_SET_RES:
break;
case UAC_SET_MEM:
break;
default:
break;
}
return value;
}
static int audio_get_endpoint_req(struct usb_function *f,
const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = f->config->cdev;
int value = -EOPNOTSUPP;
u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
u16 len = le16_to_cpu(ctrl->wLength);
u16 w_value = le16_to_cpu(ctrl->wValue);
DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
ctrl->bRequest, w_value, len, ep);
switch (ctrl->bRequest) {
case UAC_GET_CUR:
case UAC_GET_MIN:
case UAC_GET_MAX:
case UAC_GET_RES:
value = 3;
break;
case UAC_GET_MEM:
break;
default:
break;
}
return value;
}
static int static int
f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
{ {
...@@ -455,8 +519,8 @@ f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) ...@@ -455,8 +519,8 @@ f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength); u16 w_length = le16_to_cpu(ctrl->wLength);
/* composite driver infrastructure handles everything except /* composite driver infrastructure handles everything; interface
* Audio class messages; interface activation uses set_alt(). * activation uses set_alt().
*/ */
switch (ctrl->bRequestType) { switch (ctrl->bRequestType) {
case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE: case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
...@@ -467,6 +531,14 @@ f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) ...@@ -467,6 +531,14 @@ f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
value = audio_get_intf_req(f, ctrl); value = audio_get_intf_req(f, ctrl);
break; break;
case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
value = audio_set_endpoint_req(f, ctrl);
break;
case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
value = audio_get_endpoint_req(f, ctrl);
break;
default: default:
ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n", ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest, ctrl->bRequestType, ctrl->bRequest,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment