aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorPekka Seppanen <pexu@kapsi.fi>2007-09-30 23:27:55 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-10-09 21:14:50 -0400
commit4753647e6422341a091e729b9d81a9a5e7fe6179 (patch)
tree229138baa48559eca0907917387c12cb123cd0fa /drivers/media
parent3e7589c50771aa0f6eaa8de799e599c016f4029c (diff)
V4L/DVB (6244): [PATCH 1/2] GemTek Radio card
Code cleanup for GemTek Radio card driver. Removed unnecessary / invalid I/O commands and rewrote code for tuning on-board BU2614FS chip. Adds several new module params for power users. Includes automatic device probing. Signed-off-by: Pekka Seppanen <pexu@kapsi.fi> Signed-off-by: Douglas Schilling Landgraf <dougsland@gmail.com> Reviewed-by: Trent Piepho <xyzzy@speakeasy.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/radio/radio-gemtek.c651
1 files changed, 462 insertions, 189 deletions
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index eab8c80a2e47..f959bb71c460 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -26,143 +26,413 @@
26#include <media/v4l2-common.h> 26#include <media/v4l2-common.h>
27#include <linux/spinlock.h> 27#include <linux/spinlock.h>
28 28
29#include <linux/version.h> /* for KERNEL_VERSION MACRO */ 29#include <linux/version.h> /* for KERNEL_VERSION MACRO */
30#define RADIO_VERSION KERNEL_VERSION(0,0,2) 30#define RADIO_VERSION KERNEL_VERSION(0,0,3)
31#define RADIO_BANNER "GemTek Radio card driver: v0.0.3"
31 32
32static struct v4l2_queryctrl radio_qctrl[] = { 33/*
33 { 34 * Module info.
34 .id = V4L2_CID_AUDIO_MUTE, 35 */
35 .name = "Mute", 36
36 .minimum = 0, 37MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen <pexu@kapsi.fi>");
37 .maximum = 1, 38MODULE_DESCRIPTION("A driver for the GemTek Radio card.");
38 .default_value = 1, 39MODULE_LICENSE("GPL");
39 .type = V4L2_CTRL_TYPE_BOOLEAN, 40
40 },{ 41/*
41 .id = V4L2_CID_AUDIO_VOLUME, 42 * Module params.
42 .name = "Volume", 43 */
43 .minimum = 0,
44 .maximum = 65535,
45 .step = 65535,
46 .default_value = 0xff,
47 .type = V4L2_CTRL_TYPE_INTEGER,
48 }
49};
50 44
51#ifndef CONFIG_RADIO_GEMTEK_PORT 45#ifndef CONFIG_RADIO_GEMTEK_PORT
52#define CONFIG_RADIO_GEMTEK_PORT -1 46#define CONFIG_RADIO_GEMTEK_PORT -1
53#endif 47#endif
48#ifndef CONFIG_RADIO_GEMTEK_PROBE
49#define CONFIG_RADIO_GEMTEK_PROBE 1
50#endif
54 51
55static int io = CONFIG_RADIO_GEMTEK_PORT; 52static int io = CONFIG_RADIO_GEMTEK_PORT;
56static int radio_nr = -1; 53static int probe = CONFIG_RADIO_GEMTEK_PROBE;
57static spinlock_t lock; 54static int hardmute;
55static int shutdown = 1;
56static int keepmuted = 1;
57static int initmute = 1;
58static int radio_nr = -1;
58 59
59struct gemtek_device 60module_param(io, int, 0444);
60{ 61MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic"
61 int port; 62 "probing is disabled or fails. The most common I/O ports are: 0x20c "
62 unsigned long curfreq; 63 "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to "
64 " work for the combined sound/radiocard).");
65
66module_param(probe, bool, 0444);
67MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most "
68 "common I/O ports used by the card are probed.");
69
70module_param(hardmute, bool, 0644);
71MODULE_PARM_DESC(hardmute, "Enable `hard muting' by shutting down PLL, may "
72 "reduce static noise.");
73
74module_param(shutdown, bool, 0644);
75MODULE_PARM_DESC(shutdown, "Enable shutting down PLL and muting line when "
76 "module is unloaded.");
77
78module_param(keepmuted, bool, 0644);
79MODULE_PARM_DESC(keepmuted, "Keep card muted even when frequency is changed.");
80
81module_param(initmute, bool, 0444);
82MODULE_PARM_DESC(initmute, "Mute card when module is loaded.");
83
84module_param(radio_nr, int, 0444);
85
86/*
87 * Functions for controlling the card.
88 */
89#define GEMTEK_LOWFREQ (87*16000)
90#define GEMTEK_HIGHFREQ (108*16000)
91
92#define GEMTEK_CK 0x01 /* Clock signal */
93#define GEMTEK_DA 0x02 /* Serial data */
94#define GEMTEK_CE 0x04 /* Chip enable */
95#define GEMTEK_NS 0x08 /* No signal */
96#define GEMTEK_MT 0x10 /* Line mute */
97#define GEMTEK_STDF_3_125_KHZ 0x01 /* Standard frequency 3.125 kHz */
98#define GEMTEK_PLL_OFF 0x07 /* PLL off */
99
100#define BU2614_BUS_SIZE 32 /* BU2614 / BU2614FS bus size */
101#define BU2614_NOPS 8 /* Number of supported operations */
102
103#define SHORT_DELAY 5 /* usec */
104#define LONG_DELAY 75 /* usec */
105
106struct gemtek_device {
107 unsigned long lastfreq;
63 int muted; 108 int muted;
109 unsigned long bu2614data[BU2614_NOPS];
64}; 110};
65 111
112enum {
113 BU2614_VOID,
114 BU2614_FREQ, /* D0..D15, Frequency data */
115 BU2614_PORT, /* P0..P2, Output port control data */
116 BU2614_FMES, /* CT, Frequency measurement beginning data */
117 BU2614_STDF, /* R0..R2, Standard frequency data */
118 BU2614_SWIN, /* S, Switch between FMIN / AMIN */
119 BU2614_SWAL, /* PS, Swallow counter division (AMIN only) */
120 BU2614_FMUN, /* GT, Frequency measurement time and unlock */
121 BU2614_TEST /* TS, Test data is input */
122};
123
124struct bu2614_op {
125 int op; /* Operation */
126 int size; /* Data size */
127};
128
129static struct gemtek_device gemtek_unit;
130
131static struct bu2614_op bu2614ops[] = {
132 {.op = BU2614_FREQ,
133 .size = 0x10},
134 {.op = BU2614_PORT,
135 .size = 0x03},
136 {.op = BU2614_VOID,
137 .size = 0x04},
138 {.op = BU2614_FMES,
139 .size = 0x01},
140 {.op = BU2614_STDF,
141 .size = 0x03},
142 {.op = BU2614_SWIN,
143 .size = 0x01},
144 {.op = BU2614_SWAL,
145 .size = 0x01},
146 {.op = BU2614_VOID,
147 .size = 0x01},
148 {.op = BU2614_FMUN,
149 .size = 0x01},
150 {.op = BU2614_TEST,
151 .size = 0x01}
152};
66 153
67/* local things */ 154static spinlock_t lock;
68 155
69/* the correct way to mute the gemtek may be to write the last written 156/*
70 * frequency || 0x10, but just writing 0x10 once seems to do it as well 157 * Set data which will be sent to BU2614FS.
71 */ 158 */
72static void gemtek_mute(struct gemtek_device *dev) 159static void gemtek_bu2614_set(struct gemtek_device *dev, int op,
160 unsigned long data)
73{ 161{
74 if(dev->muted) 162 int i, q;
75 return; 163
164 for (i = 0, q = 0; q < ARRAY_SIZE(dev->bu2614data); ++i) {
165 if (bu2614ops[i].op == op) {
166 dev->bu2614data[q] =
167 data & ((1 << bu2614ops[i].size) - 1);
168 return;
169 }
170
171 if (bu2614ops[i].op != BU2614_VOID)
172 ++q;
173 }
174}
175
176/*
177 * Transmit settings to BU2614FS over GemTek IC.
178 */
179static void gemtek_bu2614_transmit(struct gemtek_device *dev)
180{
181 int i, bit, q, mute;
182
76 spin_lock(&lock); 183 spin_lock(&lock);
77 outb(0x10, io); 184
185 mute = dev->muted ? GEMTEK_MT : 0x00;
186
187 outb_p(mute | GEMTEK_DA | GEMTEK_CK, io);
188 udelay(SHORT_DELAY);
189 outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io);
190 udelay(LONG_DELAY);
191
192 for (i = 0, q = 0; q < ARRAY_SIZE(dev->bu2614data); ++i) {
193 for (bit = 0; bit < bu2614ops[i].size; ++bit) {
194 if (bu2614ops[i].op != BU2614_VOID &&
195 dev->bu2614data[q] & (1 << bit)) {
196 outb_p(mute | GEMTEK_CE | GEMTEK_DA, io);
197 udelay(SHORT_DELAY);
198 outb_p(mute | GEMTEK_CE | GEMTEK_DA |
199 GEMTEK_CK, io);
200 udelay(SHORT_DELAY);
201 } else {
202 outb_p(mute | GEMTEK_CE, io);
203 udelay(SHORT_DELAY);
204 outb_p(mute | GEMTEK_CE | GEMTEK_CK, io);
205 udelay(SHORT_DELAY);
206 }
207 }
208
209 if (bu2614ops[i].op != BU2614_VOID)
210 ++q;
211 }
212
213 outb_p(mute | GEMTEK_DA | GEMTEK_CK, io);
214 udelay(SHORT_DELAY);
215 outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io);
216 udelay(LONG_DELAY);
217
78 spin_unlock(&lock); 218 spin_unlock(&lock);
79 dev->muted = 1;
80} 219}
81 220
82static void gemtek_unmute(struct gemtek_device *dev) 221/*
222 * Convert FM-frequency for BU2614FS (3.125 KHz STDF expected).
223 */
224static inline void gemtek_convfreq(unsigned long *freq)
83{ 225{
84 if(dev->muted == 0) 226 (*freq) /= 160;
227 (*freq) += 1052; /* FMIN, 10.52 MHz */
228 (*freq) *= 1565; /* STDF, 1 / 156.5 = 0.00639 */
229 (*freq) /= 1000;
230}
231
232/*
233 * Set FM-frequency.
234 */
235static void gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
236{
237
238 if (keepmuted && hardmute && dev->muted)
85 return; 239 return;
86 spin_lock(&lock); 240
87 outb(0x20, io); 241 if (freq < GEMTEK_LOWFREQ)
88 spin_unlock(&lock); 242 freq = GEMTEK_LOWFREQ;
243 else if (freq > GEMTEK_HIGHFREQ)
244 freq = GEMTEK_HIGHFREQ;
245
246 dev->lastfreq = freq;
89 dev->muted = 0; 247 dev->muted = 0;
248
249 gemtek_bu2614_set(dev, BU2614_PORT, 0);
250 gemtek_bu2614_set(dev, BU2614_FMES, 0);
251 gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode */
252 gemtek_bu2614_set(dev, BU2614_SWAL, 0);
253 gemtek_bu2614_set(dev, BU2614_FMUN, 1); /* GT bit set */
254 gemtek_bu2614_set(dev, BU2614_TEST, 0);
255
256 gemtek_convfreq(&freq);
257
258 gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_STDF_3_125_KHZ);
259 gemtek_bu2614_set(dev, BU2614_FREQ, freq);
260
261 gemtek_bu2614_transmit(dev);
90} 262}
91 263
92static void zero(void) 264/*
265 * Set mute flag.
266 */
267static void gemtek_mute(struct gemtek_device *dev)
93{ 268{
94 outb_p(0x04, io); 269 int i;
95 udelay(5); 270 dev->muted = 1;
96 outb_p(0x05, io); 271
97 udelay(5); 272 if (hardmute) {
273 /* Turn off PLL, disable data output */
274 gemtek_bu2614_set(dev, BU2614_PORT, 0);
275 gemtek_bu2614_set(dev, BU2614_FMES, 0); /* CT bit off */
276 gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode */
277 gemtek_bu2614_set(dev, BU2614_SWAL, 0);
278 gemtek_bu2614_set(dev, BU2614_FMUN, 0); /* GT bit off */
279 gemtek_bu2614_set(dev, BU2614_TEST, 0);
280 gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_PLL_OFF);
281 gemtek_bu2614_set(dev, BU2614_FREQ, 0);
282 gemtek_bu2614_transmit(dev);
283 } else {
284 spin_lock(&lock);
285
286 /* Read bus contents (CE, CK and DA). */
287 i = inb_p(io);
288 /* Write it back with mute flag set. */
289 outb_p((i >> 5) | GEMTEK_MT, io);
290 udelay(SHORT_DELAY);
291
292 spin_unlock(&lock);
293 }
98} 294}
99 295
100static void one(void) 296/*
297 * Unset mute flag.
298 */
299static void gemtek_unmute(struct gemtek_device *dev)
101{ 300{
102 outb_p(0x06, io); 301 int i;
103 udelay(5); 302 dev->muted = 0;
104 outb_p(0x07, io); 303
105 udelay(5); 304 if (hardmute) {
305 /* Turn PLL back on. */
306 gemtek_setfreq(dev, dev->lastfreq);
307 } else {
308 spin_lock(&lock);
309
310 i = inb_p(io);
311 outb_p(i >> 5, io);
312 udelay(SHORT_DELAY);
313
314 spin_unlock(&lock);
315 }
106} 316}
107 317
108static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq) 318/*
319 * Get signal strength (= stereo status).
320 */
321static inline int gemtek_getsigstr(void)
109{ 322{
110 int i; 323 return inb_p(io) & GEMTEK_NS ? 0 : 1;
324}
111 325
112/* freq = 78.25*((float)freq/16000.0 + 10.52); */ 326/*
327 * Check if requested card acts like GemTek Radio card.
328 */
329static int gemtek_verify(int port)
330{
331 static int verified = -1;
332 int i, q;
113 333
114 freq /= 16; 334 if (verified == port)
115 freq += 10520; 335 return 1;
116 freq *= 7825;
117 freq /= 100000;
118 336
119 spin_lock(&lock); 337 spin_lock(&lock);
120 338
121 /* 2 start bits */ 339 q = inb_p(port); /* Read bus contents before probing. */
122 outb_p(0x03, io); 340 /* Try to turn on CE, CK and DA respectively and check if card responds
123 udelay(5); 341 properly. */
124 outb_p(0x07, io); 342 for (i = 0; i < 3; ++i) {
125 udelay(5); 343 outb_p(1 << i, port);
344 udelay(SHORT_DELAY);
126 345
127 /* 28 frequency bits (lsb first) */ 346 if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) {
128 for (i = 0; i < 14; i++) 347 spin_unlock(&lock);
129 if (freq & (1 << i)) 348 return 0;
130 one(); 349 }
131 else 350 }
132 zero(); 351 outb_p(q >> 5, port); /* Write bus contents back. */
133 /* 36 unknown bits */ 352 udelay(SHORT_DELAY);
134 for (i = 0; i < 11; i++)
135 zero();
136 one();
137 for (i = 0; i < 4; i++)
138 zero();
139 one();
140 zero();
141
142 /* 2 end bits */
143 outb_p(0x03, io);
144 udelay(5);
145 outb_p(0x07, io);
146 udelay(5);
147 353
148 spin_unlock(&lock); 354 spin_unlock(&lock);
355 verified = port;
149 356
150 return 0; 357 return 1;
151} 358}
152 359
153static int gemtek_getsigstr(struct gemtek_device *dev) 360/*
361 * Automatic probing for card.
362 */
363static int gemtek_probe(void)
154{ 364{
155 spin_lock(&lock); 365 int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c };
156 inb(io); 366 int i;
157 udelay(5); 367
158 spin_unlock(&lock); 368 if (!probe) {
159 if (inb(io) & 8) /* bit set = no signal present */ 369 printk(KERN_INFO "Automatic device probing disabled.\n");
160 return 0; 370 return -1;
161 return 1; /* signal present */ 371 }
372
373 printk(KERN_INFO "Automatic device probing enabled.\n");
374
375 for (i = 0; i < ARRAY_SIZE(ioports); ++i) {
376 printk(KERN_INFO "Trying I/O port 0x%x...\n", ioports[i]);
377
378 if (!request_region(ioports[i], 1, "gemtek-probe")) {
379 printk(KERN_WARNING "I/O port 0x%x busy!\n",
380 ioports[i]);
381 continue;
382 }
383
384 if (gemtek_verify(ioports[i])) {
385 printk(KERN_INFO "Card found from I/O port "
386 "0x%x!\n", ioports[i]);
387
388 release_region(ioports[i], 1);
389
390 io = ioports[i];
391 return io;
392 }
393
394 release_region(ioports[i], 1);
395 }
396
397 printk(KERN_ERR "Automatic probing failed!\n");
398
399 return -1;
162} 400}
163 401
164static int vidioc_querycap(struct file *file, void *priv, 402/*
165 struct v4l2_capability *v) 403 * Video 4 Linux stuff.
404 */
405
406static struct v4l2_queryctrl radio_qctrl[] = {
407 {
408 .id = V4L2_CID_AUDIO_MUTE,
409 .name = "Mute",
410 .minimum = 0,
411 .maximum = 1,
412 .default_value = 1,
413 .type = V4L2_CTRL_TYPE_BOOLEAN,
414 }, {
415 .id = V4L2_CID_AUDIO_VOLUME,
416 .name = "Volume",
417 .minimum = 0,
418 .maximum = 65535,
419 .step = 65535,
420 .default_value = 0xff,
421 .type = V4L2_CTRL_TYPE_INTEGER,
422 }
423};
424
425static struct file_operations gemtek_fops = {
426 .owner = THIS_MODULE,
427 .open = video_exclusive_open,
428 .release = video_exclusive_release,
429 .ioctl = video_ioctl2,
430 .compat_ioctl = v4l_compat_ioctl32,
431 .llseek = no_llseek
432};
433
434static int vidioc_querycap(struct file *file, void *priv,
435 struct v4l2_capability *v)
166{ 436{
167 strlcpy(v->driver, "radio-gemtek", sizeof(v->driver)); 437 strlcpy(v->driver, "radio-gemtek", sizeof(v->driver));
168 strlcpy(v->card, "GemTek", sizeof(v->card)); 438 strlcpy(v->card, "GemTek", sizeof(v->card));
@@ -172,28 +442,29 @@ static int vidioc_querycap(struct file *file, void *priv,
172 return 0; 442 return 0;
173} 443}
174 444
175static int vidioc_g_tuner(struct file *file, void *priv, 445static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
176 struct v4l2_tuner *v)
177{ 446{
178 struct video_device *dev = video_devdata(file);
179 struct gemtek_device *rt = dev->priv;
180
181 if (v->index > 0) 447 if (v->index > 0)
182 return -EINVAL; 448 return -EINVAL;
183 449
184 strcpy(v->name, "FM"); 450 strcpy(v->name, "FM");
185 v->type = V4L2_TUNER_RADIO; 451 v->type = V4L2_TUNER_RADIO;
186 v->rangelow = (87*16000); 452 v->rangelow = GEMTEK_LOWFREQ;
187 v->rangehigh = (108*16000); 453 v->rangehigh = GEMTEK_HIGHFREQ;
188 v->rxsubchans = V4L2_TUNER_SUB_MONO; 454 v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
189 v->capability = V4L2_TUNER_CAP_LOW; 455 v->signal = 0xffff * gemtek_getsigstr();
190 v->audmode = V4L2_TUNER_MODE_MONO; 456 if (v->signal) {
191 v->signal = 0xffff*gemtek_getsigstr(rt); 457 v->audmode = V4L2_TUNER_MODE_STEREO;
458 v->rxsubchans = V4L2_TUNER_SUB_STEREO;
459 } else {
460 v->audmode = V4L2_TUNER_MODE_MONO;
461 v->rxsubchans = V4L2_TUNER_SUB_MONO;
462 }
463
192 return 0; 464 return 0;
193} 465}
194 466
195static int vidioc_s_tuner(struct file *file, void *priv, 467static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
196 struct v4l2_tuner *v)
197{ 468{
198 if (v->index > 0) 469 if (v->index > 0)
199 return -EINVAL; 470 return -EINVAL;
@@ -201,38 +472,35 @@ static int vidioc_s_tuner(struct file *file, void *priv,
201} 472}
202 473
203static int vidioc_s_frequency(struct file *file, void *priv, 474static int vidioc_s_frequency(struct file *file, void *priv,
204 struct v4l2_frequency *f) 475 struct v4l2_frequency *f)
205{ 476{
206 struct video_device *dev = video_devdata(file); 477 struct video_device *dev = video_devdata(file);
207 struct gemtek_device *rt = dev->priv; 478 struct gemtek_device *rt = dev->priv;
208 479
209 rt->curfreq = f->frequency; 480 gemtek_setfreq(rt, f->frequency);
210 /* needs to be called twice in order for getsigstr to work */ 481
211 gemtek_setfreq(rt, rt->curfreq);
212 gemtek_setfreq(rt, rt->curfreq);
213 return 0; 482 return 0;
214} 483}
215 484
216static int vidioc_g_frequency(struct file *file, void *priv, 485static int vidioc_g_frequency(struct file *file, void *priv,
217 struct v4l2_frequency *f) 486 struct v4l2_frequency *f)
218{ 487{
219 struct video_device *dev = video_devdata(file); 488 struct video_device *dev = video_devdata(file);
220 struct gemtek_device *rt = dev->priv; 489 struct gemtek_device *rt = dev->priv;
221 490
222 f->type = V4L2_TUNER_RADIO; 491 f->type = V4L2_TUNER_RADIO;
223 f->frequency = rt->curfreq; 492 f->frequency = rt->lastfreq;
224 return 0; 493 return 0;
225} 494}
226 495
227static int vidioc_queryctrl(struct file *file, void *priv, 496static int vidioc_queryctrl(struct file *file, void *priv,
228 struct v4l2_queryctrl *qc) 497 struct v4l2_queryctrl *qc)
229{ 498{
230 int i; 499 int i;
231 500
232 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { 501 for (i = 0; i < ARRAY_SIZE(radio_qctrl); ++i) {
233 if (qc->id && qc->id == radio_qctrl[i].id) { 502 if (qc->id && qc->id == radio_qctrl[i].id) {
234 memcpy(qc, &(radio_qctrl[i]), 503 memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
235 sizeof(*qc));
236 return 0; 504 return 0;
237 } 505 }
238 } 506 }
@@ -240,7 +508,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
240} 508}
241 509
242static int vidioc_g_ctrl(struct file *file, void *priv, 510static int vidioc_g_ctrl(struct file *file, void *priv,
243 struct v4l2_control *ctrl) 511 struct v4l2_control *ctrl)
244{ 512{
245 struct video_device *dev = video_devdata(file); 513 struct video_device *dev = video_devdata(file);
246 struct gemtek_device *rt = dev->priv; 514 struct gemtek_device *rt = dev->priv;
@@ -260,7 +528,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
260} 528}
261 529
262static int vidioc_s_ctrl(struct file *file, void *priv, 530static int vidioc_s_ctrl(struct file *file, void *priv,
263 struct v4l2_control *ctrl) 531 struct v4l2_control *ctrl)
264{ 532{
265 struct video_device *dev = video_devdata(file); 533 struct video_device *dev = video_devdata(file);
266 struct gemtek_device *rt = dev->priv; 534 struct gemtek_device *rt = dev->priv;
@@ -282,8 +550,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
282 return -EINVAL; 550 return -EINVAL;
283} 551}
284 552
285static int vidioc_g_audio (struct file *file, void *priv, 553static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
286 struct v4l2_audio *a)
287{ 554{
288 if (a->index > 1) 555 if (a->index > 1)
289 return -EINVAL; 556 return -EINVAL;
@@ -306,99 +573,105 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
306 return 0; 573 return 0;
307} 574}
308 575
309static int vidioc_s_audio(struct file *file, void *priv, 576static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
310 struct v4l2_audio *a)
311{ 577{
312 if (a->index != 0) 578 if (a->index != 0)
313 return -EINVAL; 579 return -EINVAL;
314 return 0; 580 return 0;
315} 581}
316 582
317static struct gemtek_device gemtek_unit; 583static struct video_device gemtek_radio = {
318 584 .owner = THIS_MODULE,
319static const struct file_operations gemtek_fops = { 585 .name = "GemTek Radio card",
320 .owner = THIS_MODULE, 586 .type = VID_TYPE_TUNER,
321 .open = video_exclusive_open, 587 .hardware = VID_HARDWARE_GEMTEK,
322 .release = video_exclusive_release, 588 .fops = &gemtek_fops,
323 .ioctl = video_ioctl2, 589 .vidioc_querycap = vidioc_querycap,
324 .compat_ioctl = v4l_compat_ioctl32, 590 .vidioc_g_tuner = vidioc_g_tuner,
325 .llseek = no_llseek, 591 .vidioc_s_tuner = vidioc_s_tuner,
592 .vidioc_g_audio = vidioc_g_audio,
593 .vidioc_s_audio = vidioc_s_audio,
594 .vidioc_g_input = vidioc_g_input,
595 .vidioc_s_input = vidioc_s_input,
596 .vidioc_g_frequency = vidioc_g_frequency,
597 .vidioc_s_frequency = vidioc_s_frequency,
598 .vidioc_queryctrl = vidioc_queryctrl,
599 .vidioc_g_ctrl = vidioc_g_ctrl,
600 .vidioc_s_ctrl = vidioc_s_ctrl
326}; 601};
327 602
328static struct video_device gemtek_radio= 603/*
329{ 604 * Initialization / cleanup related stuff.
330 .owner = THIS_MODULE, 605 */
331 .name = "GemTek radio",
332 .type = VID_TYPE_TUNER,
333 .fops = &gemtek_fops,
334 .vidioc_querycap = vidioc_querycap,
335 .vidioc_g_tuner = vidioc_g_tuner,
336 .vidioc_s_tuner = vidioc_s_tuner,
337 .vidioc_g_audio = vidioc_g_audio,
338 .vidioc_s_audio = vidioc_s_audio,
339 .vidioc_g_input = vidioc_g_input,
340 .vidioc_s_input = vidioc_s_input,
341 .vidioc_g_frequency = vidioc_g_frequency,
342 .vidioc_s_frequency = vidioc_s_frequency,
343 .vidioc_queryctrl = vidioc_queryctrl,
344 .vidioc_g_ctrl = vidioc_g_ctrl,
345 .vidioc_s_ctrl = vidioc_s_ctrl,
346};
347 606
607/*
608 * Initilize card.
609 */
348static int __init gemtek_init(void) 610static int __init gemtek_init(void)
349{ 611{
350 if(io==-1) 612 int i;
351 {
352 printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (io=0x020c or io=0x248 for the combined sound/radiocard)\n");
353 return -EINVAL;
354 }
355 613
356 if (!request_region(io, 4, "gemtek")) 614 printk(KERN_INFO RADIO_BANNER "\n");
357 {
358 printk(KERN_ERR "gemtek: port 0x%x already in use\n", io);
359 return -EBUSY;
360 }
361 615
362 gemtek_radio.priv=&gemtek_unit; 616 spin_lock_init(&lock);
363 617
364 if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr)==-1) 618 gemtek_probe();
365 { 619 if (io) {
366 release_region(io, 4); 620 if (!request_region(io, 1, "gemtek")) {
621 printk(KERN_ERR "I/O port 0x%x already in use.\n", io);
622 return -EBUSY;
623 }
624
625 if (!gemtek_verify(io))
626 printk(KERN_WARNING "Card at I/O port 0x%x does not "
627 "respond properly, check your "
628 "configuration.\n", io);
629 else
630 printk(KERN_INFO "Using I/O port 0x%x.\n", io);
631 } else if (probe) {
632 printk(KERN_ERR "Automatic probing failed and no "
633 "fixed I/O port defined.\n");
634 return -ENODEV;
635 } else {
636 printk(KERN_ERR "Automatic probing disabled but no fixed "
637 "I/O port defined.");
367 return -EINVAL; 638 return -EINVAL;
368 } 639 }
369 printk(KERN_INFO "GemTek Radio Card driver.\n");
370 640
371 spin_lock_init(&lock); 641 gemtek_radio.priv = &gemtek_unit;
642
643 if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO,
644 radio_nr) == -1) {
645 release_region(io, 1);
646 return -EBUSY;
647 }
372 648
373 /* this is _maybe_ unnecessary */ 649 /* Set defaults */
374 outb(0x01, io); 650 gemtek_unit.lastfreq = GEMTEK_LOWFREQ;
651 for (i = 0; i < ARRAY_SIZE(gemtek_unit.bu2614data); ++i)
652 gemtek_unit.bu2614data[i] = 0;
375 653
376 /* mute card - prevents noisy bootups */ 654 if (initmute)
377 gemtek_unit.muted = 0; 655 gemtek_mute(&gemtek_unit);
378 gemtek_mute(&gemtek_unit);
379 656
380 return 0; 657 return 0;
381} 658}
382 659
383MODULE_AUTHOR("Jonas Munsin"); 660/*
384MODULE_DESCRIPTION("A driver for the GemTek Radio Card"); 661 * Module cleanup
385MODULE_LICENSE("GPL"); 662 */
386 663static void __exit gemtek_exit(void)
387module_param(io, int, 0);
388MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (0x20c or 0x248 have been reported to work for the combined sound/radiocard)).");
389module_param(radio_nr, int, 0);
390
391static void __exit gemtek_cleanup(void)
392{ 664{
665 if (shutdown) {
666 hardmute = 1; /* Turn off PLL */
667 gemtek_mute(&gemtek_unit);
668 } else {
669 printk(KERN_INFO "Module unloaded but card not muted!\n");
670 }
671
393 video_unregister_device(&gemtek_radio); 672 video_unregister_device(&gemtek_radio);
394 release_region(io,4); 673 release_region(io, 1);
395} 674}
396 675
397module_init(gemtek_init); 676module_init(gemtek_init);
398module_exit(gemtek_cleanup); 677module_exit(gemtek_exit);
399
400/*
401 Local variables:
402 compile-command: "gcc -c -DMODVERSIONS -D__KERNEL__ -DMODULE -O6 -Wall -Wstrict-prototypes -I /home/blp/tmp/linux-2.1.111-rtrack/include radio-rtrack2.c"
403 End:
404*/