[PATCH 06/14] V4L/DVB (4407): Driver dsbr100 is a radio device, not a video one!

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Mauro Carvalho Chehab <[email protected]>

Signed-off-by: Mauro Carvalho Chehab <[email protected]>
---

 drivers/media/radio/Kconfig   |   12 +
 drivers/media/radio/Makefile  |    1 
 drivers/media/radio/dsbr100.c |  430 +++++++++++++++++++++++++++++++++++++++++
 drivers/media/video/Kconfig   |   12 -
 drivers/media/video/Makefile  |    1 
 drivers/media/video/dsbr100.c |  430 -----------------------------------------
 6 files changed, 442 insertions(+), 444 deletions(-)

diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index de3128a..220076b 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -350,5 +350,15 @@ config RADIO_ZOLTRIX_PORT
 	help
 	  Enter the I/O port of your Zoltrix radio card.
 
-endmenu
+config USB_DSBR
+	tristate "D-Link USB FM radio support (EXPERIMENTAL)"
+	depends on USB && VIDEO_V4L1 && EXPERIMENTAL
+	---help---
+	  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
+	  you must connect the line out connector to a sound card or a
+	  set of speakers.
 
+	  To compile this driver as a module, choose M here: the
+	  module will be called dsbr100.
+endmenu
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index e95b680..cf55a18 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -20,5 +20,6 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemt
 obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
+obj-$(CONFIG_USB_DSBR) += dsbr100.o
 
 EXTRA_CFLAGS += -Isound
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
new file mode 100644
index 0000000..f7e33f9
--- /dev/null
+++ b/drivers/media/radio/dsbr100.c
@@ -0,0 +1,430 @@
+/* A driver for the D-Link DSB-R100 USB radio.  The R100 plugs
+ into both the USB and an analog audio input, so this thing
+ only deals with initialisation and frequency setting, the
+ audio data has to be handled by a sound driver.
+
+ Major issue: I can't find out where the device reports the signal
+ strength, and indeed the windows software appearantly just looks
+ at the stereo indicator as well.  So, scanning will only find
+ stereo stations.  Sad, but I can't help it.
+
+ Also, the windows program sends oodles of messages over to the
+ device, and I couldn't figure out their meaning.  My suspicion
+ is that they don't have any:-)
+
+ You might find some interesting stuff about this module at
+ http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
+
+ Copyright (c) 2000 Markus Demleitner <[email protected]>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ History:
+
+ Version 0.40:
+  Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
+
+ Version 0.30:
+	Markus: Updates for 2.5.x kernel and more ISO compliant source
+
+ Version 0.25:
+	PSL and Markus: Cleanup, radio now doesn't stop on device close
+
+ Version 0.24:
+	Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
+	right.  Some minor cleanup, improved standalone compilation
+
+ Version 0.23:
+	Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
+
+ Version 0.22:
+	Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
+	thanks to Mike Cox for pointing the problem out.
+
+ Version 0.21:
+	Markus: Minor cleanup, warnings if something goes wrong, lame attempt
+	to adhere to Documentation/CodingStyle
+
+ Version 0.2:
+	Brad Hards <[email protected]>: Fixes to make it work as non-module
+	Markus: Copyright clarification
+
+ Version 0.01: Markus: initial release
+
+*/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+#include <linux/usb.h>
+#include <linux/smp_lock.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.40"
+#define DRIVER_AUTHOR "Markus Demleitner <[email protected]>"
+#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
+
+#define DSB100_VENDOR 0x04b4
+#define DSB100_PRODUCT 0x1002
+
+/* Commands the device appears to understand */
+#define DSB100_TUNE 1
+#define DSB100_ONOFF 2
+
+#define TB_LEN 16
+
+/* Frequency limits in MHz -- these are European values.  For Japanese
+devices, that would be 76 and 91.  */
+#define FREQ_MIN  87.5
+#define FREQ_MAX 108.0
+#define FREQ_MUL 16000
+
+
+static int usb_dsbr100_probe(struct usb_interface *intf,
+			     const struct usb_device_id *id);
+static void usb_dsbr100_disconnect(struct usb_interface *intf);
+static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
+			     unsigned int cmd, unsigned long arg);
+static int usb_dsbr100_open(struct inode *inode, struct file *file);
+static int usb_dsbr100_close(struct inode *inode, struct file *file);
+
+static int radio_nr = -1;
+module_param(radio_nr, int, 0);
+
+/* Data for one (physical) device */
+typedef struct {
+	struct usb_device *usbdev;
+	struct video_device *videodev;
+	unsigned char transfer_buffer[TB_LEN];
+	int curfreq;
+	int stereo;
+	int users;
+	int removed;
+} dsbr100_device;
+
+
+/* File system interface */
+static struct file_operations usb_dsbr100_fops = {
+	.owner =	THIS_MODULE,
+	.open =		usb_dsbr100_open,
+	.release =     	usb_dsbr100_close,
+	.ioctl =        usb_dsbr100_ioctl,
+	.compat_ioctl = v4l_compat_ioctl32,
+	.llseek =       no_llseek,
+};
+
+/* V4L interface */
+static struct video_device dsbr100_videodev_template=
+{
+	.owner =	THIS_MODULE,
+	.name =		"D-Link DSB-R 100",
+	.type =		VID_TYPE_TUNER,
+	.hardware =	VID_HARDWARE_AZTECH,
+	.fops =         &usb_dsbr100_fops,
+	.release = video_device_release,
+};
+
+static struct usb_device_id usb_dsbr100_device_table [] = {
+	{ USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
+	{ }						/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
+
+/* USB subsystem interface */
+static struct usb_driver usb_dsbr100_driver = {
+	.name =		"dsbr100",
+	.probe =	usb_dsbr100_probe,
+	.disconnect =	usb_dsbr100_disconnect,
+	.id_table =	usb_dsbr100_device_table,
+};
+
+/* Low-level device interface begins here */
+
+/* switch on radio */
+static int dsbr100_start(dsbr100_device *radio)
+{
+	if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+			USB_REQ_GET_STATUS,
+			USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+			0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
+	usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+			DSB100_ONOFF,
+			USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+			0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
+		return -1;
+	return (radio->transfer_buffer)[0];
+}
+
+
+/* switch off radio */
+static int dsbr100_stop(dsbr100_device *radio)
+{
+	if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+			USB_REQ_GET_STATUS,
+			USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+			0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
+	usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+			DSB100_ONOFF,
+			USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+			0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
+		return -1;
+	return (radio->transfer_buffer)[0];
+}
+
+/* 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)
+{
+	freq = (freq/16*80)/1000+856;
+	if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+			DSB100_TUNE,
+			USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+			(freq>>8)&0x00ff, freq&0xff,
+			radio->transfer_buffer, 8, 300)<0 ||
+	   usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+			USB_REQ_GET_STATUS,
+			USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+			0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
+	usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+			USB_REQ_GET_STATUS,
+			USB_TYPE_VENDOR | USB_RECIP_DEVICE |  USB_DIR_IN,
+			0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
+		radio->stereo = -1;
+		return -1;
+	}
+	radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
+	return (radio->transfer_buffer)[0];
+}
+
+/* return the device status.  This is, in effect, just whether it
+sees a stereo signal or not.  Pity. */
+static void dsbr100_getstat(dsbr100_device *radio)
+{
+	if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+		USB_REQ_GET_STATUS,
+		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+		0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
+		radio->stereo = -1;
+	else
+		radio->stereo = ! (radio->transfer_buffer[0]&0x01);
+}
+
+
+/* USB subsystem interface begins here */
+
+/* check if the device is present and register with v4l and
+usb if it is */
+static int usb_dsbr100_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	dsbr100_device *radio;
+
+	if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL)))
+		return -ENOMEM;
+	if (!(radio->videodev = video_device_alloc())) {
+		kfree(radio);
+		return -ENOMEM;
+	}
+	memcpy(radio->videodev, &dsbr100_videodev_template,
+		sizeof(dsbr100_videodev_template));
+	radio->removed = 0;
+	radio->users = 0;
+	radio->usbdev = interface_to_usbdev(intf);
+	radio->curfreq = FREQ_MIN*FREQ_MUL;
+	video_set_drvdata(radio->videodev, radio);
+	if (video_register_device(radio->videodev, VFL_TYPE_RADIO,
+		radio_nr)) {
+		warn("Could not register video device");
+		video_device_release(radio->videodev);
+		kfree(radio);
+		return -EIO;
+	}
+	usb_set_intfdata(intf, radio);
+	return 0;
+}
+
+/* handle unplugging of the device, release data structures
+if nothing keeps us from doing it.  If something is still
+keeping us busy, the release callback of v4l will take care
+of releasing it.  stv680.c does not relase its private
+data, so I don't do this here either.  Checking out the
+code I'd expect I better did that, but if there's a memory
+leak here it's tiny (~50 bytes per disconnect) */
+static void usb_dsbr100_disconnect(struct usb_interface *intf)
+{
+	dsbr100_device *radio = usb_get_intfdata(intf);
+
+	usb_set_intfdata (intf, NULL);
+	if (radio) {
+		video_unregister_device(radio->videodev);
+		radio->videodev = NULL;
+		if (radio->users) {
+			kfree(radio);
+		} else {
+			radio->removed = 1;
+		}
+	}
+}
+
+
+/* Video for Linux interface */
+
+static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file,
+				unsigned int cmd, void *arg)
+{
+	dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+
+	if (!radio)
+		return -EIO;
+
+	switch(cmd) {
+		case VIDIOCGCAP: {
+			struct video_capability *v = arg;
+
+			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;
+		}
+		case VIDIOCGTUNER: {
+			struct video_tuner *v = arg;
+
+			dsbr100_getstat(radio);
+			if(v->tuner)	/* Only 1 tuner */
+				return -EINVAL;
+			v->rangelow = FREQ_MIN*FREQ_MUL;
+			v->rangehigh = FREQ_MAX*FREQ_MUL;
+			v->flags = VIDEO_TUNER_LOW;
+			v->mode = VIDEO_MODE_AUTO;
+			v->signal = radio->stereo*0x7000;
+				/* Don't know how to get signal strength */
+			v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo;
+			strcpy(v->name, "DSB R-100");
+			return 0;
+		}
+		case VIDIOCSTUNER: {
+			struct video_tuner *v = arg;
+
+			if(v->tuner!=0)
+				return -EINVAL;
+			/* Only 1 tuner so no setting needed ! */
+			return 0;
+		}
+		case VIDIOCGFREQ: {
+			int *freq = arg;
+
+			if (radio->curfreq==-1)
+				return -EINVAL;
+			*freq = radio->curfreq;
+			return 0;
+		}
+		case VIDIOCSFREQ: {
+			int *freq = arg;
+
+			radio->curfreq = *freq;
+			if (dsbr100_setfreq(radio, radio->curfreq)==-1)
+				warn("Set frequency failed");
+			return 0;
+		}
+		case VIDIOCGAUDIO: {
+			struct video_audio *v = arg;
+
+			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;
+		}
+		case VIDIOCSAUDIO: {
+			struct video_audio *v = arg;
+
+			if (v->audio)
+				return -EINVAL;
+			if (v->flags&VIDEO_AUDIO_MUTE) {
+				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;
+		}
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
+			     unsigned int cmd, unsigned long arg)
+{
+	return video_usercopy(inode, file, cmd, arg, usb_dsbr100_do_ioctl);
+}
+
+static int usb_dsbr100_open(struct inode *inode, struct file *file)
+{
+	dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+
+	radio->users = 1;
+	if (dsbr100_start(radio)<0) {
+		warn("Radio did not start up properly");
+		radio->users = 0;
+		return -EIO;
+	}
+	dsbr100_setfreq(radio, radio->curfreq);
+	return 0;
+}
+
+static int usb_dsbr100_close(struct inode *inode, struct file *file)
+{
+	dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+
+	if (!radio)
+		return -ENODEV;
+	radio->users = 0;
+	if (radio->removed) {
+		kfree(radio);
+	}
+	return 0;
+}
+
+static int __init dsbr100_init(void)
+{
+	int retval = usb_register(&usb_dsbr100_driver);
+	info(DRIVER_VERSION ":" DRIVER_DESC);
+	return retval;
+}
+
+static void __exit dsbr100_exit(void)
+{
+	usb_deregister(&usb_dsbr100_driver);
+}
+
+module_init (dsbr100_init);
+module_exit (dsbr100_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index fe56862..732bf1e 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -449,18 +449,6 @@ source "drivers/media/video/pvrusb2/Kcon
 
 source "drivers/media/video/em28xx/Kconfig"
 
-config USB_DSBR
-	tristate "D-Link USB FM radio support (EXPERIMENTAL)"
-	depends on USB && VIDEO_V4L1 && EXPERIMENTAL
-	---help---
-	  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
-	  you must connect the line out connector to a sound card or a
-	  set of speakers.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called dsbr100.
-
 source "drivers/media/video/usbvideo/Kconfig"
 
 source "drivers/media/video/et61x251/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 353d61c..010833d 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -77,7 +77,6 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083
 obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
-obj-$(CONFIG_USB_DSBR)          += dsbr100.o
 obj-$(CONFIG_USB_OV511)         += ov511.o
 obj-$(CONFIG_USB_SE401)         += se401.o
 obj-$(CONFIG_USB_STV680)        += stv680.o
diff --git a/drivers/media/video/dsbr100.c b/drivers/media/video/dsbr100.c
deleted file mode 100644
index f7e33f9..0000000
--- a/drivers/media/video/dsbr100.c
+++ /dev/null
@@ -1,430 +0,0 @@
-/* A driver for the D-Link DSB-R100 USB radio.  The R100 plugs
- into both the USB and an analog audio input, so this thing
- only deals with initialisation and frequency setting, the
- audio data has to be handled by a sound driver.
-
- Major issue: I can't find out where the device reports the signal
- strength, and indeed the windows software appearantly just looks
- at the stereo indicator as well.  So, scanning will only find
- stereo stations.  Sad, but I can't help it.
-
- Also, the windows program sends oodles of messages over to the
- device, and I couldn't figure out their meaning.  My suspicion
- is that they don't have any:-)
-
- You might find some interesting stuff about this module at
- http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
-
- Copyright (c) 2000 Markus Demleitner <[email protected]>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- History:
-
- Version 0.40:
-  Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
-
- Version 0.30:
-	Markus: Updates for 2.5.x kernel and more ISO compliant source
-
- Version 0.25:
-	PSL and Markus: Cleanup, radio now doesn't stop on device close
-
- Version 0.24:
-	Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
-	right.  Some minor cleanup, improved standalone compilation
-
- Version 0.23:
-	Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
-
- Version 0.22:
-	Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
-	thanks to Mike Cox for pointing the problem out.
-
- Version 0.21:
-	Markus: Minor cleanup, warnings if something goes wrong, lame attempt
-	to adhere to Documentation/CodingStyle
-
- Version 0.2:
-	Brad Hards <[email protected]>: Fixes to make it work as non-module
-	Markus: Copyright clarification
-
- Version 0.01: Markus: initial release
-
-*/
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <linux/usb.h>
-#include <linux/smp_lock.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v0.40"
-#define DRIVER_AUTHOR "Markus Demleitner <[email protected]>"
-#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
-
-#define DSB100_VENDOR 0x04b4
-#define DSB100_PRODUCT 0x1002
-
-/* Commands the device appears to understand */
-#define DSB100_TUNE 1
-#define DSB100_ONOFF 2
-
-#define TB_LEN 16
-
-/* Frequency limits in MHz -- these are European values.  For Japanese
-devices, that would be 76 and 91.  */
-#define FREQ_MIN  87.5
-#define FREQ_MAX 108.0
-#define FREQ_MUL 16000
-
-
-static int usb_dsbr100_probe(struct usb_interface *intf,
-			     const struct usb_device_id *id);
-static void usb_dsbr100_disconnect(struct usb_interface *intf);
-static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
-			     unsigned int cmd, unsigned long arg);
-static int usb_dsbr100_open(struct inode *inode, struct file *file);
-static int usb_dsbr100_close(struct inode *inode, struct file *file);
-
-static int radio_nr = -1;
-module_param(radio_nr, int, 0);
-
-/* Data for one (physical) device */
-typedef struct {
-	struct usb_device *usbdev;
-	struct video_device *videodev;
-	unsigned char transfer_buffer[TB_LEN];
-	int curfreq;
-	int stereo;
-	int users;
-	int removed;
-} dsbr100_device;
-
-
-/* File system interface */
-static struct file_operations usb_dsbr100_fops = {
-	.owner =	THIS_MODULE,
-	.open =		usb_dsbr100_open,
-	.release =     	usb_dsbr100_close,
-	.ioctl =        usb_dsbr100_ioctl,
-	.compat_ioctl = v4l_compat_ioctl32,
-	.llseek =       no_llseek,
-};
-
-/* V4L interface */
-static struct video_device dsbr100_videodev_template=
-{
-	.owner =	THIS_MODULE,
-	.name =		"D-Link DSB-R 100",
-	.type =		VID_TYPE_TUNER,
-	.hardware =	VID_HARDWARE_AZTECH,
-	.fops =         &usb_dsbr100_fops,
-	.release = video_device_release,
-};
-
-static struct usb_device_id usb_dsbr100_device_table [] = {
-	{ USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
-	{ }						/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
-
-/* USB subsystem interface */
-static struct usb_driver usb_dsbr100_driver = {
-	.name =		"dsbr100",
-	.probe =	usb_dsbr100_probe,
-	.disconnect =	usb_dsbr100_disconnect,
-	.id_table =	usb_dsbr100_device_table,
-};
-
-/* Low-level device interface begins here */
-
-/* switch on radio */
-static int dsbr100_start(dsbr100_device *radio)
-{
-	if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-			USB_REQ_GET_STATUS,
-			USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-			0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
-	usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-			DSB100_ONOFF,
-			USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-			0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
-		return -1;
-	return (radio->transfer_buffer)[0];
-}
-
-
-/* switch off radio */
-static int dsbr100_stop(dsbr100_device *radio)
-{
-	if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-			USB_REQ_GET_STATUS,
-			USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-			0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
-	usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-			DSB100_ONOFF,
-			USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-			0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
-		return -1;
-	return (radio->transfer_buffer)[0];
-}
-
-/* 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)
-{
-	freq = (freq/16*80)/1000+856;
-	if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-			DSB100_TUNE,
-			USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-			(freq>>8)&0x00ff, freq&0xff,
-			radio->transfer_buffer, 8, 300)<0 ||
-	   usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-			USB_REQ_GET_STATUS,
-			USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-			0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
-	usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-			USB_REQ_GET_STATUS,
-			USB_TYPE_VENDOR | USB_RECIP_DEVICE |  USB_DIR_IN,
-			0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
-		radio->stereo = -1;
-		return -1;
-	}
-	radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
-	return (radio->transfer_buffer)[0];
-}
-
-/* return the device status.  This is, in effect, just whether it
-sees a stereo signal or not.  Pity. */
-static void dsbr100_getstat(dsbr100_device *radio)
-{
-	if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-		USB_REQ_GET_STATUS,
-		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-		0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
-		radio->stereo = -1;
-	else
-		radio->stereo = ! (radio->transfer_buffer[0]&0x01);
-}
-
-
-/* USB subsystem interface begins here */
-
-/* check if the device is present and register with v4l and
-usb if it is */
-static int usb_dsbr100_probe(struct usb_interface *intf,
-			 const struct usb_device_id *id)
-{
-	dsbr100_device *radio;
-
-	if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL)))
-		return -ENOMEM;
-	if (!(radio->videodev = video_device_alloc())) {
-		kfree(radio);
-		return -ENOMEM;
-	}
-	memcpy(radio->videodev, &dsbr100_videodev_template,
-		sizeof(dsbr100_videodev_template));
-	radio->removed = 0;
-	radio->users = 0;
-	radio->usbdev = interface_to_usbdev(intf);
-	radio->curfreq = FREQ_MIN*FREQ_MUL;
-	video_set_drvdata(radio->videodev, radio);
-	if (video_register_device(radio->videodev, VFL_TYPE_RADIO,
-		radio_nr)) {
-		warn("Could not register video device");
-		video_device_release(radio->videodev);
-		kfree(radio);
-		return -EIO;
-	}
-	usb_set_intfdata(intf, radio);
-	return 0;
-}
-
-/* handle unplugging of the device, release data structures
-if nothing keeps us from doing it.  If something is still
-keeping us busy, the release callback of v4l will take care
-of releasing it.  stv680.c does not relase its private
-data, so I don't do this here either.  Checking out the
-code I'd expect I better did that, but if there's a memory
-leak here it's tiny (~50 bytes per disconnect) */
-static void usb_dsbr100_disconnect(struct usb_interface *intf)
-{
-	dsbr100_device *radio = usb_get_intfdata(intf);
-
-	usb_set_intfdata (intf, NULL);
-	if (radio) {
-		video_unregister_device(radio->videodev);
-		radio->videodev = NULL;
-		if (radio->users) {
-			kfree(radio);
-		} else {
-			radio->removed = 1;
-		}
-	}
-}
-
-
-/* Video for Linux interface */
-
-static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file,
-				unsigned int cmd, void *arg)
-{
-	dsbr100_device *radio=video_get_drvdata(video_devdata(file));
-
-	if (!radio)
-		return -EIO;
-
-	switch(cmd) {
-		case VIDIOCGCAP: {
-			struct video_capability *v = arg;
-
-			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;
-		}
-		case VIDIOCGTUNER: {
-			struct video_tuner *v = arg;
-
-			dsbr100_getstat(radio);
-			if(v->tuner)	/* Only 1 tuner */
-				return -EINVAL;
-			v->rangelow = FREQ_MIN*FREQ_MUL;
-			v->rangehigh = FREQ_MAX*FREQ_MUL;
-			v->flags = VIDEO_TUNER_LOW;
-			v->mode = VIDEO_MODE_AUTO;
-			v->signal = radio->stereo*0x7000;
-				/* Don't know how to get signal strength */
-			v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo;
-			strcpy(v->name, "DSB R-100");
-			return 0;
-		}
-		case VIDIOCSTUNER: {
-			struct video_tuner *v = arg;
-
-			if(v->tuner!=0)
-				return -EINVAL;
-			/* Only 1 tuner so no setting needed ! */
-			return 0;
-		}
-		case VIDIOCGFREQ: {
-			int *freq = arg;
-
-			if (radio->curfreq==-1)
-				return -EINVAL;
-			*freq = radio->curfreq;
-			return 0;
-		}
-		case VIDIOCSFREQ: {
-			int *freq = arg;
-
-			radio->curfreq = *freq;
-			if (dsbr100_setfreq(radio, radio->curfreq)==-1)
-				warn("Set frequency failed");
-			return 0;
-		}
-		case VIDIOCGAUDIO: {
-			struct video_audio *v = arg;
-
-			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;
-		}
-		case VIDIOCSAUDIO: {
-			struct video_audio *v = arg;
-
-			if (v->audio)
-				return -EINVAL;
-			if (v->flags&VIDEO_AUDIO_MUTE) {
-				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;
-		}
-		default:
-			return -ENOIOCTLCMD;
-	}
-}
-
-static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
-			     unsigned int cmd, unsigned long arg)
-{
-	return video_usercopy(inode, file, cmd, arg, usb_dsbr100_do_ioctl);
-}
-
-static int usb_dsbr100_open(struct inode *inode, struct file *file)
-{
-	dsbr100_device *radio=video_get_drvdata(video_devdata(file));
-
-	radio->users = 1;
-	if (dsbr100_start(radio)<0) {
-		warn("Radio did not start up properly");
-		radio->users = 0;
-		return -EIO;
-	}
-	dsbr100_setfreq(radio, radio->curfreq);
-	return 0;
-}
-
-static int usb_dsbr100_close(struct inode *inode, struct file *file)
-{
-	dsbr100_device *radio=video_get_drvdata(video_devdata(file));
-
-	if (!radio)
-		return -ENODEV;
-	radio->users = 0;
-	if (radio->removed) {
-		kfree(radio);
-	}
-	return 0;
-}
-
-static int __init dsbr100_init(void)
-{
-	int retval = usb_register(&usb_dsbr100_driver);
-	info(DRIVER_VERSION ":" DRIVER_DESC);
-	return retval;
-}
-
-static void __exit dsbr100_exit(void)
-{
-	usb_deregister(&usb_dsbr100_driver);
-}
-
-module_init (dsbr100_init);
-module_exit (dsbr100_exit);
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux