diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2009-10-20 18:03:39 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-12-11 14:55:15 -0500 |
commit | 0ad72524ef623f32f6899e656951bb5646caead1 (patch) | |
tree | 369642d6f8e64a063f5fcdb8ec5aa93b77fb66e7 /drivers/usb/gadget | |
parent | 5242658d1b97771d658991cf29be32bcf81d5859 (diff) |
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>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/audio.c | 115 | ||||
-rw-r--r-- | drivers/usb/gadget/f_audio.c | 76 |
2 files changed, 74 insertions, 117 deletions
diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c index a3a0f4a27ef0..58f220323847 100644 --- a/drivers/usb/gadget/audio.c +++ b/drivers/usb/gadget/audio.c | |||
@@ -89,120 +89,6 @@ static const struct usb_descriptor_header *otg_desc[] = { | |||
89 | 89 | ||
90 | /*-------------------------------------------------------------------------*/ | 90 | /*-------------------------------------------------------------------------*/ |
91 | 91 | ||
92 | /** | ||
93 | * Handle USB audio endpoint set/get command in setup class request | ||
94 | */ | ||
95 | |||
96 | static int audio_set_endpoint_req(struct usb_configuration *c, | ||
97 | const struct usb_ctrlrequest *ctrl) | ||
98 | { | ||
99 | struct usb_composite_dev *cdev = c->cdev; | ||
100 | int value = -EOPNOTSUPP; | ||
101 | u16 ep = le16_to_cpu(ctrl->wIndex); | ||
102 | u16 len = le16_to_cpu(ctrl->wLength); | ||
103 | u16 w_value = le16_to_cpu(ctrl->wValue); | ||
104 | |||
105 | DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n", | ||
106 | ctrl->bRequest, w_value, len, ep); | ||
107 | |||
108 | switch (ctrl->bRequest) { | ||
109 | case UAC_SET_CUR: | ||
110 | value = 0; | ||
111 | break; | ||
112 | |||
113 | case UAC_SET_MIN: | ||
114 | break; | ||
115 | |||
116 | case UAC_SET_MAX: | ||
117 | break; | ||
118 | |||
119 | case UAC_SET_RES: | ||
120 | break; | ||
121 | |||
122 | case UAC_SET_MEM: | ||
123 | break; | ||
124 | |||
125 | default: | ||
126 | break; | ||
127 | } | ||
128 | |||
129 | return value; | ||
130 | } | ||
131 | |||
132 | static int audio_get_endpoint_req(struct usb_configuration *c, | ||
133 | const struct usb_ctrlrequest *ctrl) | ||
134 | { | ||
135 | struct usb_composite_dev *cdev = c->cdev; | ||
136 | int value = -EOPNOTSUPP; | ||
137 | u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF); | ||
138 | u16 len = le16_to_cpu(ctrl->wLength); | ||
139 | u16 w_value = le16_to_cpu(ctrl->wValue); | ||
140 | |||
141 | DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n", | ||
142 | ctrl->bRequest, w_value, len, ep); | ||
143 | |||
144 | switch (ctrl->bRequest) { | ||
145 | case UAC_GET_CUR: | ||
146 | case UAC_GET_MIN: | ||
147 | case UAC_GET_MAX: | ||
148 | case UAC_GET_RES: | ||
149 | value = 3; | ||
150 | break; | ||
151 | case UAC_GET_MEM: | ||
152 | break; | ||
153 | default: | ||
154 | break; | ||
155 | } | ||
156 | |||
157 | return value; | ||
158 | } | ||
159 | |||
160 | static int | ||
161 | audio_setup(struct usb_configuration *c, const struct usb_ctrlrequest *ctrl) | ||
162 | { | ||
163 | struct usb_composite_dev *cdev = c->cdev; | ||
164 | struct usb_request *req = cdev->req; | ||
165 | int value = -EOPNOTSUPP; | ||
166 | u16 w_index = le16_to_cpu(ctrl->wIndex); | ||
167 | u16 w_value = le16_to_cpu(ctrl->wValue); | ||
168 | u16 w_length = le16_to_cpu(ctrl->wLength); | ||
169 | |||
170 | /* composite driver infrastructure handles everything except | ||
171 | * Audio class messages; interface activation uses set_alt(). | ||
172 | */ | ||
173 | switch (ctrl->bRequestType) { | ||
174 | case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT: | ||
175 | value = audio_set_endpoint_req(c, ctrl); | ||
176 | break; | ||
177 | |||
178 | case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT: | ||
179 | value = audio_get_endpoint_req(c, ctrl); | ||
180 | break; | ||
181 | |||
182 | default: | ||
183 | ERROR(cdev, "Invalid control req%02x.%02x v%04x i%04x l%d\n", | ||
184 | ctrl->bRequestType, ctrl->bRequest, | ||
185 | w_value, w_index, w_length); | ||
186 | } | ||
187 | |||
188 | /* respond with data transfer or status phase? */ | ||
189 | if (value >= 0) { | ||
190 | DBG(cdev, "Audio req%02x.%02x v%04x i%04x l%d\n", | ||
191 | ctrl->bRequestType, ctrl->bRequest, | ||
192 | w_value, w_index, w_length); | ||
193 | req->zero = 0; | ||
194 | req->length = value; | ||
195 | value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); | ||
196 | if (value < 0) | ||
197 | ERROR(cdev, "Audio response on err %d\n", value); | ||
198 | } | ||
199 | |||
200 | /* device either stalls (value < 0) or reports success */ | ||
201 | return value; | ||
202 | } | ||
203 | |||
204 | /*-------------------------------------------------------------------------*/ | ||
205 | |||
206 | static int __init audio_do_config(struct usb_configuration *c) | 92 | static int __init audio_do_config(struct usb_configuration *c) |
207 | { | 93 | { |
208 | /* FIXME alloc iConfiguration string, set it in c->strings */ | 94 | /* FIXME alloc iConfiguration string, set it in c->strings */ |
@@ -220,7 +106,6 @@ static int __init audio_do_config(struct usb_configuration *c) | |||
220 | static struct usb_configuration audio_config_driver = { | 106 | static struct usb_configuration audio_config_driver = { |
221 | .label = DRIVER_DESC, | 107 | .label = DRIVER_DESC, |
222 | .bind = audio_do_config, | 108 | .bind = audio_do_config, |
223 | .setup = audio_setup, | ||
224 | .bConfigurationValue = 1, | 109 | .bConfigurationValue = 1, |
225 | /* .iConfiguration = DYNAMIC */ | 110 | /* .iConfiguration = DYNAMIC */ |
226 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, | 111 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, |
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c index 98e9bb977291..c43c89ffa2c8 100644 --- a/drivers/usb/gadget/f_audio.c +++ b/drivers/usb/gadget/f_audio.c | |||
@@ -445,6 +445,70 @@ static int audio_get_intf_req(struct usb_function *f, | |||
445 | return len; | 445 | return len; |
446 | } | 446 | } |
447 | 447 | ||
448 | static int audio_set_endpoint_req(struct usb_function *f, | ||
449 | const struct usb_ctrlrequest *ctrl) | ||
450 | { | ||
451 | struct usb_composite_dev *cdev = f->config->cdev; | ||
452 | int value = -EOPNOTSUPP; | ||
453 | u16 ep = le16_to_cpu(ctrl->wIndex); | ||
454 | u16 len = le16_to_cpu(ctrl->wLength); | ||
455 | u16 w_value = le16_to_cpu(ctrl->wValue); | ||
456 | |||
457 | DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n", | ||
458 | ctrl->bRequest, w_value, len, ep); | ||
459 | |||
460 | switch (ctrl->bRequest) { | ||
461 | case UAC_SET_CUR: | ||
462 | value = 0; | ||
463 | break; | ||
464 | |||
465 | case UAC_SET_MIN: | ||
466 | break; | ||
467 | |||
468 | case UAC_SET_MAX: | ||
469 | break; | ||
470 | |||
471 | case UAC_SET_RES: | ||
472 | break; | ||
473 | |||
474 | case UAC_SET_MEM: | ||
475 | break; | ||
476 | |||
477 | default: | ||
478 | break; | ||
479 | } | ||
480 | |||
481 | return value; | ||
482 | } | ||
483 | |||
484 | static int audio_get_endpoint_req(struct usb_function *f, | ||
485 | const struct usb_ctrlrequest *ctrl) | ||
486 | { | ||
487 | struct usb_composite_dev *cdev = f->config->cdev; | ||
488 | int value = -EOPNOTSUPP; | ||
489 | u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF); | ||
490 | u16 len = le16_to_cpu(ctrl->wLength); | ||
491 | u16 w_value = le16_to_cpu(ctrl->wValue); | ||
492 | |||
493 | DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n", | ||
494 | ctrl->bRequest, w_value, len, ep); | ||
495 | |||
496 | switch (ctrl->bRequest) { | ||
497 | case UAC_GET_CUR: | ||
498 | case UAC_GET_MIN: | ||
499 | case UAC_GET_MAX: | ||
500 | case UAC_GET_RES: | ||
501 | value = 3; | ||
502 | break; | ||
503 | case UAC_GET_MEM: | ||
504 | break; | ||
505 | default: | ||
506 | break; | ||
507 | } | ||
508 | |||
509 | return value; | ||
510 | } | ||
511 | |||
448 | static int | 512 | static int |
449 | f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) | 513 | f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) |
450 | { | 514 | { |
@@ -455,8 +519,8 @@ f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) | |||
455 | u16 w_value = le16_to_cpu(ctrl->wValue); | 519 | u16 w_value = le16_to_cpu(ctrl->wValue); |
456 | u16 w_length = le16_to_cpu(ctrl->wLength); | 520 | u16 w_length = le16_to_cpu(ctrl->wLength); |
457 | 521 | ||
458 | /* composite driver infrastructure handles everything except | 522 | /* composite driver infrastructure handles everything; interface |
459 | * Audio class messages; interface activation uses set_alt(). | 523 | * activation uses set_alt(). |
460 | */ | 524 | */ |
461 | switch (ctrl->bRequestType) { | 525 | switch (ctrl->bRequestType) { |
462 | case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE: | 526 | 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 | value = audio_get_intf_req(f, ctrl); | 531 | value = audio_get_intf_req(f, ctrl); |
468 | break; | 532 | break; |
469 | 533 | ||
534 | case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT: | ||
535 | value = audio_set_endpoint_req(f, ctrl); | ||
536 | break; | ||
537 | |||
538 | case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT: | ||
539 | value = audio_get_endpoint_req(f, ctrl); | ||
540 | break; | ||
541 | |||
470 | default: | 542 | default: |
471 | ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n", | 543 | ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n", |
472 | ctrl->bRequestType, ctrl->bRequest, | 544 | ctrl->bRequestType, ctrl->bRequest, |