aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2009-03-06 11:52:34 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-03-30 11:43:13 -0400
commitc41269fd9275cce88b90af644969c6a5e2067657 (patch)
treebdf76273785e8fec8dd3845cb1e5ac138e2e6dc2
parent922c78e9f6900ade073da1a92d43c56d77cf790f (diff)
V4L/DVB (10888): radio-sf16fmi: convert to v4l2_device.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/radio/radio-sf16fmi.c284
1 files changed, 135 insertions, 149 deletions
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index d358e48c2422..4982d0cefb4f 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -22,113 +22,110 @@
22#include <linux/init.h> /* Initdata */ 22#include <linux/init.h> /* Initdata */
23#include <linux/ioport.h> /* request_region */ 23#include <linux/ioport.h> /* request_region */
24#include <linux/delay.h> /* udelay */ 24#include <linux/delay.h> /* udelay */
25#include <linux/videodev2.h> /* kernel radio structs */
26#include <media/v4l2-common.h>
27#include <media/v4l2-ioctl.h>
28#include <linux/isapnp.h> 25#include <linux/isapnp.h>
29#include <asm/io.h> /* outb, outb_p */
30#include <asm/uaccess.h> /* copy to/from user */
31#include <linux/mutex.h> 26#include <linux/mutex.h>
27#include <linux/videodev2.h> /* kernel radio structs */
28#include <linux/io.h> /* outb, outb_p */
29#include <linux/uaccess.h> /* copy to/from user */
30#include <media/v4l2-device.h>
31#include <media/v4l2-ioctl.h>
32 32
33#define RADIO_VERSION KERNEL_VERSION(0,0,2) 33MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
34MODULE_DESCRIPTION("A driver for the SF16MI radio.");
35MODULE_LICENSE("GPL");
34 36
35static struct v4l2_queryctrl radio_qctrl[] = { 37static int io = -1;
36 { 38static int radio_nr = -1;
37 .id = V4L2_CID_AUDIO_MUTE, 39
38 .name = "Mute", 40module_param(io, int, 0);
39 .minimum = 0, 41MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)");
40 .maximum = 1, 42module_param(radio_nr, int, 0);
41 .default_value = 1, 43
42 .type = V4L2_CTRL_TYPE_BOOLEAN, 44#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
43 }
44};
45 45
46struct fmi_device 46struct fmi
47{ 47{
48 unsigned long in_use; 48 struct v4l2_device v4l2_dev;
49 int port; 49 struct video_device vdev;
50 int io;
50 int curvol; /* 1 or 0 */ 51 int curvol; /* 1 or 0 */
51 unsigned long curfreq; /* freq in kHz */ 52 unsigned long curfreq; /* freq in kHz */
52 __u32 flags; 53 __u32 flags;
54 struct mutex lock;
53}; 55};
54 56
55static int io = -1; 57static struct fmi fmi_card;
56static int radio_nr = -1; 58static struct pnp_dev *dev;
57static struct pnp_dev *dev = NULL;
58static struct mutex lock;
59 59
60/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */ 60/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
61/* It is only useful to give freq in intervall of 800 (=0.05Mhz), 61/* It is only useful to give freq in intervall of 800 (=0.05Mhz),
62 * other bits will be truncated, e.g 92.7400016 -> 92.7, but 62 * other bits will be truncated, e.g 92.7400016 -> 92.7, but
63 * 92.7400017 -> 92.75 63 * 92.7400017 -> 92.75
64 */ 64 */
65#define RSF16_ENCODE(x) ((x)/800+214) 65#define RSF16_ENCODE(x) ((x) / 800 + 214)
66#define RSF16_MINFREQ 87*16000 66#define RSF16_MINFREQ (87 * 16000)
67#define RSF16_MAXFREQ 108*16000 67#define RSF16_MAXFREQ (108 * 16000)
68 68
69static void outbits(int bits, unsigned int data, int port) 69static void outbits(int bits, unsigned int data, int io)
70{ 70{
71 while(bits--) { 71 while (bits--) {
72 if(data & 1) { 72 if (data & 1) {
73 outb(5, port); 73 outb(5, io);
74 udelay(6); 74 udelay(6);
75 outb(7, port); 75 outb(7, io);
76 udelay(6); 76 udelay(6);
77 } else { 77 } else {
78 outb(1, port); 78 outb(1, io);
79 udelay(6); 79 udelay(6);
80 outb(3, port); 80 outb(3, io);
81 udelay(6); 81 udelay(6);
82 } 82 }
83 data>>=1; 83 data >>= 1;
84 } 84 }
85} 85}
86 86
87static inline void fmi_mute(int port) 87static inline void fmi_mute(struct fmi *fmi)
88{ 88{
89 mutex_lock(&lock); 89 mutex_lock(&fmi->lock);
90 outb(0x00, port); 90 outb(0x00, fmi->io);
91 mutex_unlock(&lock); 91 mutex_unlock(&fmi->lock);
92} 92}
93 93
94static inline void fmi_unmute(int port) 94static inline void fmi_unmute(struct fmi *fmi)
95{ 95{
96 mutex_lock(&lock); 96 mutex_lock(&fmi->lock);
97 outb(0x08, port); 97 outb(0x08, fmi->io);
98 mutex_unlock(&lock); 98 mutex_unlock(&fmi->lock);
99} 99}
100 100
101static inline int fmi_setfreq(struct fmi_device *dev) 101static inline int fmi_setfreq(struct fmi *fmi, unsigned long freq)
102{ 102{
103 int myport = dev->port; 103 mutex_lock(&fmi->lock);
104 unsigned long freq = dev->curfreq; 104 fmi->curfreq = freq;
105 105
106 mutex_lock(&lock); 106 outbits(16, RSF16_ENCODE(freq), fmi->io);
107 107 outbits(8, 0xC0, fmi->io);
108 outbits(16, RSF16_ENCODE(freq), myport);
109 outbits(8, 0xC0, myport);
110 msleep(143); /* was schedule_timeout(HZ/7) */ 108 msleep(143); /* was schedule_timeout(HZ/7) */
111 mutex_unlock(&lock); 109 mutex_unlock(&fmi->lock);
112 if (dev->curvol) fmi_unmute(myport); 110 if (fmi->curvol)
111 fmi_unmute(fmi);
113 return 0; 112 return 0;
114} 113}
115 114
116static inline int fmi_getsigstr(struct fmi_device *dev) 115static inline int fmi_getsigstr(struct fmi *fmi)
117{ 116{
118 int val; 117 int val;
119 int res; 118 int res;
120 int myport = dev->port;
121
122 119
123 mutex_lock(&lock); 120 mutex_lock(&fmi->lock);
124 val = dev->curvol ? 0x08 : 0x00; /* unmute/mute */ 121 val = fmi->curvol ? 0x08 : 0x00; /* unmute/mute */
125 outb(val, myport); 122 outb(val, fmi->io);
126 outb(val | 0x10, myport); 123 outb(val | 0x10, fmi->io);
127 msleep(143); /* was schedule_timeout(HZ/7) */ 124 msleep(143); /* was schedule_timeout(HZ/7) */
128 res = (int)inb(myport+1); 125 res = (int)inb(fmi->io + 1);
129 outb(val, myport); 126 outb(val, fmi->io);
130 127
131 mutex_unlock(&lock); 128 mutex_unlock(&fmi->lock);
132 return (res & 2) ? 0 : 0xFFFF; 129 return (res & 2) ? 0 : 0xFFFF;
133} 130}
134 131
@@ -137,9 +134,9 @@ static int vidioc_querycap(struct file *file, void *priv,
137{ 134{
138 strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver)); 135 strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver));
139 strlcpy(v->card, "SF16-FMx radio", sizeof(v->card)); 136 strlcpy(v->card, "SF16-FMx radio", sizeof(v->card));
140 sprintf(v->bus_info, "ISA"); 137 strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
141 v->version = RADIO_VERSION; 138 v->version = RADIO_VERSION;
142 v->capabilities = V4L2_CAP_TUNER; 139 v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
143 return 0; 140 return 0;
144} 141}
145 142
@@ -147,18 +144,18 @@ static int vidioc_g_tuner(struct file *file, void *priv,
147 struct v4l2_tuner *v) 144 struct v4l2_tuner *v)
148{ 145{
149 int mult; 146 int mult;
150 struct fmi_device *fmi = video_drvdata(file); 147 struct fmi *fmi = video_drvdata(file);
151 148
152 if (v->index > 0) 149 if (v->index > 0)
153 return -EINVAL; 150 return -EINVAL;
154 151
155 strcpy(v->name, "FM"); 152 strlcpy(v->name, "FM", sizeof(v->name));
156 v->type = V4L2_TUNER_RADIO; 153 v->type = V4L2_TUNER_RADIO;
157 mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000; 154 mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
158 v->rangelow = RSF16_MINFREQ/mult; 155 v->rangelow = RSF16_MINFREQ / mult;
159 v->rangehigh = RSF16_MAXFREQ/mult; 156 v->rangehigh = RSF16_MAXFREQ / mult;
160 v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO; 157 v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
161 v->capability = fmi->flags&V4L2_TUNER_CAP_LOW; 158 v->capability = fmi->flags & V4L2_TUNER_CAP_LOW;
162 v->audmode = V4L2_TUNER_MODE_STEREO; 159 v->audmode = V4L2_TUNER_MODE_STEREO;
163 v->signal = fmi_getsigstr(fmi); 160 v->signal = fmi_getsigstr(fmi);
164 return 0; 161 return 0;
@@ -167,32 +164,29 @@ static int vidioc_g_tuner(struct file *file, void *priv,
167static int vidioc_s_tuner(struct file *file, void *priv, 164static int vidioc_s_tuner(struct file *file, void *priv,
168 struct v4l2_tuner *v) 165 struct v4l2_tuner *v)
169{ 166{
170 if (v->index > 0) 167 return v->index ? -EINVAL : 0;
171 return -EINVAL;
172 return 0;
173} 168}
174 169
175static int vidioc_s_frequency(struct file *file, void *priv, 170static int vidioc_s_frequency(struct file *file, void *priv,
176 struct v4l2_frequency *f) 171 struct v4l2_frequency *f)
177{ 172{
178 struct fmi_device *fmi = video_drvdata(file); 173 struct fmi *fmi = video_drvdata(file);
179 174
180 if (!(fmi->flags & V4L2_TUNER_CAP_LOW)) 175 if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
181 f->frequency *= 1000; 176 f->frequency *= 1000;
182 if (f->frequency < RSF16_MINFREQ || 177 if (f->frequency < RSF16_MINFREQ ||
183 f->frequency > RSF16_MAXFREQ ) 178 f->frequency > RSF16_MAXFREQ)
184 return -EINVAL; 179 return -EINVAL;
185 /*rounding in steps of 800 to match th freq 180 /* rounding in steps of 800 to match the freq
186 that will be used */ 181 that will be used */
187 fmi->curfreq = (f->frequency/800)*800; 182 fmi_setfreq(fmi, (f->frequency / 800) * 800);
188 fmi_setfreq(fmi);
189 return 0; 183 return 0;
190} 184}
191 185
192static int vidioc_g_frequency(struct file *file, void *priv, 186static int vidioc_g_frequency(struct file *file, void *priv,
193 struct v4l2_frequency *f) 187 struct v4l2_frequency *f)
194{ 188{
195 struct fmi_device *fmi = video_drvdata(file); 189 struct fmi *fmi = video_drvdata(file);
196 190
197 f->type = V4L2_TUNER_RADIO; 191 f->type = V4L2_TUNER_RADIO;
198 f->frequency = fmi->curfreq; 192 f->frequency = fmi->curfreq;
@@ -204,14 +198,9 @@ static int vidioc_g_frequency(struct file *file, void *priv,
204static int vidioc_queryctrl(struct file *file, void *priv, 198static int vidioc_queryctrl(struct file *file, void *priv,
205 struct v4l2_queryctrl *qc) 199 struct v4l2_queryctrl *qc)
206{ 200{
207 int i; 201 switch (qc->id) {
208 202 case V4L2_CID_AUDIO_MUTE:
209 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { 203 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
210 if (qc->id && qc->id == radio_qctrl[i].id) {
211 memcpy(qc, &(radio_qctrl[i]),
212 sizeof(*qc));
213 return 0;
214 }
215 } 204 }
216 return -EINVAL; 205 return -EINVAL;
217} 206}
@@ -219,7 +208,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
219static int vidioc_g_ctrl(struct file *file, void *priv, 208static int vidioc_g_ctrl(struct file *file, void *priv,
220 struct v4l2_control *ctrl) 209 struct v4l2_control *ctrl)
221{ 210{
222 struct fmi_device *fmi = video_drvdata(file); 211 struct fmi *fmi = video_drvdata(file);
223 212
224 switch (ctrl->id) { 213 switch (ctrl->id) {
225 case V4L2_CID_AUDIO_MUTE: 214 case V4L2_CID_AUDIO_MUTE:
@@ -232,31 +221,20 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
232static int vidioc_s_ctrl(struct file *file, void *priv, 221static int vidioc_s_ctrl(struct file *file, void *priv,
233 struct v4l2_control *ctrl) 222 struct v4l2_control *ctrl)
234{ 223{
235 struct fmi_device *fmi = video_drvdata(file); 224 struct fmi *fmi = video_drvdata(file);
236 225
237 switch (ctrl->id) { 226 switch (ctrl->id) {
238 case V4L2_CID_AUDIO_MUTE: 227 case V4L2_CID_AUDIO_MUTE:
239 if (ctrl->value) 228 if (ctrl->value)
240 fmi_mute(fmi->port); 229 fmi_mute(fmi);
241 else 230 else
242 fmi_unmute(fmi->port); 231 fmi_unmute(fmi);
243 fmi->curvol = ctrl->value; 232 fmi->curvol = ctrl->value;
244 return 0; 233 return 0;
245 } 234 }
246 return -EINVAL; 235 return -EINVAL;
247} 236}
248 237
249static int vidioc_g_audio(struct file *file, void *priv,
250 struct v4l2_audio *a)
251{
252 if (a->index > 1)
253 return -EINVAL;
254
255 strcpy(a->name, "Radio");
256 a->capability = V4L2_AUDCAP_STEREO;
257 return 0;
258}
259
260static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) 238static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
261{ 239{
262 *i = 0; 240 *i = 0;
@@ -265,36 +243,38 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
265 243
266static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) 244static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
267{ 245{
268 if (i != 0) 246 return i ? -EINVAL : 0;
269 return -EINVAL;
270 return 0;
271} 247}
272 248
273static int vidioc_s_audio(struct file *file, void *priv, 249static int vidioc_g_audio(struct file *file, void *priv,
274 struct v4l2_audio *a) 250 struct v4l2_audio *a)
275{ 251{
276 if (a->index != 0) 252 a->index = 0;
277 return -EINVAL; 253 strlcpy(a->name, "Radio", sizeof(a->name));
254 a->capability = V4L2_AUDCAP_STEREO;
278 return 0; 255 return 0;
279} 256}
280 257
281static struct fmi_device fmi_unit; 258static int vidioc_s_audio(struct file *file, void *priv,
259 struct v4l2_audio *a)
260{
261 return a->index ? -EINVAL : 0;
262}
282 263
283static int fmi_exclusive_open(struct file *file) 264static int fmi_open(struct file *file)
284{ 265{
285 return test_and_set_bit(0, &fmi_unit.in_use) ? -EBUSY : 0; 266 return 0;
286} 267}
287 268
288static int fmi_exclusive_release(struct file *file) 269static int fmi_release(struct file *file)
289{ 270{
290 clear_bit(0, &fmi_unit.in_use);
291 return 0; 271 return 0;
292} 272}
293 273
294static const struct v4l2_file_operations fmi_fops = { 274static const struct v4l2_file_operations fmi_fops = {
295 .owner = THIS_MODULE, 275 .owner = THIS_MODULE,
296 .open = fmi_exclusive_open, 276 .open = fmi_open,
297 .release = fmi_exclusive_release, 277 .release = fmi_release,
298 .ioctl = video_ioctl2, 278 .ioctl = video_ioctl2,
299}; 279};
300 280
@@ -313,13 +293,6 @@ static const struct v4l2_ioctl_ops fmi_ioctl_ops = {
313 .vidioc_s_ctrl = vidioc_s_ctrl, 293 .vidioc_s_ctrl = vidioc_s_ctrl,
314}; 294};
315 295
316static struct video_device fmi_radio = {
317 .name = "SF16FMx radio",
318 .fops = &fmi_fops,
319 .ioctl_ops = &fmi_ioctl_ops,
320 .release = video_device_release_empty,
321};
322
323/* ladis: this is my card. does any other types exist? */ 296/* ladis: this is my card. does any other types exist? */
324static struct isapnp_device_id id_table[] __devinitdata = { 297static struct isapnp_device_id id_table[] __devinitdata = {
325 { ISAPNP_ANY_ID, ISAPNP_ANY_ID, 298 { ISAPNP_ANY_ID, ISAPNP_ANY_ID,
@@ -344,7 +317,7 @@ static int __init isapnp_fmi_probe(void)
344 if (pnp_device_attach(dev) < 0) 317 if (pnp_device_attach(dev) < 0)
345 return -EAGAIN; 318 return -EAGAIN;
346 if (pnp_activate_dev(dev) < 0) { 319 if (pnp_activate_dev(dev) < 0) {
347 printk ("radio-sf16fmi: PnP configure failed (out of resources?)\n"); 320 printk(KERN_ERR "radio-sf16fmi: PnP configure failed (out of resources?)\n");
348 pnp_device_detach(dev); 321 pnp_device_detach(dev);
349 return -ENOMEM; 322 return -ENOMEM;
350 } 323 }
@@ -354,59 +327,72 @@ static int __init isapnp_fmi_probe(void)
354 } 327 }
355 328
356 i = pnp_port_start(dev, 0); 329 i = pnp_port_start(dev, 0);
357 printk ("radio-sf16fmi: PnP reports card at %#x\n", i); 330 printk(KERN_INFO "radio-sf16fmi: PnP reports card at %#x\n", i);
358 331
359 return i; 332 return i;
360} 333}
361 334
362static int __init fmi_init(void) 335static int __init fmi_init(void)
363{ 336{
337 struct fmi *fmi = &fmi_card;
338 struct v4l2_device *v4l2_dev = &fmi->v4l2_dev;
339 int res;
340
364 if (io < 0) 341 if (io < 0)
365 io = isapnp_fmi_probe(); 342 io = isapnp_fmi_probe();
366 if (io < 0) { 343 strlcpy(v4l2_dev->name, "sf16fmi", sizeof(v4l2_dev->name));
367 printk(KERN_ERR "radio-sf16fmi: No PnP card found.\n"); 344 fmi->io = io;
368 return io; 345 if (fmi->io < 0) {
346 v4l2_err(v4l2_dev, "No PnP card found.\n");
347 return fmi->io;
369 } 348 }
370 if (!request_region(io, 2, "radio-sf16fmi")) { 349 if (!request_region(io, 2, "radio-sf16fmi")) {
371 printk(KERN_ERR "radio-sf16fmi: port 0x%x already in use\n", io); 350 v4l2_err(v4l2_dev, "port 0x%x already in use\n", fmi->io);
372 pnp_device_detach(dev); 351 pnp_device_detach(dev);
373 return -EBUSY; 352 return -EBUSY;
374 } 353 }
375 354
376 fmi_unit.port = io; 355 res = v4l2_device_register(NULL, v4l2_dev);
377 fmi_unit.curvol = 0; 356 if (res < 0) {
378 fmi_unit.curfreq = 0; 357 release_region(fmi->io, 2);
379 fmi_unit.flags = V4L2_TUNER_CAP_LOW; 358 pnp_device_detach(dev);
380 video_set_drvdata(&fmi_radio, &fmi_unit); 359 v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
360 return res;
361 }
362
363 fmi->flags = V4L2_TUNER_CAP_LOW;
364 strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name));
365 fmi->vdev.v4l2_dev = v4l2_dev;
366 fmi->vdev.fops = &fmi_fops;
367 fmi->vdev.ioctl_ops = &fmi_ioctl_ops;
368 fmi->vdev.release = video_device_release_empty;
369 video_set_drvdata(&fmi->vdev, fmi);
381 370
382 mutex_init(&lock); 371 mutex_init(&fmi->lock);
383 372
384 if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) < 0) { 373 if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
385 release_region(io, 2); 374 v4l2_device_unregister(v4l2_dev);
375 release_region(fmi->io, 2);
376 pnp_device_detach(dev);
386 return -EINVAL; 377 return -EINVAL;
387 } 378 }
388 379
389 printk(KERN_INFO "SF16FMx radio card driver at 0x%x\n", io); 380 v4l2_info(v4l2_dev, "card driver at 0x%x\n", fmi->io);
390 /* mute card - prevents noisy bootups */ 381 /* mute card - prevents noisy bootups */
391 fmi_mute(io); 382 fmi_mute(fmi);
392 return 0; 383 return 0;
393} 384}
394 385
395MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood"); 386static void __exit fmi_exit(void)
396MODULE_DESCRIPTION("A driver for the SF16MI radio.");
397MODULE_LICENSE("GPL");
398
399module_param(io, int, 0);
400MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)");
401module_param(radio_nr, int, 0);
402
403static void __exit fmi_cleanup_module(void)
404{ 387{
405 video_unregister_device(&fmi_radio); 388 struct fmi *fmi = &fmi_card;
406 release_region(io, 2); 389
390 video_unregister_device(&fmi->vdev);
391 v4l2_device_unregister(&fmi->v4l2_dev);
392 release_region(fmi->io, 2);
407 if (dev) 393 if (dev)
408 pnp_device_detach(dev); 394 pnp_device_detach(dev);
409} 395}
410 396
411module_init(fmi_init); 397module_init(fmi_init);
412module_exit(fmi_cleanup_module); 398module_exit(fmi_exit);