diff options
Diffstat (limited to 'drivers/usb/gadget/f_audio.c')
-rw-r--r-- | drivers/usb/gadget/f_audio.c | 98 |
1 files changed, 88 insertions, 10 deletions
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c index 98e9bb977291..43bf44514c41 100644 --- a/drivers/usb/gadget/f_audio.c +++ b/drivers/usb/gadget/f_audio.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * Licensed under the GPL-2 or later. | 9 | * Licensed under the GPL-2 or later. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/slab.h> | ||
12 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
13 | #include <linux/device.h> | 14 | #include <linux/device.h> |
14 | #include <asm/atomic.h> | 15 | #include <asm/atomic.h> |
@@ -56,13 +57,16 @@ static struct usb_interface_descriptor ac_interface_desc __initdata = { | |||
56 | DECLARE_UAC_AC_HEADER_DESCRIPTOR(2); | 57 | DECLARE_UAC_AC_HEADER_DESCRIPTOR(2); |
57 | 58 | ||
58 | #define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES) | 59 | #define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES) |
60 | /* 1 input terminal, 1 output terminal and 1 feature unit */ | ||
61 | #define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \ | ||
62 | + UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0)) | ||
59 | /* B.3.2 Class-Specific AC Interface Descriptor */ | 63 | /* B.3.2 Class-Specific AC Interface Descriptor */ |
60 | static struct uac_ac_header_descriptor_2 ac_header_desc = { | 64 | static struct uac_ac_header_descriptor_v1_2 ac_header_desc = { |
61 | .bLength = UAC_DT_AC_HEADER_LENGTH, | 65 | .bLength = UAC_DT_AC_HEADER_LENGTH, |
62 | .bDescriptorType = USB_DT_CS_INTERFACE, | 66 | .bDescriptorType = USB_DT_CS_INTERFACE, |
63 | .bDescriptorSubtype = UAC_HEADER, | 67 | .bDescriptorSubtype = UAC_HEADER, |
64 | .bcdADC = __constant_cpu_to_le16(0x0100), | 68 | .bcdADC = __constant_cpu_to_le16(0x0100), |
65 | .wTotalLength = __constant_cpu_to_le16(UAC_DT_AC_HEADER_LENGTH), | 69 | .wTotalLength = __constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH), |
66 | .bInCollection = F_AUDIO_NUM_INTERFACES, | 70 | .bInCollection = F_AUDIO_NUM_INTERFACES, |
67 | .baInterfaceNr = { | 71 | .baInterfaceNr = { |
68 | [0] = F_AUDIO_AC_INTERFACE, | 72 | [0] = F_AUDIO_AC_INTERFACE, |
@@ -121,7 +125,7 @@ static struct usb_audio_control_selector feature_unit = { | |||
121 | }; | 125 | }; |
122 | 126 | ||
123 | #define OUTPUT_TERMINAL_ID 3 | 127 | #define OUTPUT_TERMINAL_ID 3 |
124 | static struct uac_output_terminal_descriptor output_terminal_desc = { | 128 | static struct uac_output_terminal_descriptor_v1 output_terminal_desc = { |
125 | .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, | 129 | .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, |
126 | .bDescriptorType = USB_DT_CS_INTERFACE, | 130 | .bDescriptorType = USB_DT_CS_INTERFACE, |
127 | .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, | 131 | .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, |
@@ -151,7 +155,7 @@ static struct usb_interface_descriptor as_interface_alt_1_desc = { | |||
151 | }; | 155 | }; |
152 | 156 | ||
153 | /* B.4.2 Class-Specific AS Interface Descriptor */ | 157 | /* B.4.2 Class-Specific AS Interface Descriptor */ |
154 | static struct uac_as_header_descriptor as_header_desc = { | 158 | static struct uac_as_header_descriptor_v1 as_header_desc = { |
155 | .bLength = UAC_DT_AS_HEADER_SIZE, | 159 | .bLength = UAC_DT_AS_HEADER_SIZE, |
156 | .bDescriptorType = USB_DT_CS_INTERFACE, | 160 | .bDescriptorType = USB_DT_CS_INTERFACE, |
157 | .bDescriptorSubtype = UAC_AS_GENERAL, | 161 | .bDescriptorSubtype = UAC_AS_GENERAL, |
@@ -252,12 +256,12 @@ static struct f_audio_buf *f_audio_buffer_alloc(int buf_size) | |||
252 | 256 | ||
253 | copy_buf = kzalloc(sizeof *copy_buf, GFP_ATOMIC); | 257 | copy_buf = kzalloc(sizeof *copy_buf, GFP_ATOMIC); |
254 | if (!copy_buf) | 258 | if (!copy_buf) |
255 | return (struct f_audio_buf *)-ENOMEM; | 259 | return ERR_PTR(-ENOMEM); |
256 | 260 | ||
257 | copy_buf->buf = kzalloc(buf_size, GFP_ATOMIC); | 261 | copy_buf->buf = kzalloc(buf_size, GFP_ATOMIC); |
258 | if (!copy_buf->buf) { | 262 | if (!copy_buf->buf) { |
259 | kfree(copy_buf); | 263 | kfree(copy_buf); |
260 | return (struct f_audio_buf *)-ENOMEM; | 264 | return ERR_PTR(-ENOMEM); |
261 | } | 265 | } |
262 | 266 | ||
263 | return copy_buf; | 267 | return copy_buf; |
@@ -332,7 +336,7 @@ static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req) | |||
332 | list_add_tail(©_buf->list, &audio->play_queue); | 336 | list_add_tail(©_buf->list, &audio->play_queue); |
333 | schedule_work(&audio->playback_work); | 337 | schedule_work(&audio->playback_work); |
334 | copy_buf = f_audio_buffer_alloc(audio_buf_size); | 338 | copy_buf = f_audio_buffer_alloc(audio_buf_size); |
335 | if (copy_buf < 0) | 339 | if (IS_ERR(copy_buf)) |
336 | return -ENOMEM; | 340 | return -ENOMEM; |
337 | } | 341 | } |
338 | 342 | ||
@@ -445,6 +449,70 @@ static int audio_get_intf_req(struct usb_function *f, | |||
445 | return len; | 449 | return len; |
446 | } | 450 | } |
447 | 451 | ||
452 | static int audio_set_endpoint_req(struct usb_function *f, | ||
453 | const struct usb_ctrlrequest *ctrl) | ||
454 | { | ||
455 | struct usb_composite_dev *cdev = f->config->cdev; | ||
456 | int value = -EOPNOTSUPP; | ||
457 | u16 ep = le16_to_cpu(ctrl->wIndex); | ||
458 | u16 len = le16_to_cpu(ctrl->wLength); | ||
459 | u16 w_value = le16_to_cpu(ctrl->wValue); | ||
460 | |||
461 | DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n", | ||
462 | ctrl->bRequest, w_value, len, ep); | ||
463 | |||
464 | switch (ctrl->bRequest) { | ||
465 | case UAC_SET_CUR: | ||
466 | value = 0; | ||
467 | break; | ||
468 | |||
469 | case UAC_SET_MIN: | ||
470 | break; | ||
471 | |||
472 | case UAC_SET_MAX: | ||
473 | break; | ||
474 | |||
475 | case UAC_SET_RES: | ||
476 | break; | ||
477 | |||
478 | case UAC_SET_MEM: | ||
479 | break; | ||
480 | |||
481 | default: | ||
482 | break; | ||
483 | } | ||
484 | |||
485 | return value; | ||
486 | } | ||
487 | |||
488 | static int audio_get_endpoint_req(struct usb_function *f, | ||
489 | const struct usb_ctrlrequest *ctrl) | ||
490 | { | ||
491 | struct usb_composite_dev *cdev = f->config->cdev; | ||
492 | int value = -EOPNOTSUPP; | ||
493 | u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF); | ||
494 | u16 len = le16_to_cpu(ctrl->wLength); | ||
495 | u16 w_value = le16_to_cpu(ctrl->wValue); | ||
496 | |||
497 | DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n", | ||
498 | ctrl->bRequest, w_value, len, ep); | ||
499 | |||
500 | switch (ctrl->bRequest) { | ||
501 | case UAC_GET_CUR: | ||
502 | case UAC_GET_MIN: | ||
503 | case UAC_GET_MAX: | ||
504 | case UAC_GET_RES: | ||
505 | value = 3; | ||
506 | break; | ||
507 | case UAC_GET_MEM: | ||
508 | break; | ||
509 | default: | ||
510 | break; | ||
511 | } | ||
512 | |||
513 | return value; | ||
514 | } | ||
515 | |||
448 | static int | 516 | static int |
449 | f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) | 517 | f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) |
450 | { | 518 | { |
@@ -455,8 +523,8 @@ f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) | |||
455 | u16 w_value = le16_to_cpu(ctrl->wValue); | 523 | u16 w_value = le16_to_cpu(ctrl->wValue); |
456 | u16 w_length = le16_to_cpu(ctrl->wLength); | 524 | u16 w_length = le16_to_cpu(ctrl->wLength); |
457 | 525 | ||
458 | /* composite driver infrastructure handles everything except | 526 | /* composite driver infrastructure handles everything; interface |
459 | * Audio class messages; interface activation uses set_alt(). | 527 | * activation uses set_alt(). |
460 | */ | 528 | */ |
461 | switch (ctrl->bRequestType) { | 529 | switch (ctrl->bRequestType) { |
462 | case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE: | 530 | case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE: |
@@ -467,6 +535,14 @@ f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) | |||
467 | value = audio_get_intf_req(f, ctrl); | 535 | value = audio_get_intf_req(f, ctrl); |
468 | break; | 536 | break; |
469 | 537 | ||
538 | case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT: | ||
539 | value = audio_set_endpoint_req(f, ctrl); | ||
540 | break; | ||
541 | |||
542 | case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT: | ||
543 | value = audio_get_endpoint_req(f, ctrl); | ||
544 | break; | ||
545 | |||
470 | default: | 546 | default: |
471 | ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n", | 547 | ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n", |
472 | ctrl->bRequestType, ctrl->bRequest, | 548 | ctrl->bRequestType, ctrl->bRequest, |
@@ -504,6 +580,8 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) | |||
504 | usb_ep_enable(out_ep, audio->out_desc); | 580 | usb_ep_enable(out_ep, audio->out_desc); |
505 | out_ep->driver_data = audio; | 581 | out_ep->driver_data = audio; |
506 | audio->copy_buf = f_audio_buffer_alloc(audio_buf_size); | 582 | audio->copy_buf = f_audio_buffer_alloc(audio_buf_size); |
583 | if (IS_ERR(audio->copy_buf)) | ||
584 | return -ENOMEM; | ||
507 | 585 | ||
508 | /* | 586 | /* |
509 | * allocate a bunch of read buffers | 587 | * allocate a bunch of read buffers |
@@ -715,7 +793,7 @@ int __init audio_bind_config(struct usb_configuration *c) | |||
715 | return status; | 793 | return status; |
716 | 794 | ||
717 | add_fail: | 795 | add_fail: |
718 | gaudio_cleanup(&audio->card); | 796 | gaudio_cleanup(); |
719 | setup_fail: | 797 | setup_fail: |
720 | kfree(audio); | 798 | kfree(audio); |
721 | return status; | 799 | return status; |