aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2009-03-06 11:53:58 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-03-30 11:43:13 -0400
commit5ac3d5bf4aedf55721cf4f65ab44fb1f598585ce (patch)
tree7ecb431c7eee8f1638120aad0418b0c7071b8904
parentc32a9d7155307414bb6e120f4e6581a32ed708d3 (diff)
V4L/DVB (10890): radio-terratec: 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-terratec.c310
1 files changed, 147 insertions, 163 deletions
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index 0798d71abd00..5a37e0d797bf 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -28,15 +28,30 @@
28#include <linux/init.h> /* Initdata */ 28#include <linux/init.h> /* Initdata */
29#include <linux/ioport.h> /* request_region */ 29#include <linux/ioport.h> /* request_region */
30#include <linux/delay.h> /* udelay */ 30#include <linux/delay.h> /* udelay */
31#include <asm/io.h> /* outb, outb_p */
32#include <asm/uaccess.h> /* copy to/from user */
33#include <linux/videodev2.h> /* kernel radio structs */ 31#include <linux/videodev2.h> /* kernel radio structs */
34#include <media/v4l2-common.h> 32#include <linux/mutex.h>
33#include <linux/version.h> /* for KERNEL_VERSION MACRO */
34#include <linux/io.h> /* outb, outb_p */
35#include <linux/uaccess.h> /* copy to/from user */
36#include <media/v4l2-device.h>
35#include <media/v4l2-ioctl.h> 37#include <media/v4l2-ioctl.h>
36#include <linux/spinlock.h>
37 38
38#include <linux/version.h> /* for KERNEL_VERSION MACRO */ 39MODULE_AUTHOR("R.OFFERMANNS & others");
39#define RADIO_VERSION KERNEL_VERSION(0,0,2) 40MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
41MODULE_LICENSE("GPL");
42
43#ifndef CONFIG_RADIO_TERRATEC_PORT
44#define CONFIG_RADIO_TERRATEC_PORT 0x590
45#endif
46
47static int io = CONFIG_RADIO_TERRATEC_PORT;
48static int radio_nr = -1;
49
50module_param(io, int, 0);
51MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)");
52module_param(radio_nr, int, 0);
53
54#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
40 55
41static struct v4l2_queryctrl radio_qctrl[] = { 56static struct v4l2_queryctrl radio_qctrl[] = {
42 { 57 {
@@ -57,13 +72,6 @@ static struct v4l2_queryctrl radio_qctrl[] = {
57 } 72 }
58}; 73};
59 74
60#ifndef CONFIG_RADIO_TERRATEC_PORT
61#define CONFIG_RADIO_TERRATEC_PORT 0x590
62#endif
63
64/**************** this ones are for the terratec *******************/
65#define BASEPORT 0x590
66#define VOLPORT 0x591
67#define WRT_DIS 0x00 75#define WRT_DIS 0x00
68#define CLK_OFF 0x00 76#define CLK_OFF 0x00
69#define IIC_DATA 0x01 77#define IIC_DATA 0x01
@@ -71,138 +79,124 @@ static struct v4l2_queryctrl radio_qctrl[] = {
71#define DATA 0x04 79#define DATA 0x04
72#define CLK_ON 0x08 80#define CLK_ON 0x08
73#define WRT_EN 0x10 81#define WRT_EN 0x10
74/*******************************************************************/
75 82
76static int io = CONFIG_RADIO_TERRATEC_PORT; 83struct terratec
77static int radio_nr = -1;
78static spinlock_t lock;
79
80struct tt_device
81{ 84{
82 unsigned long in_use; 85 struct v4l2_device v4l2_dev;
83 int port; 86 struct video_device vdev;
87 int io;
84 int curvol; 88 int curvol;
85 unsigned long curfreq; 89 unsigned long curfreq;
86 int muted; 90 int muted;
91 struct mutex lock;
87}; 92};
88 93
94static struct terratec terratec_card;
89 95
90/* local things */ 96/* local things */
91 97
92static void cardWriteVol(int volume) 98static void tt_write_vol(struct terratec *tt, int volume)
93{ 99{
94 int i; 100 int i;
95 volume = volume+(volume * 32); // change both channels 101
96 spin_lock(&lock); 102 volume = volume + (volume * 32); /* change both channels */
97 for (i=0;i<8;i++) 103 mutex_lock(&tt->lock);
98 { 104 for (i = 0; i < 8; i++) {
99 if (volume & (0x80>>i)) 105 if (volume & (0x80 >> i))
100 outb(0x80, VOLPORT); 106 outb(0x80, tt->io + 1);
101 else outb(0x00, VOLPORT); 107 else
108 outb(0x00, tt->io + 1);
102 } 109 }
103 spin_unlock(&lock); 110 mutex_unlock(&tt->lock);
104} 111}
105 112
106 113
107 114
108static void tt_mute(struct tt_device *dev) 115static void tt_mute(struct terratec *tt)
109{ 116{
110 dev->muted = 1; 117 tt->muted = 1;
111 cardWriteVol(0); 118 tt_write_vol(tt, 0);
112} 119}
113 120
114static int tt_setvol(struct tt_device *dev, int vol) 121static int tt_setvol(struct terratec *tt, int vol)
115{ 122{
116 123 if (vol == tt->curvol) { /* requested volume = current */
117// printk(KERN_ERR "setvol called, vol = %d\n", vol); 124 if (tt->muted) { /* user is unmuting the card */
118 125 tt->muted = 0;
119 if(vol == dev->curvol) { /* requested volume = current */ 126 tt_write_vol(tt, vol); /* enable card */
120 if (dev->muted) { /* user is unmuting the card */
121 dev->muted = 0;
122 cardWriteVol(vol); /* enable card */
123 } 127 }
124
125 return 0; 128 return 0;
126 } 129 }
127 130
128 if(vol == 0) { /* volume = 0 means mute the card */ 131 if (vol == 0) { /* volume = 0 means mute the card */
129 cardWriteVol(0); /* "turn off card" by setting vol to 0 */ 132 tt_write_vol(tt, 0); /* "turn off card" by setting vol to 0 */
130 dev->curvol = vol; /* track the volume state! */ 133 tt->curvol = vol; /* track the volume state! */
131 return 0; 134 return 0;
132 } 135 }
133 136
134 dev->muted = 0; 137 tt->muted = 0;
135 138 tt_write_vol(tt, vol);
136 cardWriteVol(vol); 139 tt->curvol = vol;
137
138 dev->curvol = vol;
139
140 return 0; 140 return 0;
141
142} 141}
143 142
144 143
145/* this is the worst part in this driver */ 144/* this is the worst part in this driver */
146/* many more or less strange things are going on here, but hey, it works :) */ 145/* many more or less strange things are going on here, but hey, it works :) */
147 146
148static int tt_setfreq(struct tt_device *dev, unsigned long freq1) 147static int tt_setfreq(struct terratec *tt, unsigned long freq1)
149{ 148{
150 int freq; 149 int freq;
151 int i; 150 int i;
152 int p; 151 int p;
153 int temp; 152 int temp;
154 long rest; 153 long rest;
155
156 unsigned char buffer[25]; /* we have to bit shift 25 registers */ 154 unsigned char buffer[25]; /* we have to bit shift 25 registers */
157 freq = freq1/160; /* convert the freq. to a nice to handle value */
158 for(i=24;i>-1;i--)
159 buffer[i]=0;
160 155
161 rest = freq*10+10700; /* i once had understood what is going on here */ 156 mutex_lock(&tt->lock);
157
158 tt->curfreq = freq1;
159
160 freq = freq1 / 160; /* convert the freq. to a nice to handle value */
161 memset(buffer, 0, sizeof(buffer));
162
163 rest = freq * 10 + 10700; /* I once had understood what is going on here */
162 /* maybe some wise guy (friedhelm?) can comment this stuff */ 164 /* maybe some wise guy (friedhelm?) can comment this stuff */
163 i=13; 165 i = 13;
164 p=10; 166 p = 10;
165 temp=102400; 167 temp = 102400;
166 while (rest!=0) 168 while (rest != 0) {
167 { 169 if (rest % temp == rest)
168 if (rest%temp == rest)
169 buffer[i] = 0; 170 buffer[i] = 0;
170 else 171 else {
171 {
172 buffer[i] = 1; 172 buffer[i] = 1;
173 rest = rest-temp; 173 rest = rest - temp;
174 } 174 }
175 i--; 175 i--;
176 p--; 176 p--;
177 temp = temp/2; 177 temp = temp / 2;
178 } 178 }
179 179
180 spin_lock(&lock); 180 for (i = 24; i > -1; i--) { /* bit shift the values to the radiocard */
181 181 if (buffer[i] == 1) {
182 for (i=24;i>-1;i--) /* bit shift the values to the radiocard */ 182 outb(WRT_EN | DATA, tt->io);
183 { 183 outb(WRT_EN | DATA | CLK_ON, tt->io);
184 if (buffer[i]==1) 184 outb(WRT_EN | DATA, tt->io);
185 { 185 } else {
186 outb(WRT_EN|DATA, BASEPORT); 186 outb(WRT_EN | 0x00, tt->io);
187 outb(WRT_EN|DATA|CLK_ON , BASEPORT); 187 outb(WRT_EN | 0x00 | CLK_ON, tt->io);
188 outb(WRT_EN|DATA, BASEPORT);
189 }
190 else
191 {
192 outb(WRT_EN|0x00, BASEPORT);
193 outb(WRT_EN|0x00|CLK_ON , BASEPORT);
194 } 188 }
195 } 189 }
196 outb(0x00, BASEPORT); 190 outb(0x00, tt->io);
197 191
198 spin_unlock(&lock); 192 mutex_unlock(&tt->lock);
199 193
200 return 0; 194 return 0;
201} 195}
202 196
203static int tt_getsigstr(struct tt_device *dev) /* TODO */ 197static int tt_getsigstr(struct terratec *tt)
204{ 198{
205 if (inb(io) & 2) /* bit set = no signal present */ 199 if (inb(tt->io) & 2) /* bit set = no signal present */
206 return 0; 200 return 0;
207 return 1; /* signal present */ 201 return 1; /* signal present */
208} 202}
@@ -212,53 +206,50 @@ static int vidioc_querycap(struct file *file, void *priv,
212{ 206{
213 strlcpy(v->driver, "radio-terratec", sizeof(v->driver)); 207 strlcpy(v->driver, "radio-terratec", sizeof(v->driver));
214 strlcpy(v->card, "ActiveRadio", sizeof(v->card)); 208 strlcpy(v->card, "ActiveRadio", sizeof(v->card));
215 sprintf(v->bus_info, "ISA"); 209 strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
216 v->version = RADIO_VERSION; 210 v->version = RADIO_VERSION;
217 v->capabilities = V4L2_CAP_TUNER; 211 v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
218 return 0; 212 return 0;
219} 213}
220 214
221static int vidioc_g_tuner(struct file *file, void *priv, 215static int vidioc_g_tuner(struct file *file, void *priv,
222 struct v4l2_tuner *v) 216 struct v4l2_tuner *v)
223{ 217{
224 struct tt_device *tt = video_drvdata(file); 218 struct terratec *tt = video_drvdata(file);
225 219
226 if (v->index > 0) 220 if (v->index > 0)
227 return -EINVAL; 221 return -EINVAL;
228 222
229 strcpy(v->name, "FM"); 223 strlcpy(v->name, "FM", sizeof(v->name));
230 v->type = V4L2_TUNER_RADIO; 224 v->type = V4L2_TUNER_RADIO;
231 v->rangelow = (87*16000); 225 v->rangelow = 87 * 16000;
232 v->rangehigh = (108*16000); 226 v->rangehigh = 108 * 16000;
233 v->rxsubchans = V4L2_TUNER_SUB_MONO; 227 v->rxsubchans = V4L2_TUNER_SUB_MONO;
234 v->capability = V4L2_TUNER_CAP_LOW; 228 v->capability = V4L2_TUNER_CAP_LOW;
235 v->audmode = V4L2_TUNER_MODE_MONO; 229 v->audmode = V4L2_TUNER_MODE_MONO;
236 v->signal = 0xFFFF*tt_getsigstr(tt); 230 v->signal = 0xFFFF * tt_getsigstr(tt);
237 return 0; 231 return 0;
238} 232}
239 233
240static int vidioc_s_tuner(struct file *file, void *priv, 234static int vidioc_s_tuner(struct file *file, void *priv,
241 struct v4l2_tuner *v) 235 struct v4l2_tuner *v)
242{ 236{
243 if (v->index > 0) 237 return v->index ? -EINVAL : 0;
244 return -EINVAL;
245 return 0;
246} 238}
247 239
248static int vidioc_s_frequency(struct file *file, void *priv, 240static int vidioc_s_frequency(struct file *file, void *priv,
249 struct v4l2_frequency *f) 241 struct v4l2_frequency *f)
250{ 242{
251 struct tt_device *tt = video_drvdata(file); 243 struct terratec *tt = video_drvdata(file);
252 244
253 tt->curfreq = f->frequency; 245 tt_setfreq(tt, f->frequency);
254 tt_setfreq(tt, tt->curfreq);
255 return 0; 246 return 0;
256} 247}
257 248
258static int vidioc_g_frequency(struct file *file, void *priv, 249static int vidioc_g_frequency(struct file *file, void *priv,
259 struct v4l2_frequency *f) 250 struct v4l2_frequency *f)
260{ 251{
261 struct tt_device *tt = video_drvdata(file); 252 struct terratec *tt = video_drvdata(file);
262 253
263 f->type = V4L2_TUNER_RADIO; 254 f->type = V4L2_TUNER_RADIO;
264 f->frequency = tt->curfreq; 255 f->frequency = tt->curfreq;
@@ -272,8 +263,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
272 263
273 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { 264 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
274 if (qc->id && qc->id == radio_qctrl[i].id) { 265 if (qc->id && qc->id == radio_qctrl[i].id) {
275 memcpy(qc, &(radio_qctrl[i]), 266 memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
276 sizeof(*qc));
277 return 0; 267 return 0;
278 } 268 }
279 } 269 }
@@ -283,7 +273,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
283static int vidioc_g_ctrl(struct file *file, void *priv, 273static int vidioc_g_ctrl(struct file *file, void *priv,
284 struct v4l2_control *ctrl) 274 struct v4l2_control *ctrl)
285{ 275{
286 struct tt_device *tt = video_drvdata(file); 276 struct terratec *tt = video_drvdata(file);
287 277
288 switch (ctrl->id) { 278 switch (ctrl->id) {
289 case V4L2_CID_AUDIO_MUTE: 279 case V4L2_CID_AUDIO_MUTE:
@@ -302,7 +292,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
302static int vidioc_s_ctrl(struct file *file, void *priv, 292static int vidioc_s_ctrl(struct file *file, void *priv,
303 struct v4l2_control *ctrl) 293 struct v4l2_control *ctrl)
304{ 294{
305 struct tt_device *tt = video_drvdata(file); 295 struct terratec *tt = video_drvdata(file);
306 296
307 switch (ctrl->id) { 297 switch (ctrl->id) {
308 case V4L2_CID_AUDIO_MUTE: 298 case V4L2_CID_AUDIO_MUTE:
@@ -318,17 +308,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
318 return -EINVAL; 308 return -EINVAL;
319} 309}
320 310
321static int vidioc_g_audio(struct file *file, void *priv,
322 struct v4l2_audio *a)
323{
324 if (a->index > 1)
325 return -EINVAL;
326
327 strcpy(a->name, "Radio");
328 a->capability = V4L2_AUDCAP_STEREO;
329 return 0;
330}
331
332static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) 311static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
333{ 312{
334 *i = 0; 313 *i = 0;
@@ -337,36 +316,38 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
337 316
338static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) 317static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
339{ 318{
340 if (i != 0) 319 return i ? -EINVAL : 0;
341 return -EINVAL;
342 return 0;
343} 320}
344 321
345static int vidioc_s_audio(struct file *file, void *priv, 322static int vidioc_g_audio(struct file *file, void *priv,
346 struct v4l2_audio *a) 323 struct v4l2_audio *a)
347{ 324{
348 if (a->index != 0) 325 a->index = 0;
349 return -EINVAL; 326 strlcpy(a->name, "Radio", sizeof(a->name));
327 a->capability = V4L2_AUDCAP_STEREO;
350 return 0; 328 return 0;
351} 329}
352 330
353static struct tt_device terratec_unit; 331static int vidioc_s_audio(struct file *file, void *priv,
332 struct v4l2_audio *a)
333{
334 return a->index ? -EINVAL : 0;
335}
354 336
355static int terratec_exclusive_open(struct file *file) 337static int terratec_open(struct file *file)
356{ 338{
357 return test_and_set_bit(0, &terratec_unit.in_use) ? -EBUSY : 0; 339 return 0;
358} 340}
359 341
360static int terratec_exclusive_release(struct file *file) 342static int terratec_release(struct file *file)
361{ 343{
362 clear_bit(0, &terratec_unit.in_use);
363 return 0; 344 return 0;
364} 345}
365 346
366static const struct v4l2_file_operations terratec_fops = { 347static const struct v4l2_file_operations terratec_fops = {
367 .owner = THIS_MODULE, 348 .owner = THIS_MODULE,
368 .open = terratec_exclusive_open, 349 .open = terratec_open,
369 .release = terratec_exclusive_release, 350 .release = terratec_release,
370 .ioctl = video_ioctl2, 351 .ioctl = video_ioctl2,
371}; 352};
372 353
@@ -385,60 +366,63 @@ static const struct v4l2_ioctl_ops terratec_ioctl_ops = {
385 .vidioc_s_input = vidioc_s_input, 366 .vidioc_s_input = vidioc_s_input,
386}; 367};
387 368
388static struct video_device terratec_radio = {
389 .name = "TerraTec ActiveRadio",
390 .fops = &terratec_fops,
391 .ioctl_ops = &terratec_ioctl_ops,
392 .release = video_device_release_empty,
393};
394
395static int __init terratec_init(void) 369static int __init terratec_init(void)
396{ 370{
397 if(io==-1) 371 struct terratec *tt = &terratec_card;
398 { 372 struct v4l2_device *v4l2_dev = &tt->v4l2_dev;
399 printk(KERN_ERR "You must set an I/O address with io=0x???\n"); 373 int res;
374
375 strlcpy(v4l2_dev->name, "terratec", sizeof(v4l2_dev->name));
376 tt->io = io;
377 if (tt->io == -1) {
378 v4l2_err(v4l2_dev, "you must set an I/O address with io=0x???\n");
400 return -EINVAL; 379 return -EINVAL;
401 } 380 }
402 if (!request_region(io, 2, "terratec")) 381 if (!request_region(tt->io, 2, "terratec")) {
403 { 382 v4l2_err(v4l2_dev, "port 0x%x already in use\n", io);
404 printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io);
405 return -EBUSY; 383 return -EBUSY;
406 } 384 }
407 385
408 video_set_drvdata(&terratec_radio, &terratec_unit); 386 res = v4l2_device_register(NULL, v4l2_dev);
387 if (res < 0) {
388 release_region(tt->io, 2);
389 v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
390 return res;
391 }
392
393 strlcpy(tt->vdev.name, v4l2_dev->name, sizeof(tt->vdev.name));
394 tt->vdev.v4l2_dev = v4l2_dev;
395 tt->vdev.fops = &terratec_fops;
396 tt->vdev.ioctl_ops = &terratec_ioctl_ops;
397 tt->vdev.release = video_device_release_empty;
398 video_set_drvdata(&tt->vdev, tt);
409 399
410 spin_lock_init(&lock); 400 mutex_init(&tt->lock);
411 401
412 if (video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr) < 0) { 402 if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
413 release_region(io,2); 403 v4l2_device_unregister(&tt->v4l2_dev);
404 release_region(tt->io, 2);
414 return -EINVAL; 405 return -EINVAL;
415 } 406 }
416 407
417 printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n"); 408 v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n");
418 409
419 /* mute card - prevents noisy bootups */ 410 /* mute card - prevents noisy bootups */
420 411 tt_write_vol(tt, 0);
421 /* this ensures that the volume is all the way down */
422 cardWriteVol(0);
423 terratec_unit.curvol = 0;
424
425 return 0; 412 return 0;
426} 413}
427 414
428MODULE_AUTHOR("R.OFFERMANNS & others"); 415static void __exit terratec_exit(void)
429MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
430MODULE_LICENSE("GPL");
431module_param(io, int, 0);
432MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)");
433module_param(radio_nr, int, 0);
434
435static void __exit terratec_cleanup_module(void)
436{ 416{
437 video_unregister_device(&terratec_radio); 417 struct terratec *tt = &terratec_card;
438 release_region(io,2); 418 struct v4l2_device *v4l2_dev = &tt->v4l2_dev;
439 printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n"); 419
420 video_unregister_device(&tt->vdev);
421 v4l2_device_unregister(&tt->v4l2_dev);
422 release_region(tt->io, 2);
423 v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver unloaded.\n");
440} 424}
441 425
442module_init(terratec_init); 426module_init(terratec_init);
443module_exit(terratec_cleanup_module); 427module_exit(terratec_exit);
444 428