Archived
14
0
Fork 0

V4L/DVB (4410): Cleanups and fixes for dsbr100

Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
Alan Cox 2006-08-08 15:47:50 -03:00 committed by Mauro Carvalho Chehab
parent c0c7fa0966
commit 5aff308c5e
2 changed files with 126 additions and 70 deletions

View file

@ -352,7 +352,7 @@ config RADIO_ZOLTRIX_PORT
config USB_DSBR config USB_DSBR
tristate "D-Link USB FM radio support (EXPERIMENTAL)" tristate "D-Link USB FM radio support (EXPERIMENTAL)"
depends on USB && VIDEO_V4L1 && EXPERIMENTAL depends on USB && VIDEO_V4L2 && EXPERIMENTAL
---help--- ---help---
Say Y here if you want to connect this type of radio to your Say Y here if you want to connect this type of radio to your
computer's USB port. Note that the audio is not digital, and computer's USB port. Note that the audio is not digital, and

View file

@ -33,8 +33,14 @@
History: History:
Version 0.41-ac1:
Alan Cox: Some cleanups and fixes
Version 0.41:
Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
Version 0.40: Version 0.40:
Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
Version 0.30: Version 0.30:
Markus: Updates for 2.5.x kernel and more ISO compliant source Markus: Updates for 2.5.x kernel and more ISO compliant source
@ -65,13 +71,12 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/videodev.h> #include <linux/videodev2.h>
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
@ -79,7 +84,22 @@
/* /*
* Version Information * Version Information
*/ */
#define DRIVER_VERSION "v0.40" #include <linux/version.h> /* for KERNEL_VERSION MACRO */
#define DRIVER_VERSION "v0.41"
#define RADIO_VERSION KERNEL_VERSION(0,4,1)
static struct v4l2_queryctrl radio_qctrl[] = {
{
.id = V4L2_CID_AUDIO_MUTE,
.name = "Mute",
.minimum = 0,
.maximum = 1,
.default_value = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
}
};
#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>" #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver" #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
@ -111,7 +131,7 @@ static int radio_nr = -1;
module_param(radio_nr, int, 0); module_param(radio_nr, int, 0);
/* Data for one (physical) device */ /* Data for one (physical) device */
typedef struct { struct dsbr100_device {
struct usb_device *usbdev; struct usb_device *usbdev;
struct video_device *videodev; struct video_device *videodev;
unsigned char transfer_buffer[TB_LEN]; unsigned char transfer_buffer[TB_LEN];
@ -119,7 +139,8 @@ typedef struct {
int stereo; int stereo;
int users; int users;
int removed; int removed;
} dsbr100_device; int muted;
};
/* File system interface */ /* File system interface */
@ -138,7 +159,6 @@ static struct video_device dsbr100_videodev_template=
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "D-Link DSB-R 100", .name = "D-Link DSB-R 100",
.type = VID_TYPE_TUNER, .type = VID_TYPE_TUNER,
.hardware = VID_HARDWARE_AZTECH,
.fops = &usb_dsbr100_fops, .fops = &usb_dsbr100_fops,
.release = video_device_release, .release = video_device_release,
}; };
@ -161,7 +181,7 @@ static struct usb_driver usb_dsbr100_driver = {
/* Low-level device interface begins here */ /* Low-level device interface begins here */
/* switch on radio */ /* switch on radio */
static int dsbr100_start(dsbr100_device *radio) static int dsbr100_start(struct dsbr100_device *radio)
{ {
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS, USB_REQ_GET_STATUS,
@ -172,12 +192,13 @@ static int dsbr100_start(dsbr100_device *radio)
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x01, 0x00, radio->transfer_buffer, 8, 300)<0) 0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
return -1; return -1;
radio->muted=0;
return (radio->transfer_buffer)[0]; return (radio->transfer_buffer)[0];
} }
/* switch off radio */ /* switch off radio */
static int dsbr100_stop(dsbr100_device *radio) static int dsbr100_stop(struct dsbr100_device *radio)
{ {
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS, USB_REQ_GET_STATUS,
@ -188,11 +209,12 @@ static int dsbr100_stop(dsbr100_device *radio)
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x00, 0x00, radio->transfer_buffer, 8, 300)<0) 0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
return -1; return -1;
radio->muted=1;
return (radio->transfer_buffer)[0]; return (radio->transfer_buffer)[0];
} }
/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
static int dsbr100_setfreq(dsbr100_device *radio, int freq) static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
{ {
freq = (freq/16*80)/1000+856; freq = (freq/16*80)/1000+856;
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
@ -217,7 +239,7 @@ static int dsbr100_setfreq(dsbr100_device *radio, int freq)
/* return the device status. This is, in effect, just whether it /* return the device status. This is, in effect, just whether it
sees a stereo signal or not. Pity. */ sees a stereo signal or not. Pity. */
static void dsbr100_getstat(dsbr100_device *radio) static void dsbr100_getstat(struct dsbr100_device *radio)
{ {
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS, USB_REQ_GET_STATUS,
@ -236,9 +258,9 @@ usb if it is */
static int usb_dsbr100_probe(struct usb_interface *intf, static int usb_dsbr100_probe(struct usb_interface *intf,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
dsbr100_device *radio; struct dsbr100_device *radio;
if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL))) if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
if (!(radio->videodev = video_device_alloc())) { if (!(radio->videodev = video_device_alloc())) {
kfree(radio); kfree(radio);
@ -271,7 +293,7 @@ code I'd expect I better did that, but if there's a memory
leak here it's tiny (~50 bytes per disconnect) */ leak here it's tiny (~50 bytes per disconnect) */
static void usb_dsbr100_disconnect(struct usb_interface *intf) static void usb_dsbr100_disconnect(struct usb_interface *intf)
{ {
dsbr100_device *radio = usb_get_intfdata(intf); struct dsbr100_device *radio = usb_get_intfdata(intf);
usb_set_intfdata (intf, NULL); usb_set_intfdata (intf, NULL);
if (radio) { if (radio) {
@ -291,89 +313,121 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file, static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg) unsigned int cmd, void *arg)
{ {
dsbr100_device *radio=video_get_drvdata(video_devdata(file)); struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
if (!radio) if (!radio)
return -EIO; return -EIO;
switch(cmd) { switch(cmd) {
case VIDIOCGCAP: { case VIDIOC_QUERYCAP:
struct video_capability *v = arg; {
struct v4l2_capability *v = arg;
memset(v,0,sizeof(*v));
strlcpy(v->driver, "dsbr100", sizeof (v->driver));
strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof (v->card));
sprintf(v->bus_info,"ISA");
v->version = RADIO_VERSION;
v->capabilities = V4L2_CAP_TUNER;
memset(v, 0, sizeof(*v));
v->type = VID_TYPE_TUNER;
v->channels = 1;
v->audios = 1;
strcpy(v->name, "D-Link R-100 USB FM Radio");
return 0; return 0;
} }
case VIDIOCGTUNER: { case VIDIOC_G_TUNER:
struct video_tuner *v = arg; {
struct v4l2_tuner *v = arg;
if (v->index > 0)
return -EINVAL;
dsbr100_getstat(radio); dsbr100_getstat(radio);
if(v->tuner) /* Only 1 tuner */
return -EINVAL; memset(v,0,sizeof(*v));
strcpy(v->name, "FM");
v->type = V4L2_TUNER_RADIO;
v->rangelow = FREQ_MIN*FREQ_MUL; v->rangelow = FREQ_MIN*FREQ_MUL;
v->rangehigh = FREQ_MAX*FREQ_MUL; v->rangehigh = FREQ_MAX*FREQ_MUL;
v->flags = VIDEO_TUNER_LOW; v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
v->mode = VIDEO_MODE_AUTO; v->capability=V4L2_TUNER_CAP_LOW;
v->signal = radio->stereo*0x7000; if(radio->stereo)
/* Don't know how to get signal strength */ v->audmode = V4L2_TUNER_MODE_STEREO;
v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo; else
strcpy(v->name, "DSB R-100"); v->audmode = V4L2_TUNER_MODE_MONO;
v->signal = 0xFFFF; /* We can't get the signal strength */
return 0; return 0;
} }
case VIDIOCSTUNER: { case VIDIOC_S_TUNER:
struct video_tuner *v = arg; {
struct v4l2_tuner *v = arg;
if(v->tuner!=0) if (v->index > 0)
return -EINVAL; return -EINVAL;
/* Only 1 tuner so no setting needed ! */
return 0; return 0;
} }
case VIDIOCGFREQ: { case VIDIOC_S_FREQUENCY:
int *freq = arg; {
struct v4l2_frequency *f = arg;
if (radio->curfreq==-1) radio->curfreq = f->frequency;
return -EINVAL;
*freq = radio->curfreq;
return 0;
}
case VIDIOCSFREQ: {
int *freq = arg;
radio->curfreq = *freq;
if (dsbr100_setfreq(radio, radio->curfreq)==-1) if (dsbr100_setfreq(radio, radio->curfreq)==-1)
warn("Set frequency failed"); warn("Set frequency failed");
return 0; return 0;
} }
case VIDIOCGAUDIO: { case VIDIOC_G_FREQUENCY:
struct video_audio *v = arg; {
struct v4l2_frequency *f = arg;
f->type = V4L2_TUNER_RADIO;
f->frequency = radio->curfreq;
memset(v, 0, sizeof(*v));
v->flags |= VIDEO_AUDIO_MUTABLE;
v->mode = VIDEO_SOUND_STEREO;
v->volume = 1;
v->step = 1;
strcpy(v->name, "Radio");
return 0; return 0;
} }
case VIDIOCSAUDIO: { case VIDIOC_QUERYCTRL:
struct video_audio *v = arg; {
struct v4l2_queryctrl *qc = arg;
int i;
if (v->audio) for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
return -EINVAL; if (qc->id && qc->id == radio_qctrl[i].id) {
if (v->flags&VIDEO_AUDIO_MUTE) { memcpy(qc, &(radio_qctrl[i]),
if (dsbr100_stop(radio)==-1) sizeof(*qc));
warn("Radio did not respond properly"); return 0;
}
} }
else return -EINVAL;
if (dsbr100_start(radio)==-1) }
warn("Radio did not respond properly"); case VIDIOC_G_CTRL:
return 0; {
struct v4l2_control *ctrl= arg;
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
ctrl->value=radio->muted;
return 0;
}
return -EINVAL;
}
case VIDIOC_S_CTRL:
{
struct v4l2_control *ctrl= arg;
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
if (ctrl->value) {
if (dsbr100_stop(radio)==-1)
warn("Radio did not respond properly");
} else {
if (dsbr100_start(radio)==-1)
warn("Radio did not respond properly");
}
return 0;
}
return -EINVAL;
} }
default: default:
return -ENOIOCTLCMD; return v4l_compat_translate_ioctl(inode,file,cmd,arg,
usb_dsbr100_do_ioctl);
} }
} }
@ -385,9 +439,11 @@ static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
static int usb_dsbr100_open(struct inode *inode, struct file *file) static int usb_dsbr100_open(struct inode *inode, struct file *file)
{ {
dsbr100_device *radio=video_get_drvdata(video_devdata(file)); struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
radio->users = 1; radio->users = 1;
radio->muted = 1;
if (dsbr100_start(radio)<0) { if (dsbr100_start(radio)<0) {
warn("Radio did not start up properly"); warn("Radio did not start up properly");
radio->users = 0; radio->users = 0;
@ -399,7 +455,7 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file)
static int usb_dsbr100_close(struct inode *inode, struct file *file) static int usb_dsbr100_close(struct inode *inode, struct file *file)
{ {
dsbr100_device *radio=video_get_drvdata(video_devdata(file)); struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
if (!radio) if (!radio)
return -ENODEV; return -ENODEV;