aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2011-06-17 14:15:12 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-07-27 16:53:04 -0400
commit4f83e7b3ef938eb9a01eadf81a0f3b2c67d3afb6 (patch)
treef49cd93355efa11d2ad2ce97bb25bbeb0d4ad155 /drivers
parentdff0f8c279e34089128e9687d77bfc72dbb471bd (diff)
[media] em28xx: Add support for devices with a separate audio interface
Some devices use a separate interface for the vendor audio class. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/em28xx/em28xx-audio.c44
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c102
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c20
-rw-r--r--drivers/media/video/em28xx/em28xx.h3
4 files changed, 109 insertions, 60 deletions
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
index 47f21a382546..cff0768afbf5 100644
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -3,9 +3,9 @@
3 * 3 *
4 * Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com> 4 * Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
5 * 5 *
6 * Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@infradead.org> 6 * Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
7 * - Port to work with the in-kernel driver 7 * - Port to work with the in-kernel driver
8 * - Several cleanups 8 * - Cleanups, fixes, alsa-controls, etc.
9 * 9 *
10 * This driver is based on my previous au600 usb pstn audio driver 10 * This driver is based on my previous au600 usb pstn audio driver
11 * and inherits all the copyrights 11 * and inherits all the copyrights
@@ -281,23 +281,27 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
281 return -ENODEV; 281 return -ENODEV;
282 } 282 }
283 283
284 /* Sets volume, mute, etc */ 284 runtime->hw = snd_em28xx_hw_capture;
285 if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) {
286 if (dev->audio_ifnum)
287 dev->alt = 1;
288 else
289 dev->alt = 7;
285 290
286 dev->mute = 0; 291 dprintk("changing alternate number on interface %d to %d\n",
287 mutex_lock(&dev->lock); 292 dev->audio_ifnum, dev->alt);
288 ret = em28xx_audio_analog_set(dev); 293 usb_set_interface(dev->udev, dev->audio_ifnum, dev->alt);
289 if (ret < 0)
290 goto err;
291 294
292 runtime->hw = snd_em28xx_hw_capture; 295 /* Sets volume, mute, etc */
293 if (dev->alt == 0 && dev->adev.users == 0) { 296 dev->mute = 0;
294 dev->alt = 7; 297 mutex_lock(&dev->lock);
295 dprintk("changing alternate number to 7\n"); 298 ret = em28xx_audio_analog_set(dev);
296 usb_set_interface(dev->udev, 0, 7); 299 if (ret < 0)
297 } 300 goto err;
298 301
299 dev->adev.users++; 302 dev->adev.users++;
300 mutex_unlock(&dev->lock); 303 mutex_unlock(&dev->lock);
304 }
301 305
302 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 306 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
303 dev->adev.capture_pcm_substream = substream; 307 dev->adev.capture_pcm_substream = substream;
@@ -635,17 +639,17 @@ static int em28xx_audio_init(struct em28xx *dev)
635 static int devnr; 639 static int devnr;
636 int err; 640 int err;
637 641
638 if (dev->has_alsa_audio != 1) { 642 if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
639 /* This device does not support the extension (in this case 643 /* This device does not support the extension (in this case
640 the device is expecting the snd-usb-audio module or 644 the device is expecting the snd-usb-audio module or
641 doesn't have analog audio support at all) */ 645 doesn't have analog audio support at all) */
642 return 0; 646 return 0;
643 } 647 }
644 648
645 printk(KERN_INFO "em28xx-audio.c: probing for em28x1 " 649 printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n");
646 "non standard usbaudio\n");
647 printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus " 650 printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
648 "Rechberger\n"); 651 "Rechberger\n");
652 printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
649 653
650 err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0, 654 err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
651 &card); 655 &card);
@@ -737,7 +741,7 @@ static void __exit em28xx_alsa_unregister(void)
737 741
738MODULE_LICENSE("GPL"); 742MODULE_LICENSE("GPL");
739MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>"); 743MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
740MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); 744MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
741MODULE_DESCRIPTION("Em28xx Audio driver"); 745MODULE_DESCRIPTION("Em28xx Audio driver");
742 746
743module_init(em28xx_alsa_register); 747module_init(em28xx_alsa_register);
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index bbd67d754b59..c445bea2f27e 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -2846,6 +2846,16 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
2846 } 2846 }
2847 } 2847 }
2848 2848
2849 if (dev->is_audio_only) {
2850 errCode = em28xx_audio_setup(dev);
2851 if (errCode)
2852 return -ENODEV;
2853 em28xx_add_into_devlist(dev);
2854 em28xx_init_extension(dev);
2855
2856 return 0;
2857 }
2858
2849 /* Prepopulate cached GPO register content */ 2859 /* Prepopulate cached GPO register content */
2850 retval = em28xx_read_reg(dev, dev->reg_gpo_num); 2860 retval = em28xx_read_reg(dev, dev->reg_gpo_num);
2851 if (retval >= 0) 2861 if (retval >= 0)
@@ -2946,6 +2956,9 @@ fail_reg_devices:
2946 return retval; 2956 return retval;
2947} 2957}
2948 2958
2959/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
2960#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
2961
2949/* 2962/*
2950 * em28xx_usb_probe() 2963 * em28xx_usb_probe()
2951 * checks for supported devices 2964 * checks for supported devices
@@ -2955,15 +2968,15 @@ static int em28xx_usb_probe(struct usb_interface *interface,
2955{ 2968{
2956 const struct usb_endpoint_descriptor *endpoint; 2969 const struct usb_endpoint_descriptor *endpoint;
2957 struct usb_device *udev; 2970 struct usb_device *udev;
2958 struct usb_interface *uif;
2959 struct em28xx *dev = NULL; 2971 struct em28xx *dev = NULL;
2960 int retval; 2972 int retval;
2961 int i, nr, ifnum, isoc_pipe; 2973 bool is_audio_only = false, has_audio = false;
2974 int i, nr, isoc_pipe;
2975 const int ifnum = interface->altsetting[0].desc.bInterfaceNumber;
2962 char *speed; 2976 char *speed;
2963 char descr[255] = ""; 2977 char descr[255] = "";
2964 2978
2965 udev = usb_get_dev(interface_to_usbdev(interface)); 2979 udev = usb_get_dev(interface_to_usbdev(interface));
2966 ifnum = interface->altsetting[0].desc.bInterfaceNumber;
2967 2980
2968 /* Check to see next free device and mark as used */ 2981 /* Check to see next free device and mark as used */
2969 nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS); 2982 nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
@@ -2983,6 +2996,19 @@ static int em28xx_usb_probe(struct usb_interface *interface,
2983 goto err; 2996 goto err;
2984 } 2997 }
2985 2998
2999 /* Get endpoints */
3000 for (i = 0; i < interface->num_altsetting; i++) {
3001 int ep;
3002
3003 for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
3004 struct usb_host_endpoint *e;
3005 e = &interface->altsetting[i].endpoint[ep];
3006
3007 if (e->desc.bEndpointAddress == 0x83)
3008 has_audio = true;
3009 }
3010 }
3011
2986 endpoint = &interface->cur_altsetting->endpoint[0].desc; 3012 endpoint = &interface->cur_altsetting->endpoint[0].desc;
2987 3013
2988 /* check if the device has the iso in endpoint at the correct place */ 3014 /* check if the device has the iso in endpoint at the correct place */
@@ -3002,19 +3028,22 @@ static int em28xx_usb_probe(struct usb_interface *interface,
3002 check_interface = 0; 3028 check_interface = 0;
3003 3029
3004 if (!check_interface) { 3030 if (!check_interface) {
3005 em28xx_err(DRIVER_NAME " video device (%04x:%04x): " 3031 if (has_audio) {
3006 "interface %i, class %i found.\n", 3032 is_audio_only = true;
3007 le16_to_cpu(udev->descriptor.idVendor), 3033 } else {
3008 le16_to_cpu(udev->descriptor.idProduct), 3034 em28xx_err(DRIVER_NAME " video device (%04x:%04x): "
3009 ifnum, 3035 "interface %i, class %i found.\n",
3010 interface->altsetting[0].desc.bInterfaceClass); 3036 le16_to_cpu(udev->descriptor.idVendor),
3011 3037 le16_to_cpu(udev->descriptor.idProduct),
3012 em28xx_err(DRIVER_NAME " This is an anciliary " 3038 ifnum,
3013 "interface not used by the driver\n"); 3039 interface->altsetting[0].desc.bInterfaceClass);
3014 3040 em28xx_err(DRIVER_NAME " This is an anciliary "
3015 em28xx_devused &= ~(1<<nr); 3041 "interface not used by the driver\n");
3016 retval = -ENODEV; 3042
3017 goto err; 3043 em28xx_devused &= ~(1<<nr);
3044 retval = -ENODEV;
3045 goto err;
3046 }
3018 } 3047 }
3019 } 3048 }
3020 3049
@@ -3044,8 +3073,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
3044 if (*descr) 3073 if (*descr)
3045 strlcat(descr, " ", sizeof(descr)); 3074 strlcat(descr, " ", sizeof(descr));
3046 3075
3047 printk(DRIVER_NAME ": New device %s@ %s Mbps " 3076 printk(KERN_INFO DRIVER_NAME
3048 "(%04x:%04x, interface %d, class %d)\n", 3077 ": New device %s@ %s Mbps (%04x:%04x, interface %d, class %d)\n",
3049 descr, 3078 descr,
3050 speed, 3079 speed,
3051 le16_to_cpu(udev->descriptor.idVendor), 3080 le16_to_cpu(udev->descriptor.idVendor),
@@ -3053,6 +3082,11 @@ static int em28xx_usb_probe(struct usb_interface *interface,
3053 ifnum, 3082 ifnum,
3054 interface->altsetting->desc.bInterfaceNumber); 3083 interface->altsetting->desc.bInterfaceNumber);
3055 3084
3085 if (has_audio)
3086 printk(KERN_INFO DRIVER_NAME
3087 ": Audio Vendor Class interface %i found\n",
3088 ifnum);
3089
3056 /* 3090 /*
3057 * Make sure we have 480 Mbps of bandwidth, otherwise things like 3091 * Make sure we have 480 Mbps of bandwidth, otherwise things like
3058 * video stream wouldn't likely work, since 12 Mbps is generally 3092 * video stream wouldn't likely work, since 12 Mbps is generally
@@ -3088,10 +3122,13 @@ static int em28xx_usb_probe(struct usb_interface *interface,
3088 dev->devno = nr; 3122 dev->devno = nr;
3089 dev->model = id->driver_info; 3123 dev->model = id->driver_info;
3090 dev->alt = -1; 3124 dev->alt = -1;
3125 dev->is_audio_only = is_audio_only;
3126 dev->has_alsa_audio = has_audio;
3127 dev->audio_ifnum = ifnum;
3091 3128
3092 /* Checks if audio is provided by some interface */ 3129 /* Checks if audio is provided by some interface */
3093 for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { 3130 for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
3094 uif = udev->config->interface[i]; 3131 struct usb_interface *uif = udev->config->interface[i];
3095 if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { 3132 if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
3096 dev->has_audio_class = 1; 3133 dev->has_audio_class = 1;
3097 break; 3134 break;
@@ -3099,9 +3136,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
3099 } 3136 }
3100 3137
3101 /* compute alternate max packet sizes */ 3138 /* compute alternate max packet sizes */
3102 uif = udev->actconfig->interface[0]; 3139 dev->num_alt = interface->num_altsetting;
3103
3104 dev->num_alt = uif->num_altsetting;
3105 dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL); 3140 dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL);
3106 3141
3107 if (dev->alt_max_pkt_size == NULL) { 3142 if (dev->alt_max_pkt_size == NULL) {
@@ -3113,14 +3148,21 @@ static int em28xx_usb_probe(struct usb_interface *interface,
3113 } 3148 }
3114 3149
3115 for (i = 0; i < dev->num_alt ; i++) { 3150 for (i = 0; i < dev->num_alt ; i++) {
3116 u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize); 3151 u16 tmp = le16_to_cpu(interface->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize);
3117 dev->alt_max_pkt_size[i] = 3152 unsigned int size = tmp & 0x7ff;
3118 (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); 3153
3154 if (udev->speed == USB_SPEED_HIGH)
3155 size = size * hb_mult(tmp);
3156
3157 dev->alt_max_pkt_size[i] = size;
3119 } 3158 }
3120 3159
3121 if ((card[nr] >= 0) && (card[nr] < em28xx_bcount)) 3160 if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
3122 dev->model = card[nr]; 3161 dev->model = card[nr];
3123 3162
3163 /* save our data pointer in this interface device */
3164 usb_set_intfdata(interface, dev);
3165
3124 /* allocate device struct */ 3166 /* allocate device struct */
3125 mutex_init(&dev->lock); 3167 mutex_init(&dev->lock);
3126 mutex_lock(&dev->lock); 3168 mutex_lock(&dev->lock);
@@ -3132,9 +3174,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
3132 goto err; 3174 goto err;
3133 } 3175 }
3134 3176
3135 /* save our data pointer in this interface device */
3136 usb_set_intfdata(interface, dev);
3137
3138 request_modules(dev); 3177 request_modules(dev);
3139 3178
3140 /* Should be the last thing to do, to avoid newer udev's to 3179 /* Should be the last thing to do, to avoid newer udev's to
@@ -3163,6 +3202,13 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
3163 if (!dev) 3202 if (!dev)
3164 return; 3203 return;
3165 3204
3205 if (dev->is_audio_only) {
3206 mutex_lock(&dev->lock);
3207 em28xx_close_extension(dev);
3208 mutex_unlock(&dev->lock);
3209 return;
3210 }
3211
3166 em28xx_info("disconnecting %s\n", dev->vdev->name); 3212 em28xx_info("disconnecting %s\n", dev->vdev->name);
3167 3213
3168 flush_request_modules(dev); 3214 flush_request_modules(dev);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 752d4ed7f828..16c9b73b1c3f 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -499,17 +499,13 @@ int em28xx_audio_setup(struct em28xx *dev)
499 if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874 499 if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874
500 || dev->chip_id == CHIP_ID_EM28174) { 500 || dev->chip_id == CHIP_ID_EM28174) {
501 /* Digital only device - don't load any alsa module */ 501 /* Digital only device - don't load any alsa module */
502 dev->audio_mode.has_audio = 0; 502 dev->audio_mode.has_audio = false;
503 dev->has_audio_class = 0; 503 dev->has_audio_class = false;
504 dev->has_alsa_audio = 0; 504 dev->has_alsa_audio = false;
505 return 0; 505 return 0;
506 } 506 }
507 507
508 /* If device doesn't support Usb Audio Class, use vendor class */ 508 dev->audio_mode.has_audio = true;
509 if (!dev->has_audio_class)
510 dev->has_alsa_audio = 1;
511
512 dev->audio_mode.has_audio = 1;
513 509
514 /* See how this device is configured */ 510 /* See how this device is configured */
515 cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); 511 cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
@@ -519,8 +515,8 @@ int em28xx_audio_setup(struct em28xx *dev)
519 cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */ 515 cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */
520 } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) { 516 } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) {
521 /* The device doesn't have vendor audio at all */ 517 /* The device doesn't have vendor audio at all */
522 dev->has_alsa_audio = 0; 518 dev->has_alsa_audio = false;
523 dev->audio_mode.has_audio = 0; 519 dev->audio_mode.has_audio = false;
524 return 0; 520 return 0;
525 } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 521 } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
526 EM28XX_CHIPCFG_I2S_3_SAMPRATES) { 522 EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
@@ -549,8 +545,8 @@ int em28xx_audio_setup(struct em28xx *dev)
549 */ 545 */
550 em28xx_warn("AC97 chip type couldn't be determined\n"); 546 em28xx_warn("AC97 chip type couldn't be determined\n");
551 dev->audio_mode.ac97 = EM28XX_NO_AC97; 547 dev->audio_mode.ac97 = EM28XX_NO_AC97;
552 dev->has_alsa_audio = 0; 548 dev->has_alsa_audio = false;
553 dev->audio_mode.has_audio = 0; 549 dev->audio_mode.has_audio = false;
554 goto init_audio; 550 goto init_audio;
555 } 551 }
556 552
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index f9b77b4c90e4..e03849fd3717 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -487,6 +487,8 @@ struct em28xx {
487 int devno; /* marks the number of this device */ 487 int devno; /* marks the number of this device */
488 enum em28xx_chip_id chip_id; 488 enum em28xx_chip_id chip_id;
489 489
490 int audio_ifnum;
491
490 struct v4l2_device v4l2_dev; 492 struct v4l2_device v4l2_dev;
491 struct em28xx_board board; 493 struct em28xx_board board;
492 494
@@ -503,6 +505,7 @@ struct em28xx {
503 505
504 unsigned int has_audio_class:1; 506 unsigned int has_audio_class:1;
505 unsigned int has_alsa_audio:1; 507 unsigned int has_alsa_audio:1;
508 unsigned int is_audio_only:1;
506 509
507 /* Controls audio streaming */ 510 /* Controls audio streaming */
508 struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ 511 struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */