aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/radio/radio-maxiradio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/radio/radio-maxiradio.c')
-rw-r--r--drivers/media/radio/radio-maxiradio.c354
1 files changed, 217 insertions, 137 deletions
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index 6beeb74004b1..8e184cfc1c94 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -27,7 +27,9 @@
27 * BUGS: 27 * BUGS:
28 * - card unmutes if you change frequency 28 * - card unmutes if you change frequency
29 * 29 *
30 * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> 30 * (c) 2006, 2007 by Mauro Carvalho Chehab <mchehab@infradead.org>:
31 * - Conversion to V4L2 API
32 * - Uses video_ioctl2 for parsing and to add debug support
31 */ 33 */
32 34
33 35
@@ -43,10 +45,18 @@
43#include <linux/videodev2.h> 45#include <linux/videodev2.h>
44#include <media/v4l2-common.h> 46#include <media/v4l2-common.h>
45 47
46#define DRIVER_VERSION "0.76" 48#define DRIVER_VERSION "0.77"
47 49
48#include <linux/version.h> /* for KERNEL_VERSION MACRO */ 50#include <linux/version.h> /* for KERNEL_VERSION MACRO */
49#define RADIO_VERSION KERNEL_VERSION(0,7,6) 51#define RADIO_VERSION KERNEL_VERSION(0,7,7)
52
53static struct video_device maxiradio_radio;
54
55#define dprintk(num, fmt, arg...) \
56 do { \
57 if (maxiradio_radio.debug >= num) \
58 printk(KERN_DEBUG "%s: " fmt, \
59 maxiradio_radio.name, ## arg); } while (0)
50 60
51static struct v4l2_queryctrl radio_qctrl[] = { 61static struct v4l2_queryctrl radio_qctrl[] = {
52 { 62 {
@@ -81,30 +91,21 @@ module_param(radio_nr, int, 0);
81#define FREQ_IF 171200 /* 10.7*16000 */ 91#define FREQ_IF 171200 /* 10.7*16000 */
82#define FREQ_STEP 200 /* 12.5*16 */ 92#define FREQ_STEP 200 /* 12.5*16 */
83 93
84#define FREQ2BITS(x) ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\ 94/* (x==fmhz*16*1000) -> bits */
85 /(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */ 95#define FREQ2BITS(x) ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1)) \
96 /(FREQ_STEP<<2))<<2)
86 97
87#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) 98#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF)
88 99
89 100
90static int radio_ioctl(struct inode *inode, struct file *file,
91 unsigned int cmd, unsigned long arg);
92
93static const struct file_operations maxiradio_fops = { 101static const struct file_operations maxiradio_fops = {
94 .owner = THIS_MODULE, 102 .owner = THIS_MODULE,
95 .open = video_exclusive_open, 103 .open = video_exclusive_open,
96 .release = video_exclusive_release, 104 .release = video_exclusive_release,
97 .ioctl = radio_ioctl, 105 .ioctl = video_ioctl2,
98 .compat_ioctl = v4l_compat_ioctl32, 106 .compat_ioctl = v4l_compat_ioctl32,
99 .llseek = no_llseek, 107 .llseek = no_llseek,
100}; 108};
101static struct video_device maxiradio_radio =
102{
103 .owner = THIS_MODULE,
104 .name = "Maxi Radio FM2000 radio",
105 .type = VID_TYPE_TUNER,
106 .fops = &maxiradio_fops,
107};
108 109
109static struct radio_device 110static struct radio_device
110{ 111{
@@ -116,12 +117,14 @@ static struct radio_device
116 unsigned long freq; 117 unsigned long freq;
117 118
118 struct mutex lock; 119 struct mutex lock;
119} radio_unit = {0, 0, 0, 0, }; 120} radio_unit = {
120 121 .muted =1,
122 .freq = FREQ_LO,
123};
121 124
122static void outbit(unsigned long bit, __u16 io) 125static void outbit(unsigned long bit, __u16 io)
123{ 126{
124 if(bit != 0) 127 if (bit != 0)
125 { 128 {
126 outb( power|wren|data ,io); udelay(4); 129 outb( power|wren|data ,io); udelay(4);
127 outb( power|wren|data|clk ,io); udelay(4); 130 outb( power|wren|data|clk ,io); udelay(4);
@@ -137,14 +140,20 @@ static void outbit(unsigned long bit, __u16 io)
137 140
138static void turn_power(__u16 io, int p) 141static void turn_power(__u16 io, int p)
139{ 142{
140 if(p != 0) outb(power, io); else outb(0,io); 143 if (p != 0) {
144 dprintk(1, "Radio powered on\n");
145 outb(power, io);
146 } else {
147 dprintk(1, "Radio powered off\n");
148 outb(0,io);
149 }
141} 150}
142 151
143 152static void set_freq(__u16 io, __u32 freq)
144static void set_freq(__u16 io, __u32 data)
145{ 153{
146 unsigned long int si; 154 unsigned long int si;
147 int bl; 155 int bl;
156 int data = FREQ2BITS(freq);
148 157
149 /* TEA5757 shift register bits (see pdf) */ 158 /* TEA5757 shift register bits (see pdf) */
150 159
@@ -163,161 +172,225 @@ static void set_freq(__u16 io, __u32 data)
163 outbit(0,io); // 16 search level 172 outbit(0,io); // 16 search level
164 173
165 si = 0x8000; 174 si = 0x8000;
166 for(bl = 1; bl <= 16 ; bl++) { outbit(data & si,io); si >>=1; } 175 for (bl = 1; bl <= 16 ; bl++) {
176 outbit(data & si,io);
177 si >>=1;
178 }
167 179
168 outb(power,io); 180 dprintk(1, "Radio freq set to %d.%02d MHz\n",
181 freq / 16000,
182 freq % 16000 * 100 / 16000);
183
184 turn_power(io, 1);
169} 185}
170 186
171static int get_stereo(__u16 io) 187static int get_stereo(__u16 io)
172{ 188{
173 outb(power,io); udelay(4); 189 outb(power,io);
190 udelay(4);
191
174 return !(inb(io) & mo_st); 192 return !(inb(io) & mo_st);
175} 193}
176 194
177static int get_tune(__u16 io) 195static int get_tune(__u16 io)
178{ 196{
179 outb(power+clk,io); udelay(4); 197 outb(power+clk,io);
198 udelay(4);
199
180 return !(inb(io) & mo_st); 200 return !(inb(io) & mo_st);
181} 201}
182 202
183 203
184static inline int radio_function(struct inode *inode, struct file *file, 204static int vidioc_querycap (struct file *file, void *priv,
185 unsigned int cmd, void *arg) 205 struct v4l2_capability *v)
206{
207 strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver));
208 strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card));
209 sprintf(v->bus_info,"ISA");
210 v->version = RADIO_VERSION;
211 v->capabilities = V4L2_CAP_TUNER;
212
213 return 0;
214}
215
216static int vidioc_g_tuner (struct file *file, void *priv,
217 struct v4l2_tuner *v)
186{ 218{
187 struct video_device *dev = video_devdata(file); 219 struct video_device *dev = video_devdata(file);
188 struct radio_device *card=dev->priv; 220 struct radio_device *card=dev->priv;
189 221
190 switch(cmd) { 222 if (v->index > 0)
191 case VIDIOC_QUERYCAP: 223 return -EINVAL;
192 {
193 struct v4l2_capability *v = arg;
194 memset(v,0,sizeof(*v));
195 strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver));
196 strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card));
197 sprintf(v->bus_info,"ISA");
198 v->version = RADIO_VERSION;
199 v->capabilities = V4L2_CAP_TUNER;
200 224
201 return 0; 225 memset(v,0,sizeof(*v));
202 } 226 strcpy(v->name, "FM");
203 case VIDIOC_G_TUNER: 227 v->type = V4L2_TUNER_RADIO;
204 {
205 struct v4l2_tuner *v = arg;
206 228
207 if (v->index > 0) 229 v->rangelow=FREQ_LO;
208 return -EINVAL; 230 v->rangehigh=FREQ_HI;
231 v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
232 v->capability=V4L2_TUNER_CAP_LOW;
233 if(get_stereo(card->io))
234 v->audmode = V4L2_TUNER_MODE_STEREO;
235 else
236 v->audmode = V4L2_TUNER_MODE_MONO;
237 v->signal=0xffff*get_tune(card->io);
209 238
210 memset(v,0,sizeof(*v)); 239 return 0;
211 strcpy(v->name, "FM"); 240}
212 v->type = V4L2_TUNER_RADIO;
213 241
214 v->rangelow=FREQ_LO; 242static int vidioc_s_tuner (struct file *file, void *priv,
215 v->rangehigh=FREQ_HI; 243 struct v4l2_tuner *v)
216 v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; 244{
217 v->capability=V4L2_TUNER_CAP_LOW; 245 if (v->index > 0)
218 if(get_stereo(card->io)) 246 return -EINVAL;
219 v->audmode = V4L2_TUNER_MODE_STEREO;
220 else
221 v->audmode = V4L2_TUNER_MODE_MONO;
222 v->signal=0xffff*get_tune(card->io);
223 247
224 return 0; 248 return 0;
225 } 249}
226 case VIDIOC_S_TUNER:
227 {
228 struct v4l2_tuner *v = arg;
229 250
230 if (v->index > 0) 251static int vidioc_g_audio (struct file *file, void *priv,
231 return -EINVAL; 252 struct v4l2_audio *a)
253{
254 if (a->index > 1)
255 return -EINVAL;
232 256
233 return 0; 257 strcpy(a->name, "FM");
234 } 258 a->capability = V4L2_AUDCAP_STEREO;
235 case VIDIOC_S_FREQUENCY: 259 return 0;
236 { 260}
237 struct v4l2_frequency *f = arg;
238 261
239 if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) 262static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
240 return -EINVAL; 263{
264 *i = 0;
241 265
242 card->freq = f->frequency; 266 return 0;
243 set_freq(card->io, FREQ2BITS(card->freq)); 267}
244 msleep(125);
245 return 0;
246 }
247 case VIDIOC_G_FREQUENCY:
248 {
249 struct v4l2_frequency *f = arg;
250 268
251 f->type = V4L2_TUNER_RADIO; 269static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
252 f->frequency = card->freq; 270{
271 if (i != 0)
272 return -EINVAL;
253 273
254 return 0; 274 return 0;
255 } 275}
256 case VIDIOC_QUERYCTRL: 276
257 { 277
258 struct v4l2_queryctrl *qc = arg; 278static int vidioc_s_audio (struct file *file, void *priv,
259 int i; 279 struct v4l2_audio *a)
260 280{
261 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { 281 if (a->index != 0)
262 if (qc->id && qc->id == radio_qctrl[i].id) { 282 return -EINVAL;
263 memcpy(qc, &(radio_qctrl[i]), 283
264 sizeof(*qc)); 284 return 0;
265 return (0); 285}
266 } 286
267 } 287static int vidioc_s_frequency (struct file *file, void *priv,
268 return -EINVAL; 288 struct v4l2_frequency *f)
269 } 289{
270 case VIDIOC_G_CTRL: 290 struct video_device *dev = video_devdata(file);
271 { 291 struct radio_device *card=dev->priv;
272 struct v4l2_control *ctrl= arg;
273
274 switch (ctrl->id) {
275 case V4L2_CID_AUDIO_MUTE:
276 ctrl->value=card->muted;
277 return (0);
278 }
279 return -EINVAL;
280 }
281 case VIDIOC_S_CTRL:
282 {
283 struct v4l2_control *ctrl= arg;
284
285 switch (ctrl->id) {
286 case V4L2_CID_AUDIO_MUTE:
287 card->muted = ctrl->value;
288 if(card->muted)
289 turn_power(card->io, 0);
290 else
291 set_freq(card->io, FREQ2BITS(card->freq));
292 return 0;
293 }
294 return -EINVAL;
295 }
296 292
297 default: 293 if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) {
298 return v4l_compat_translate_ioctl(inode,file,cmd,arg, 294 dprintk(1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
299 radio_function); 295 f->frequency / 16000,
296 f->frequency % 16000 * 100 / 16000,
297 FREQ_LO / 16000, FREQ_HI / 16000);
300 298
299 return -EINVAL;
301 } 300 }
301
302 card->freq = f->frequency;
303 set_freq(card->io, card->freq);
304 msleep(125);
305
306 return 0;
302} 307}
303 308
304static int radio_ioctl(struct inode *inode, struct file *file, 309static int vidioc_g_frequency (struct file *file, void *priv,
305 unsigned int cmd, unsigned long arg) 310 struct v4l2_frequency *f)
306{ 311{
307 struct video_device *dev = video_devdata(file); 312 struct video_device *dev = video_devdata(file);
308 struct radio_device *card=dev->priv; 313 struct radio_device *card=dev->priv;
309 int ret;
310 314
311 mutex_lock(&card->lock); 315 f->type = V4L2_TUNER_RADIO;
312 ret = video_usercopy(inode, file, cmd, arg, radio_function); 316 f->frequency = card->freq;
313 mutex_unlock(&card->lock); 317
314 return ret; 318 dprintk(4, "radio freq is %d.%02d MHz",
319 f->frequency / 16000,
320 f->frequency % 16000 * 100 / 16000);
321
322 return 0;
315} 323}
316 324
317MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net"); 325static int vidioc_queryctrl (struct file *file, void *priv,
318MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio."); 326 struct v4l2_queryctrl *qc)
319MODULE_LICENSE("GPL"); 327{
328 int i;
320 329
330 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
331 if (qc->id && qc->id == radio_qctrl[i].id) {
332 memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
333 return (0);
334 }
335 }
336
337 return -EINVAL;
338}
339
340static int vidioc_g_ctrl (struct file *file, void *priv,
341 struct v4l2_control *ctrl)
342{
343 struct video_device *dev = video_devdata(file);
344 struct radio_device *card=dev->priv;
345
346 switch (ctrl->id) {
347 case V4L2_CID_AUDIO_MUTE:
348 ctrl->value=card->muted;
349 return (0);
350 }
351
352 return -EINVAL;
353}
354
355static int vidioc_s_ctrl (struct file *file, void *priv,
356 struct v4l2_control *ctrl)
357{
358 struct video_device *dev = video_devdata(file);
359 struct radio_device *card=dev->priv;
360
361 switch (ctrl->id) {
362 case V4L2_CID_AUDIO_MUTE:
363 card->muted = ctrl->value;
364 if(card->muted)
365 turn_power(card->io, 0);
366 else
367 set_freq(card->io, card->freq);
368 return 0;
369 }
370
371 return -EINVAL;
372}
373
374static struct video_device maxiradio_radio =
375{
376 .owner = THIS_MODULE,
377 .name = "Maxi Radio FM2000 radio",
378 .type = VID_TYPE_TUNER,
379 .fops = &maxiradio_fops,
380
381 .vidioc_querycap = vidioc_querycap,
382 .vidioc_g_tuner = vidioc_g_tuner,
383 .vidioc_s_tuner = vidioc_s_tuner,
384 .vidioc_g_audio = vidioc_g_audio,
385 .vidioc_s_audio = vidioc_s_audio,
386 .vidioc_g_input = vidioc_g_input,
387 .vidioc_s_input = vidioc_s_input,
388 .vidioc_g_frequency = vidioc_g_frequency,
389 .vidioc_s_frequency = vidioc_s_frequency,
390 .vidioc_queryctrl = vidioc_queryctrl,
391 .vidioc_g_ctrl = vidioc_g_ctrl,
392 .vidioc_s_ctrl = vidioc_s_ctrl,
393};
321 394
322static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 395static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
323{ 396{
@@ -334,7 +407,7 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d
334 mutex_init(&radio_unit.lock); 407 mutex_init(&radio_unit.lock);
335 maxiradio_radio.priv = &radio_unit; 408 maxiradio_radio.priv = &radio_unit;
336 409
337 if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) { 410 if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
338 printk("radio-maxiradio: can't register device!"); 411 printk("radio-maxiradio: can't register device!");
339 goto err_out_free_region; 412 goto err_out_free_region;
340 } 413 }
@@ -389,3 +462,10 @@ static void __exit maxiradio_radio_exit(void)
389 462
390module_init(maxiradio_radio_init); 463module_init(maxiradio_radio_init);
391module_exit(maxiradio_radio_exit); 464module_exit(maxiradio_radio_exit);
465
466MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
467MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
468MODULE_LICENSE("GPL");
469
470module_param_named(debug,maxiradio_radio.debug, int, 0644);
471MODULE_PARM_DESC(debug,"activates debug info");