aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/radio/radio-zoltrix.c
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2009-03-06 11:55:34 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-03-30 11:43:13 -0400
commitec632c8a1094e52d3da903ba057accad15f11d04 (patch)
treee5b68634cab57482a90109b26fdc1b02077f43fe /drivers/media/radio/radio-zoltrix.c
parentf1bfe89b6721ba9ad8c3c6e67cce58d5616cd012 (diff)
V4L/DVB (10893): radio-zoltrix: convert to v4l2_device.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/radio/radio-zoltrix.c')
-rw-r--r--drivers/media/radio/radio-zoltrix.c379
1 files changed, 178 insertions, 201 deletions
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index d2ac17eeec5f..18dbaf1650de 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -33,33 +33,17 @@
33#include <linux/init.h> /* Initdata */ 33#include <linux/init.h> /* Initdata */
34#include <linux/ioport.h> /* request_region */ 34#include <linux/ioport.h> /* request_region */
35#include <linux/delay.h> /* udelay, msleep */ 35#include <linux/delay.h> /* udelay, msleep */
36#include <asm/io.h> /* outb, outb_p */
37#include <asm/uaccess.h> /* copy to/from user */
38#include <linux/videodev2.h> /* kernel radio structs */ 36#include <linux/videodev2.h> /* kernel radio structs */
39#include <media/v4l2-common.h> 37#include <linux/mutex.h>
38#include <linux/version.h> /* for KERNEL_VERSION MACRO */
39#include <linux/io.h> /* outb, outb_p */
40#include <linux/uaccess.h> /* copy to/from user */
41#include <media/v4l2-device.h>
40#include <media/v4l2-ioctl.h> 42#include <media/v4l2-ioctl.h>
41 43
42#include <linux/version.h> /* for KERNEL_VERSION MACRO */ 44MODULE_AUTHOR("C.van Schaik");
43#define RADIO_VERSION KERNEL_VERSION(0,0,2) 45MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus.");
44 46MODULE_LICENSE("GPL");
45static struct v4l2_queryctrl radio_qctrl[] = {
46 {
47 .id = V4L2_CID_AUDIO_MUTE,
48 .name = "Mute",
49 .minimum = 0,
50 .maximum = 1,
51 .default_value = 1,
52 .type = V4L2_CTRL_TYPE_BOOLEAN,
53 },{
54 .id = V4L2_CID_AUDIO_VOLUME,
55 .name = "Volume",
56 .minimum = 0,
57 .maximum = 65535,
58 .step = 4096,
59 .default_value = 0xff,
60 .type = V4L2_CTRL_TYPE_INTEGER,
61 }
62};
63 47
64#ifndef CONFIG_RADIO_ZOLTRIX_PORT 48#ifndef CONFIG_RADIO_ZOLTRIX_PORT
65#define CONFIG_RADIO_ZOLTRIX_PORT -1 49#define CONFIG_RADIO_ZOLTRIX_PORT -1
@@ -68,9 +52,16 @@ static struct v4l2_queryctrl radio_qctrl[] = {
68static int io = CONFIG_RADIO_ZOLTRIX_PORT; 52static int io = CONFIG_RADIO_ZOLTRIX_PORT;
69static int radio_nr = -1; 53static int radio_nr = -1;
70 54
71struct zol_device { 55module_param(io, int, 0);
72 unsigned long in_use; 56MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)");
73 int port; 57module_param(radio_nr, int, 0);
58
59#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
60
61struct zoltrix {
62 struct v4l2_device v4l2_dev;
63 struct video_device vdev;
64 int io;
74 int curvol; 65 int curvol;
75 unsigned long curfreq; 66 unsigned long curfreq;
76 int muted; 67 int muted;
@@ -78,161 +69,158 @@ struct zol_device {
78 struct mutex lock; 69 struct mutex lock;
79}; 70};
80 71
81static int zol_setvol(struct zol_device *dev, int vol) 72static struct zoltrix zoltrix_card;
73
74static int zol_setvol(struct zoltrix *zol, int vol)
82{ 75{
83 dev->curvol = vol; 76 zol->curvol = vol;
84 if (dev->muted) 77 if (zol->muted)
85 return 0; 78 return 0;
86 79
87 mutex_lock(&dev->lock); 80 mutex_lock(&zol->lock);
88 if (vol == 0) { 81 if (vol == 0) {
89 outb(0, io); 82 outb(0, zol->io);
90 outb(0, io); 83 outb(0, zol->io);
91 inb(io + 3); /* Zoltrix needs to be read to confirm */ 84 inb(zol->io + 3); /* Zoltrix needs to be read to confirm */
92 mutex_unlock(&dev->lock); 85 mutex_unlock(&zol->lock);
93 return 0; 86 return 0;
94 } 87 }
95 88
96 outb(dev->curvol-1, io); 89 outb(zol->curvol-1, zol->io);
97 msleep(10); 90 msleep(10);
98 inb(io + 2); 91 inb(zol->io + 2);
99 mutex_unlock(&dev->lock); 92 mutex_unlock(&zol->lock);
100 return 0; 93 return 0;
101} 94}
102 95
103static void zol_mute(struct zol_device *dev) 96static void zol_mute(struct zoltrix *zol)
104{ 97{
105 dev->muted = 1; 98 zol->muted = 1;
106 mutex_lock(&dev->lock); 99 mutex_lock(&zol->lock);
107 outb(0, io); 100 outb(0, zol->io);
108 outb(0, io); 101 outb(0, zol->io);
109 inb(io + 3); /* Zoltrix needs to be read to confirm */ 102 inb(zol->io + 3); /* Zoltrix needs to be read to confirm */
110 mutex_unlock(&dev->lock); 103 mutex_unlock(&zol->lock);
111} 104}
112 105
113static void zol_unmute(struct zol_device *dev) 106static void zol_unmute(struct zoltrix *zol)
114{ 107{
115 dev->muted = 0; 108 zol->muted = 0;
116 zol_setvol(dev, dev->curvol); 109 zol_setvol(zol, zol->curvol);
117} 110}
118 111
119static int zol_setfreq(struct zol_device *dev, unsigned long freq) 112static int zol_setfreq(struct zoltrix *zol, unsigned long freq)
120{ 113{
121 /* tunes the radio to the desired frequency */ 114 /* tunes the radio to the desired frequency */
115 struct v4l2_device *v4l2_dev = &zol->v4l2_dev;
122 unsigned long long bitmask, f, m; 116 unsigned long long bitmask, f, m;
123 unsigned int stereo = dev->stereo; 117 unsigned int stereo = zol->stereo;
124 int i; 118 int i;
125 119
126 if (freq == 0) { 120 if (freq == 0) {
127 printk(KERN_WARNING "zoltrix: received zero freq. Failed to set.\n"); 121 v4l2_warn(v4l2_dev, "cannot set a frequency of 0.\n");
128 return -EINVAL; 122 return -EINVAL;
129 } 123 }
130 124
131 m = (freq / 160 - 8800) * 2; 125 m = (freq / 160 - 8800) * 2;
132 f = (unsigned long long) m + 0x4d1c; 126 f = (unsigned long long)m + 0x4d1c;
133 127
134 bitmask = 0xc480402c10080000ull; 128 bitmask = 0xc480402c10080000ull;
135 i = 45; 129 i = 45;
136 130
137 mutex_lock(&dev->lock); 131 mutex_lock(&zol->lock);
138 132
139 outb(0, io); 133 zol->curfreq = freq;
140 outb(0, io);
141 inb(io + 3); /* Zoltrix needs to be read to confirm */
142 134
143 outb(0x40, io); 135 outb(0, zol->io);
144 outb(0xc0, io); 136 outb(0, zol->io);
137 inb(zol->io + 3); /* Zoltrix needs to be read to confirm */
145 138
146 bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ ( stereo << 31)); 139 outb(0x40, zol->io);
140 outb(0xc0, zol->io);
141
142 bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ (stereo << 31));
147 while (i--) { 143 while (i--) {
148 if ((bitmask & 0x8000000000000000ull) != 0) { 144 if ((bitmask & 0x8000000000000000ull) != 0) {
149 outb(0x80, io); 145 outb(0x80, zol->io);
150 udelay(50); 146 udelay(50);
151 outb(0x00, io); 147 outb(0x00, zol->io);
152 udelay(50); 148 udelay(50);
153 outb(0x80, io); 149 outb(0x80, zol->io);
154 udelay(50); 150 udelay(50);
155 } else { 151 } else {
156 outb(0xc0, io); 152 outb(0xc0, zol->io);
157 udelay(50); 153 udelay(50);
158 outb(0x40, io); 154 outb(0x40, zol->io);
159 udelay(50); 155 udelay(50);
160 outb(0xc0, io); 156 outb(0xc0, zol->io);
161 udelay(50); 157 udelay(50);
162 } 158 }
163 bitmask *= 2; 159 bitmask *= 2;
164 } 160 }
165 /* termination sequence */ 161 /* termination sequence */
166 outb(0x80, io); 162 outb(0x80, zol->io);
167 outb(0xc0, io); 163 outb(0xc0, zol->io);
168 outb(0x40, io); 164 outb(0x40, zol->io);
169 udelay(1000); 165 udelay(1000);
170 inb(io+2); 166 inb(zol->io + 2);
171 167
172 udelay(1000); 168 udelay(1000);
173 169
174 if (dev->muted) 170 if (zol->muted) {
175 { 171 outb(0, zol->io);
176 outb(0, io); 172 outb(0, zol->io);
177 outb(0, io); 173 inb(zol->io + 3);
178 inb(io + 3);
179 udelay(1000); 174 udelay(1000);
180 } 175 }
181 176
182 mutex_unlock(&dev->lock); 177 mutex_unlock(&zol->lock);
183 178
184 if(!dev->muted) 179 if (!zol->muted)
185 { 180 zol_setvol(zol, zol->curvol);
186 zol_setvol(dev, dev->curvol);
187 }
188 return 0; 181 return 0;
189} 182}
190 183
191/* Get signal strength */ 184/* Get signal strength */
192 185static int zol_getsigstr(struct zoltrix *zol)
193static int zol_getsigstr(struct zol_device *dev)
194{ 186{
195 int a, b; 187 int a, b;
196 188
197 mutex_lock(&dev->lock); 189 mutex_lock(&zol->lock);
198 outb(0x00, io); /* This stuff I found to do nothing */ 190 outb(0x00, zol->io); /* This stuff I found to do nothing */
199 outb(dev->curvol, io); 191 outb(zol->curvol, zol->io);
200 msleep(20); 192 msleep(20);
201 193
202 a = inb(io); 194 a = inb(zol->io);
203 msleep(10); 195 msleep(10);
204 b = inb(io); 196 b = inb(zol->io);
205 197
206 mutex_unlock(&dev->lock); 198 mutex_unlock(&zol->lock);
207 199
208 if (a != b) 200 if (a != b)
209 return (0); 201 return 0;
210 202
211 if ((a == 0xcf) || (a == 0xdf) /* I found this out by playing */ 203 /* I found this out by playing with a binary scanner on the card io */
212 || (a == 0xef)) /* with a binary scanner on the card io */ 204 return a == 0xcf || a == 0xdf || a == 0xef;
213 return (1);
214 return (0);
215} 205}
216 206
217static int zol_is_stereo (struct zol_device *dev) 207static int zol_is_stereo(struct zoltrix *zol)
218{ 208{
219 int x1, x2; 209 int x1, x2;
220 210
221 mutex_lock(&dev->lock); 211 mutex_lock(&zol->lock);
222 212
223 outb(0x00, io); 213 outb(0x00, zol->io);
224 outb(dev->curvol, io); 214 outb(zol->curvol, zol->io);
225 msleep(20); 215 msleep(20);
226 216
227 x1 = inb(io); 217 x1 = inb(zol->io);
228 msleep(10); 218 msleep(10);
229 x2 = inb(io); 219 x2 = inb(zol->io);
230 220
231 mutex_unlock(&dev->lock); 221 mutex_unlock(&zol->lock);
232 222
233 if ((x1 == x2) && (x1 == 0xcf)) 223 return x1 == x2 && x1 == 0xcf;
234 return 1;
235 return 0;
236} 224}
237 225
238static int vidioc_querycap(struct file *file, void *priv, 226static int vidioc_querycap(struct file *file, void *priv,
@@ -240,59 +228,54 @@ static int vidioc_querycap(struct file *file, void *priv,
240{ 228{
241 strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver)); 229 strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver));
242 strlcpy(v->card, "Zoltrix Radio", sizeof(v->card)); 230 strlcpy(v->card, "Zoltrix Radio", sizeof(v->card));
243 sprintf(v->bus_info, "ISA"); 231 strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
244 v->version = RADIO_VERSION; 232 v->version = RADIO_VERSION;
245 v->capabilities = V4L2_CAP_TUNER; 233 v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
246 return 0; 234 return 0;
247} 235}
248 236
249static int vidioc_g_tuner(struct file *file, void *priv, 237static int vidioc_g_tuner(struct file *file, void *priv,
250 struct v4l2_tuner *v) 238 struct v4l2_tuner *v)
251{ 239{
252 struct zol_device *zol = video_drvdata(file); 240 struct zoltrix *zol = video_drvdata(file);
253 241
254 if (v->index > 0) 242 if (v->index > 0)
255 return -EINVAL; 243 return -EINVAL;
256 244
257 strcpy(v->name, "FM"); 245 strlcpy(v->name, "FM", sizeof(v->name));
258 v->type = V4L2_TUNER_RADIO; 246 v->type = V4L2_TUNER_RADIO;
259 v->rangelow = (88*16000); 247 v->rangelow = 88 * 16000;
260 v->rangehigh = (108*16000); 248 v->rangehigh = 108 * 16000;
261 v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; 249 v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
262 v->capability = V4L2_TUNER_CAP_LOW; 250 v->capability = V4L2_TUNER_CAP_LOW;
263 if (zol_is_stereo(zol)) 251 if (zol_is_stereo(zol))
264 v->audmode = V4L2_TUNER_MODE_STEREO; 252 v->audmode = V4L2_TUNER_MODE_STEREO;
265 else 253 else
266 v->audmode = V4L2_TUNER_MODE_MONO; 254 v->audmode = V4L2_TUNER_MODE_MONO;
267 v->signal = 0xFFFF*zol_getsigstr(zol); 255 v->signal = 0xFFFF * zol_getsigstr(zol);
268 return 0; 256 return 0;
269} 257}
270 258
271static int vidioc_s_tuner(struct file *file, void *priv, 259static int vidioc_s_tuner(struct file *file, void *priv,
272 struct v4l2_tuner *v) 260 struct v4l2_tuner *v)
273{ 261{
274 if (v->index > 0) 262 return v->index ? -EINVAL : 0;
275 return -EINVAL;
276 return 0;
277} 263}
278 264
279static int vidioc_s_frequency(struct file *file, void *priv, 265static int vidioc_s_frequency(struct file *file, void *priv,
280 struct v4l2_frequency *f) 266 struct v4l2_frequency *f)
281{ 267{
282 struct zol_device *zol = video_drvdata(file); 268 struct zoltrix *zol = video_drvdata(file);
283 269
284 zol->curfreq = f->frequency; 270 if (zol_setfreq(zol, f->frequency) != 0)
285 if (zol_setfreq(zol, zol->curfreq) != 0) {
286 printk(KERN_WARNING "zoltrix: Set frequency failed.\n");
287 return -EINVAL; 271 return -EINVAL;
288 }
289 return 0; 272 return 0;
290} 273}
291 274
292static int vidioc_g_frequency(struct file *file, void *priv, 275static int vidioc_g_frequency(struct file *file, void *priv,
293 struct v4l2_frequency *f) 276 struct v4l2_frequency *f)
294{ 277{
295 struct zol_device *zol = video_drvdata(file); 278 struct zoltrix *zol = video_drvdata(file);
296 279
297 f->type = V4L2_TUNER_RADIO; 280 f->type = V4L2_TUNER_RADIO;
298 f->frequency = zol->curfreq; 281 f->frequency = zol->curfreq;
@@ -302,14 +285,11 @@ static int vidioc_g_frequency(struct file *file, void *priv,
302static int vidioc_queryctrl(struct file *file, void *priv, 285static int vidioc_queryctrl(struct file *file, void *priv,
303 struct v4l2_queryctrl *qc) 286 struct v4l2_queryctrl *qc)
304{ 287{
305 int i; 288 switch (qc->id) {
306 289 case V4L2_CID_AUDIO_MUTE:
307 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { 290 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
308 if (qc->id && qc->id == radio_qctrl[i].id) { 291 case V4L2_CID_AUDIO_VOLUME:
309 memcpy(qc, &(radio_qctrl[i]), 292 return v4l2_ctrl_query_fill(qc, 0, 65535, 4096, 65535);
310 sizeof(*qc));
311 return 0;
312 }
313 } 293 }
314 return -EINVAL; 294 return -EINVAL;
315} 295}
@@ -317,7 +297,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
317static int vidioc_g_ctrl(struct file *file, void *priv, 297static int vidioc_g_ctrl(struct file *file, void *priv,
318 struct v4l2_control *ctrl) 298 struct v4l2_control *ctrl)
319{ 299{
320 struct zol_device *zol = video_drvdata(file); 300 struct zoltrix *zol = video_drvdata(file);
321 301
322 switch (ctrl->id) { 302 switch (ctrl->id) {
323 case V4L2_CID_AUDIO_MUTE: 303 case V4L2_CID_AUDIO_MUTE:
@@ -333,7 +313,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
333static int vidioc_s_ctrl(struct file *file, void *priv, 313static int vidioc_s_ctrl(struct file *file, void *priv,
334 struct v4l2_control *ctrl) 314 struct v4l2_control *ctrl)
335{ 315{
336 struct zol_device *zol = video_drvdata(file); 316 struct zoltrix *zol = video_drvdata(file);
337 317
338 switch (ctrl->id) { 318 switch (ctrl->id) {
339 case V4L2_CID_AUDIO_MUTE: 319 case V4L2_CID_AUDIO_MUTE:
@@ -341,43 +321,30 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
341 zol_mute(zol); 321 zol_mute(zol);
342 else { 322 else {
343 zol_unmute(zol); 323 zol_unmute(zol);
344 zol_setvol(zol,zol->curvol); 324 zol_setvol(zol, zol->curvol);
345 } 325 }
346 return 0; 326 return 0;
347 case V4L2_CID_AUDIO_VOLUME: 327 case V4L2_CID_AUDIO_VOLUME:
348 zol_setvol(zol,ctrl->value/4096); 328 zol_setvol(zol, ctrl->value / 4096);
349 return 0; 329 return 0;
350 } 330 }
351 zol->stereo = 1; 331 zol->stereo = 1;
352 if (zol_setfreq(zol, zol->curfreq) != 0) { 332 if (zol_setfreq(zol, zol->curfreq) != 0)
353 printk(KERN_WARNING "zoltrix: Set frequency failed.\n");
354 return -EINVAL; 333 return -EINVAL;
355 }
356#if 0 334#if 0
357/* FIXME: Implement stereo/mono switch on V4L2 */ 335/* FIXME: Implement stereo/mono switch on V4L2 */
358 if (v->mode & VIDEO_SOUND_STEREO) { 336 if (v->mode & VIDEO_SOUND_STEREO) {
359 zol->stereo = 1; 337 zol->stereo = 1;
360 zol_setfreq(zol, zol->curfreq); 338 zol_setfreq(zol, zol->curfreq);
361 } 339 }
362 if (v->mode & VIDEO_SOUND_MONO) { 340 if (v->mode & VIDEO_SOUND_MONO) {
363 zol->stereo = 0; 341 zol->stereo = 0;
364 zol_setfreq(zol, zol->curfreq); 342 zol_setfreq(zol, zol->curfreq);
365 } 343 }
366#endif 344#endif
367 return -EINVAL; 345 return -EINVAL;
368} 346}
369 347
370static int vidioc_g_audio(struct file *file, void *priv,
371 struct v4l2_audio *a)
372{
373 if (a->index > 1)
374 return -EINVAL;
375
376 strcpy(a->name, "Radio");
377 a->capability = V4L2_AUDCAP_STEREO;
378 return 0;
379}
380
381static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) 348static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
382{ 349{
383 *i = 0; 350 *i = 0;
@@ -386,37 +353,39 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
386 353
387static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) 354static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
388{ 355{
389 if (i != 0) 356 return i ? -EINVAL : 0;
390 return -EINVAL;
391 return 0;
392} 357}
393 358
394static int vidioc_s_audio(struct file *file, void *priv, 359static int vidioc_g_audio(struct file *file, void *priv,
395 struct v4l2_audio *a) 360 struct v4l2_audio *a)
396{ 361{
397 if (a->index != 0) 362 a->index = 0;
398 return -EINVAL; 363 strlcpy(a->name, "Radio", sizeof(a->name));
364 a->capability = V4L2_AUDCAP_STEREO;
399 return 0; 365 return 0;
400} 366}
401 367
402static struct zol_device zoltrix_unit; 368static int vidioc_s_audio(struct file *file, void *priv,
369 struct v4l2_audio *a)
370{
371 return a->index ? -EINVAL : 0;
372}
403 373
404static int zoltrix_exclusive_open(struct file *file) 374static int zoltrix_open(struct file *file)
405{ 375{
406 return test_and_set_bit(0, &zoltrix_unit.in_use) ? -EBUSY : 0; 376 return 0;
407} 377}
408 378
409static int zoltrix_exclusive_release(struct file *file) 379static int zoltrix_release(struct file *file)
410{ 380{
411 clear_bit(0, &zoltrix_unit.in_use);
412 return 0; 381 return 0;
413} 382}
414 383
415static const struct v4l2_file_operations zoltrix_fops = 384static const struct v4l2_file_operations zoltrix_fops =
416{ 385{
417 .owner = THIS_MODULE, 386 .owner = THIS_MODULE,
418 .open = zoltrix_exclusive_open, 387 .open = zoltrix_open,
419 .release = zoltrix_exclusive_release, 388 .release = zoltrix_release,
420 .ioctl = video_ioctl2, 389 .ioctl = video_ioctl2,
421}; 390};
422 391
@@ -435,67 +404,75 @@ static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = {
435 .vidioc_s_ctrl = vidioc_s_ctrl, 404 .vidioc_s_ctrl = vidioc_s_ctrl,
436}; 405};
437 406
438static struct video_device zoltrix_radio = {
439 .name = "Zoltrix Radio Plus",
440 .fops = &zoltrix_fops,
441 .ioctl_ops = &zoltrix_ioctl_ops,
442 .release = video_device_release_empty,
443};
444
445static int __init zoltrix_init(void) 407static int __init zoltrix_init(void)
446{ 408{
447 if (io == -1) { 409 struct zoltrix *zol = &zoltrix_card;
448 printk(KERN_ERR "You must set an I/O address with io=0x???\n"); 410 struct v4l2_device *v4l2_dev = &zol->v4l2_dev;
411 int res;
412
413 strlcpy(v4l2_dev->name, "zoltrix", sizeof(v4l2_dev->name));
414 zol->io = io;
415 if (zol->io == -1) {
416 v4l2_err(v4l2_dev, "You must set an I/O address with io=0x???\n");
449 return -EINVAL; 417 return -EINVAL;
450 } 418 }
451 if ((io != 0x20c) && (io != 0x30c)) { 419 if (zol->io != 0x20c && zol->io != 0x30c) {
452 printk(KERN_ERR "zoltrix: invalid port, try 0x20c or 0x30c\n"); 420 v4l2_err(v4l2_dev, "invalid port, try 0x20c or 0x30c\n");
453 return -ENXIO; 421 return -ENXIO;
454 } 422 }
455 423
456 video_set_drvdata(&zoltrix_radio, &zoltrix_unit); 424 if (!request_region(zol->io, 2, "zoltrix")) {
457 if (!request_region(io, 2, "zoltrix")) { 425 v4l2_err(v4l2_dev, "port 0x%x already in use\n", zol->io);
458 printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io);
459 return -EBUSY; 426 return -EBUSY;
460 } 427 }
461 428
462 if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO, radio_nr) < 0) { 429 res = v4l2_device_register(NULL, v4l2_dev);
463 release_region(io, 2); 430 if (res < 0) {
431 release_region(zol->io, 2);
432 v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
433 return res;
434 }
435
436 strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name));
437 zol->vdev.v4l2_dev = v4l2_dev;
438 zol->vdev.fops = &zoltrix_fops;
439 zol->vdev.ioctl_ops = &zoltrix_ioctl_ops;
440 zol->vdev.release = video_device_release_empty;
441 video_set_drvdata(&zol->vdev, zol);
442
443 if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
444 v4l2_device_unregister(v4l2_dev);
445 release_region(zol->io, 2);
464 return -EINVAL; 446 return -EINVAL;
465 } 447 }
466 printk(KERN_INFO "Zoltrix Radio Plus card driver.\n"); 448 v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n");
467 449
468 mutex_init(&zoltrix_unit.lock); 450 mutex_init(&zol->lock);
469 451
470 /* mute card - prevents noisy bootups */ 452 /* mute card - prevents noisy bootups */
471 453
472 /* this ensures that the volume is all the way down */ 454 /* this ensures that the volume is all the way down */
473 455
474 outb(0, io); 456 outb(0, zol->io);
475 outb(0, io); 457 outb(0, zol->io);
476 msleep(20); 458 msleep(20);
477 inb(io + 3); 459 inb(zol->io + 3);
478 460
479 zoltrix_unit.curvol = 0; 461 zol->curvol = 0;
480 zoltrix_unit.stereo = 1; 462 zol->stereo = 1;
481 463
482 return 0; 464 return 0;
483} 465}
484 466
485MODULE_AUTHOR("C.van Schaik"); 467static void __exit zoltrix_exit(void)
486MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus.");
487MODULE_LICENSE("GPL");
488
489module_param(io, int, 0);
490MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)");
491module_param(radio_nr, int, 0);
492
493static void __exit zoltrix_cleanup_module(void)
494{ 468{
495 video_unregister_device(&zoltrix_radio); 469 struct zoltrix *zol = &zoltrix_card;
496 release_region(io, 2); 470
471 video_unregister_device(&zol->vdev);
472 v4l2_device_unregister(&zol->v4l2_dev);
473 release_region(zol->io, 2);
497} 474}
498 475
499module_init(zoltrix_init); 476module_init(zoltrix_init);
500module_exit(zoltrix_cleanup_module); 477module_exit(zoltrix_exit);
501 478