aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2012-01-16 03:24:08 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-02-14 14:10:41 -0500
commit8bd7ef5ae615cce5cde2e8b40445cfe4a20c3c03 (patch)
tree445468a6367fdf790980befb6293bc93cc47267d /drivers
parentf8c085244ef6a88c38db3ee49bda0ff4249edf34 (diff)
[media] radio-rtrack2: Convert to radio-isa
Tested with v4l2-compliance, but not with actual hardware. Contact the linux-media mailinglist if you have this card! Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/radio/Kconfig8
-rw-r--r--drivers/media/radio/radio-rtrack2.c332
2 files changed, 69 insertions, 271 deletions
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 06a8c7a53556..f76cbbc9a784 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -233,14 +233,14 @@ config RADIO_RTRACK_PORT
233config RADIO_RTRACK2 233config RADIO_RTRACK2
234 tristate "AIMSlab RadioTrack II support" 234 tristate "AIMSlab RadioTrack II support"
235 depends on ISA && VIDEO_V4L2 235 depends on ISA && VIDEO_V4L2
236 select RADIO_ISA
236 ---help--- 237 ---help---
237 Choose Y here if you have this FM radio card, and then fill in the 238 Choose Y here if you have this FM radio card, and then fill in the
238 port address below. 239 port address below.
239 240
240 In order to control your radio card, you will need to use programs 241 Note: this driver hasn't been tested since a long time due to lack
241 that are compatible with the Video For Linux API. Information on 242 of hardware. If you have this hardware, then please contact the
242 this API and pointers to "v4l" programs may be found at 243 linux-media mailinglist.
243 <file:Documentation/video4linux/API.html>.
244 244
245 To compile this driver as a module, choose M here: the 245 To compile this driver as a module, choose M here: the
246 module will be called radio-rtrack2. 246 module will be called radio-rtrack2.
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index 3628be617ee9..b275c5d0fe9a 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -1,11 +1,12 @@
1/* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff 1/*
2 * RadioTrack II driver
3 * Copyright 1998 Ben Pfaff
2 * 4 *
3 * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood 5 * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
4 * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk> 6 * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
5 * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org> 7 * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
6 * 8 *
7 * TODO: Allow for more than one of these foolish entities :-) 9 * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
8 *
9 * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> 10 * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
10 */ 11 */
11 12
@@ -18,323 +19,120 @@
18#include <linux/io.h> /* outb, outb_p */ 19#include <linux/io.h> /* outb, outb_p */
19#include <media/v4l2-device.h> 20#include <media/v4l2-device.h>
20#include <media/v4l2-ioctl.h> 21#include <media/v4l2-ioctl.h>
22#include "radio-isa.h"
21 23
22MODULE_AUTHOR("Ben Pfaff"); 24MODULE_AUTHOR("Ben Pfaff");
23MODULE_DESCRIPTION("A driver for the RadioTrack II radio card."); 25MODULE_DESCRIPTION("A driver for the RadioTrack II radio card.");
24MODULE_LICENSE("GPL"); 26MODULE_LICENSE("GPL");
25MODULE_VERSION("0.0.3"); 27MODULE_VERSION("0.1.99");
26 28
27#ifndef CONFIG_RADIO_RTRACK2_PORT 29#ifndef CONFIG_RADIO_RTRACK2_PORT
28#define CONFIG_RADIO_RTRACK2_PORT -1 30#define CONFIG_RADIO_RTRACK2_PORT -1
29#endif 31#endif
30 32
31static int io = CONFIG_RADIO_RTRACK2_PORT; 33#define RTRACK2_MAX 2
32static int radio_nr = -1;
33
34module_param(io, int, 0);
35MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)");
36module_param(radio_nr, int, 0);
37
38struct rtrack2
39{
40 struct v4l2_device v4l2_dev;
41 struct video_device vdev;
42 int io;
43 unsigned long curfreq;
44 int muted;
45 struct mutex lock;
46};
47 34
48static struct rtrack2 rtrack2_card; 35static int io[RTRACK2_MAX] = { [0] = CONFIG_RADIO_RTRACK2_PORT,
36 [1 ... (RTRACK2_MAX - 1)] = -1 };
37static int radio_nr[RTRACK2_MAX] = { [0 ... (RTRACK2_MAX - 1)] = -1 };
49 38
39module_param_array(io, int, NULL, 0444);
40MODULE_PARM_DESC(io, "I/O addresses of the RadioTrack card (0x20f or 0x30f)");
41module_param_array(radio_nr, int, NULL, 0444);
42MODULE_PARM_DESC(radio_nr, "Radio device numbers");
50 43
51/* local things */ 44static struct radio_isa_card *rtrack2_alloc(void)
52
53static void rt_mute(struct rtrack2 *dev)
54{
55 if (dev->muted)
56 return;
57 mutex_lock(&dev->lock);
58 outb(1, dev->io);
59 mutex_unlock(&dev->lock);
60 dev->muted = 1;
61}
62
63static void rt_unmute(struct rtrack2 *dev)
64{ 45{
65 if(dev->muted == 0) 46 return kzalloc(sizeof(struct radio_isa_card), GFP_KERNEL);
66 return;
67 mutex_lock(&dev->lock);
68 outb(0, dev->io);
69 mutex_unlock(&dev->lock);
70 dev->muted = 0;
71} 47}
72 48
73static void zero(struct rtrack2 *dev) 49static void zero(struct radio_isa_card *isa)
74{ 50{
75 outb_p(1, dev->io); 51 outb_p(1, isa->io);
76 outb_p(3, dev->io); 52 outb_p(3, isa->io);
77 outb_p(1, dev->io); 53 outb_p(1, isa->io);
78} 54}
79 55
80static void one(struct rtrack2 *dev) 56static void one(struct radio_isa_card *isa)
81{ 57{
82 outb_p(5, dev->io); 58 outb_p(5, isa->io);
83 outb_p(7, dev->io); 59 outb_p(7, isa->io);
84 outb_p(5, dev->io); 60 outb_p(5, isa->io);
85} 61}
86 62
87static int rt_setfreq(struct rtrack2 *dev, unsigned long freq) 63static int rtrack2_s_frequency(struct radio_isa_card *isa, u32 freq)
88{ 64{
89 int i; 65 int i;
90 66
91 mutex_lock(&dev->lock);
92 dev->curfreq = freq;
93 freq = freq / 200 + 856; 67 freq = freq / 200 + 856;
94 68
95 outb_p(0xc8, dev->io); 69 outb_p(0xc8, isa->io);
96 outb_p(0xc9, dev->io); 70 outb_p(0xc9, isa->io);
97 outb_p(0xc9, dev->io); 71 outb_p(0xc9, isa->io);
98 72
99 for (i = 0; i < 10; i++) 73 for (i = 0; i < 10; i++)
100 zero(dev); 74 zero(isa);
101 75
102 for (i = 14; i >= 0; i--) 76 for (i = 14; i >= 0; i--)
103 if (freq & (1 << i)) 77 if (freq & (1 << i))
104 one(dev); 78 one(isa);
105 else 79 else
106 zero(dev); 80 zero(isa);
107
108 outb_p(0xc8, dev->io);
109 if (!dev->muted)
110 outb_p(0, dev->io);
111
112 mutex_unlock(&dev->lock);
113 return 0;
114}
115
116static int vidioc_querycap(struct file *file, void *priv,
117 struct v4l2_capability *v)
118{
119 strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver));
120 strlcpy(v->card, "RadioTrack II", sizeof(v->card));
121 strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
122 v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
123 return 0;
124}
125 81
126static int vidioc_s_tuner(struct file *file, void *priv, 82 outb_p(0xc8, isa->io);
127 struct v4l2_tuner *v) 83 if (!v4l2_ctrl_g_ctrl(isa->mute))
128{ 84 outb_p(0, isa->io);
129 return v->index ? -EINVAL : 0;
130}
131
132static int rt_getsigstr(struct rtrack2 *dev)
133{
134 int sig = 1;
135
136 mutex_lock(&dev->lock);
137 if (inb(dev->io) & 2) /* bit set = no signal present */
138 sig = 0;
139 mutex_unlock(&dev->lock);
140 return sig;
141}
142
143static int vidioc_g_tuner(struct file *file, void *priv,
144 struct v4l2_tuner *v)
145{
146 struct rtrack2 *rt = video_drvdata(file);
147
148 if (v->index > 0)
149 return -EINVAL;
150
151 strlcpy(v->name, "FM", sizeof(v->name));
152 v->type = V4L2_TUNER_RADIO;
153 v->rangelow = 88 * 16000;
154 v->rangehigh = 108 * 16000;
155 v->rxsubchans = V4L2_TUNER_SUB_MONO;
156 v->capability = V4L2_TUNER_CAP_LOW;
157 v->audmode = V4L2_TUNER_MODE_MONO;
158 v->signal = 0xFFFF * rt_getsigstr(rt);
159 return 0; 85 return 0;
160} 86}
161 87
162static int vidioc_s_frequency(struct file *file, void *priv, 88static u32 rtrack2_g_signal(struct radio_isa_card *isa)
163 struct v4l2_frequency *f)
164{ 89{
165 struct rtrack2 *rt = video_drvdata(file); 90 /* bit set = no signal present */
166 91 return (inb(isa->io) & 2) ? 0 : 0xffff;
167 if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
168 return -EINVAL;
169 rt_setfreq(rt, f->frequency);
170 return 0;
171} 92}
172 93
173static int vidioc_g_frequency(struct file *file, void *priv, 94static int rtrack2_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
174 struct v4l2_frequency *f)
175{ 95{
176 struct rtrack2 *rt = video_drvdata(file); 96 outb(mute, isa->io);
177
178 if (f->tuner != 0)
179 return -EINVAL;
180 f->type = V4L2_TUNER_RADIO;
181 f->frequency = rt->curfreq;
182 return 0; 97 return 0;
183} 98}
184 99
185static int vidioc_queryctrl(struct file *file, void *priv, 100static const struct radio_isa_ops rtrack2_ops = {
186 struct v4l2_queryctrl *qc) 101 .alloc = rtrack2_alloc,
187{ 102 .s_mute_volume = rtrack2_s_mute_volume,
188 switch (qc->id) { 103 .s_frequency = rtrack2_s_frequency,
189 case V4L2_CID_AUDIO_MUTE: 104 .g_signal = rtrack2_g_signal,
190 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
191 case V4L2_CID_AUDIO_VOLUME:
192 return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535);
193 }
194 return -EINVAL;
195}
196
197static int vidioc_g_ctrl(struct file *file, void *priv,
198 struct v4l2_control *ctrl)
199{
200 struct rtrack2 *rt = video_drvdata(file);
201
202 switch (ctrl->id) {
203 case V4L2_CID_AUDIO_MUTE:
204 ctrl->value = rt->muted;
205 return 0;
206 case V4L2_CID_AUDIO_VOLUME:
207 if (rt->muted)
208 ctrl->value = 0;
209 else
210 ctrl->value = 65535;
211 return 0;
212 }
213 return -EINVAL;
214}
215
216static int vidioc_s_ctrl(struct file *file, void *priv,
217 struct v4l2_control *ctrl)
218{
219 struct rtrack2 *rt = video_drvdata(file);
220
221 switch (ctrl->id) {
222 case V4L2_CID_AUDIO_MUTE:
223 if (ctrl->value)
224 rt_mute(rt);
225 else
226 rt_unmute(rt);
227 return 0;
228 case V4L2_CID_AUDIO_VOLUME:
229 if (ctrl->value)
230 rt_unmute(rt);
231 else
232 rt_mute(rt);
233 return 0;
234 }
235 return -EINVAL;
236}
237
238static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
239{
240 *i = 0;
241 return 0;
242}
243
244static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
245{
246 return i ? -EINVAL : 0;
247}
248
249static int vidioc_g_audio(struct file *file, void *priv,
250 struct v4l2_audio *a)
251{
252 a->index = 0;
253 strlcpy(a->name, "Radio", sizeof(a->name));
254 a->capability = V4L2_AUDCAP_STEREO;
255 return 0;
256}
257
258static int vidioc_s_audio(struct file *file, void *priv,
259 struct v4l2_audio *a)
260{
261 return a->index ? -EINVAL : 0;
262}
263
264static const struct v4l2_file_operations rtrack2_fops = {
265 .owner = THIS_MODULE,
266 .unlocked_ioctl = video_ioctl2,
267}; 105};
268 106
269static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = { 107static const int rtrack2_ioports[] = { 0x20f, 0x30f };
270 .vidioc_querycap = vidioc_querycap, 108
271 .vidioc_g_tuner = vidioc_g_tuner, 109static struct radio_isa_driver rtrack2_driver = {
272 .vidioc_s_tuner = vidioc_s_tuner, 110 .driver = {
273 .vidioc_g_frequency = vidioc_g_frequency, 111 .match = radio_isa_match,
274 .vidioc_s_frequency = vidioc_s_frequency, 112 .probe = radio_isa_probe,
275 .vidioc_queryctrl = vidioc_queryctrl, 113 .remove = radio_isa_remove,
276 .vidioc_g_ctrl = vidioc_g_ctrl, 114 .driver = {
277 .vidioc_s_ctrl = vidioc_s_ctrl, 115 .name = "radio-rtrack2",
278 .vidioc_g_audio = vidioc_g_audio, 116 },
279 .vidioc_s_audio = vidioc_s_audio, 117 },
280 .vidioc_g_input = vidioc_g_input, 118 .io_params = io,
281 .vidioc_s_input = vidioc_s_input, 119 .radio_nr_params = radio_nr,
120 .io_ports = rtrack2_ioports,
121 .num_of_io_ports = ARRAY_SIZE(rtrack2_ioports),
122 .region_size = 4,
123 .card = "AIMSlab RadioTrack II",
124 .ops = &rtrack2_ops,
125 .has_stereo = true,
282}; 126};
283 127
284static int __init rtrack2_init(void) 128static int __init rtrack2_init(void)
285{ 129{
286 struct rtrack2 *dev = &rtrack2_card; 130 return isa_register_driver(&rtrack2_driver.driver, RTRACK2_MAX);
287 struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
288 int res;
289
290 strlcpy(v4l2_dev->name, "rtrack2", sizeof(v4l2_dev->name));
291 dev->io = io;
292 if (dev->io == -1) {
293 v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or io=0x30c\n");
294 return -EINVAL;
295 }
296 if (!request_region(dev->io, 4, "rtrack2")) {
297 v4l2_err(v4l2_dev, "port 0x%x already in use\n", dev->io);
298 return -EBUSY;
299 }
300
301 res = v4l2_device_register(NULL, v4l2_dev);
302 if (res < 0) {
303 release_region(dev->io, 4);
304 v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
305 return res;
306 }
307
308 strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
309 dev->vdev.v4l2_dev = v4l2_dev;
310 dev->vdev.fops = &rtrack2_fops;
311 dev->vdev.ioctl_ops = &rtrack2_ioctl_ops;
312 dev->vdev.release = video_device_release_empty;
313 video_set_drvdata(&dev->vdev, dev);
314
315 /* mute card - prevents noisy bootups */
316 outb(1, dev->io);
317 dev->muted = 1;
318
319 mutex_init(&dev->lock);
320 if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
321 v4l2_device_unregister(v4l2_dev);
322 release_region(dev->io, 4);
323 return -EINVAL;
324 }
325
326 v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n");
327
328 return 0;
329} 131}
330 132
331static void __exit rtrack2_exit(void) 133static void __exit rtrack2_exit(void)
332{ 134{
333 struct rtrack2 *dev = &rtrack2_card; 135 isa_unregister_driver(&rtrack2_driver.driver);
334
335 video_unregister_device(&dev->vdev);
336 v4l2_device_unregister(&dev->v4l2_dev);
337 release_region(dev->io, 4);
338} 136}
339 137
340module_init(rtrack2_init); 138module_init(rtrack2_init);