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: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Cc: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
5242658d1b
commit
0ad72524ef
@@ -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)
|
|||||||
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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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,
|
||||||
|
Reference in New Issue
Block a user