diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2012-01-16 03:24:08 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-02-14 14:10:41 -0500 |
commit | 8bd7ef5ae615cce5cde2e8b40445cfe4a20c3c03 (patch) | |
tree | 445468a6367fdf790980befb6293bc93cc47267d /drivers | |
parent | f8c085244ef6a88c38db3ee49bda0ff4249edf34 (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/Kconfig | 8 | ||||
-rw-r--r-- | drivers/media/radio/radio-rtrack2.c | 332 |
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 | |||
233 | config RADIO_RTRACK2 | 233 | config 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 | ||
22 | MODULE_AUTHOR("Ben Pfaff"); | 24 | MODULE_AUTHOR("Ben Pfaff"); |
23 | MODULE_DESCRIPTION("A driver for the RadioTrack II radio card."); | 25 | MODULE_DESCRIPTION("A driver for the RadioTrack II radio card."); |
24 | MODULE_LICENSE("GPL"); | 26 | MODULE_LICENSE("GPL"); |
25 | MODULE_VERSION("0.0.3"); | 27 | MODULE_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 | ||
31 | static int io = CONFIG_RADIO_RTRACK2_PORT; | 33 | #define RTRACK2_MAX 2 |
32 | static int radio_nr = -1; | ||
33 | |||
34 | module_param(io, int, 0); | ||
35 | MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)"); | ||
36 | module_param(radio_nr, int, 0); | ||
37 | |||
38 | struct 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 | ||
48 | static struct rtrack2 rtrack2_card; | 35 | static int io[RTRACK2_MAX] = { [0] = CONFIG_RADIO_RTRACK2_PORT, |
36 | [1 ... (RTRACK2_MAX - 1)] = -1 }; | ||
37 | static int radio_nr[RTRACK2_MAX] = { [0 ... (RTRACK2_MAX - 1)] = -1 }; | ||
49 | 38 | ||
39 | module_param_array(io, int, NULL, 0444); | ||
40 | MODULE_PARM_DESC(io, "I/O addresses of the RadioTrack card (0x20f or 0x30f)"); | ||
41 | module_param_array(radio_nr, int, NULL, 0444); | ||
42 | MODULE_PARM_DESC(radio_nr, "Radio device numbers"); | ||
50 | 43 | ||
51 | /* local things */ | 44 | static struct radio_isa_card *rtrack2_alloc(void) |
52 | |||
53 | static 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 | |||
63 | static 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 | ||
73 | static void zero(struct rtrack2 *dev) | 49 | static 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 | ||
80 | static void one(struct rtrack2 *dev) | 56 | static 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 | ||
87 | static int rt_setfreq(struct rtrack2 *dev, unsigned long freq) | 63 | static 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 | |||
116 | static 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 | ||
126 | static 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 | |||
132 | static 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 | |||
143 | static 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 | ||
162 | static int vidioc_s_frequency(struct file *file, void *priv, | 88 | static 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 | ||
173 | static int vidioc_g_frequency(struct file *file, void *priv, | 94 | static 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 | ||
185 | static int vidioc_queryctrl(struct file *file, void *priv, | 100 | static 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 | |||
197 | static 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 | |||
216 | static 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 | |||
238 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
239 | { | ||
240 | *i = 0; | ||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
245 | { | ||
246 | return i ? -EINVAL : 0; | ||
247 | } | ||
248 | |||
249 | static 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 | |||
258 | static int vidioc_s_audio(struct file *file, void *priv, | ||
259 | struct v4l2_audio *a) | ||
260 | { | ||
261 | return a->index ? -EINVAL : 0; | ||
262 | } | ||
263 | |||
264 | static const struct v4l2_file_operations rtrack2_fops = { | ||
265 | .owner = THIS_MODULE, | ||
266 | .unlocked_ioctl = video_ioctl2, | ||
267 | }; | 105 | }; |
268 | 106 | ||
269 | static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = { | 107 | static const int rtrack2_ioports[] = { 0x20f, 0x30f }; |
270 | .vidioc_querycap = vidioc_querycap, | 108 | |
271 | .vidioc_g_tuner = vidioc_g_tuner, | 109 | static 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 | ||
284 | static int __init rtrack2_init(void) | 128 | static 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 | ||
331 | static void __exit rtrack2_exit(void) | 133 | static 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 | ||
340 | module_init(rtrack2_init); | 138 | module_init(rtrack2_init); |