radio-sf16fmr2.c (0a1340c185734a57fbf4775927966ad4a1347b02) | radio-sf16fmr2.c (acda0e71857c8ec4e5348d08b53a52d35b92e6aa) |
---|---|
1/* SF16FMR2 radio driver for Linux radio support 2 * heavily based on fmi driver... 3 * (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com 4 * 5 * Notes on the hardware 6 * 7 * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); 8 * No volume control - only mute/unmute - you have to use line volume 9 * 10 * For read stereo/mono you must wait 0.1 sec after set frequency and 11 * card unmuted so I set frequency on unmute 12 * Signal handling seem to work only on autoscanning (not implemented) | 1/* SF16FMR2 radio driver for Linux radio support 2 * heavily based on fmi driver... 3 * (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com 4 * 5 * Notes on the hardware 6 * 7 * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); 8 * No volume control - only mute/unmute - you have to use line volume 9 * 10 * For read stereo/mono you must wait 0.1 sec after set frequency and 11 * card unmuted so I set frequency on unmute 12 * Signal handling seem to work only on autoscanning (not implemented) |
13 * 14 * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> |
|
13 */ 14 15#include <linux/module.h> /* Modules */ 16#include <linux/init.h> /* Initdata */ 17#include <linux/ioport.h> /* request_region */ 18#include <linux/delay.h> /* udelay */ 19#include <asm/io.h> /* outb, outb_p */ 20#include <asm/uaccess.h> /* copy to/from user */ | 15 */ 16 17#include <linux/module.h> /* Modules */ 18#include <linux/init.h> /* Initdata */ 19#include <linux/ioport.h> /* request_region */ 20#include <linux/delay.h> /* udelay */ 21#include <asm/io.h> /* outb, outb_p */ 22#include <asm/uaccess.h> /* copy to/from user */ |
21#include <linux/videodev.h> /* kernel radio structs */ | 23#include <linux/videodev2.h> /* kernel radio structs */ |
22#include <media/v4l2-common.h> 23#include <linux/mutex.h> 24 | 24#include <media/v4l2-common.h> 25#include <linux/mutex.h> 26 |
27#define RADIO_VERSION KERNEL_VERSION(0,0,2) 28 29static struct v4l2_queryctrl radio_qctrl[] = { 30 { 31 .id = V4L2_CID_AUDIO_MUTE, 32 .name = "Mute", 33 .minimum = 0, 34 .maximum = 1, 35 .default_value = 1, 36 .type = V4L2_CTRL_TYPE_BOOLEAN, 37 },{ 38 .id = V4L2_CID_AUDIO_VOLUME, 39 .name = "Volume", 40 .minimum = 0, 41 .maximum = 65535, 42 .step = 1<<12, 43 .default_value = 0xff, 44 .type = V4L2_CTRL_TYPE_INTEGER, 45 } 46}; 47 |
|
25static struct mutex lock; 26 27#undef DEBUG 28//#define DEBUG 1 29 30#ifdef DEBUG 31# define debug_print(s) printk s 32#else --- 176 unchanged lines hidden (view full) --- 209 struct fmr2_device *fmr2 = dev->priv; 210 debug_print((KERN_DEBUG "freq %ld flags %d vol %d mute %d " 211 "stereo %d type %d\n", 212 fmr2->curfreq, fmr2->flags, fmr2->curvol, fmr2->mute, 213 fmr2->stereo, fmr2->card_type)); 214 215 switch(cmd) 216 { | 48static struct mutex lock; 49 50#undef DEBUG 51//#define DEBUG 1 52 53#ifdef DEBUG 54# define debug_print(s) printk s 55#else --- 176 unchanged lines hidden (view full) --- 232 struct fmr2_device *fmr2 = dev->priv; 233 debug_print((KERN_DEBUG "freq %ld flags %d vol %d mute %d " 234 "stereo %d type %d\n", 235 fmr2->curfreq, fmr2->flags, fmr2->curvol, fmr2->mute, 236 fmr2->stereo, fmr2->card_type)); 237 238 switch(cmd) 239 { |
217 case VIDIOCGCAP: | 240 case VIDIOC_QUERYCAP: |
218 { | 241 { |
219 struct video_capability *v = arg; | 242 struct v4l2_capability *v = arg; |
220 memset(v,0,sizeof(*v)); | 243 memset(v,0,sizeof(*v)); |
221 strcpy(v->name, "SF16-FMR2 radio"); 222 v->type=VID_TYPE_TUNER; 223 v->channels=1; 224 v->audios=1; | 244 strlcpy(v->driver, "radio-sf16fmr2", sizeof (v->driver)); 245 strlcpy(v->card, "SF16-FMR2 radio", sizeof (v->card)); 246 sprintf(v->bus_info,"ISA"); 247 v->version = RADIO_VERSION; 248 v->capabilities = V4L2_CAP_TUNER; 249 |
225 return 0; 226 } | 250 return 0; 251 } |
227 case VIDIOCGTUNER: | 252 case VIDIOC_G_TUNER: |
228 { | 253 { |
229 struct video_tuner *v = arg; | 254 struct v4l2_tuner *v = arg; |
230 int mult; 231 | 255 int mult; 256 |
232 if(v->tuner) /* Only 1 tuner */ | 257 if (v->index > 0) |
233 return -EINVAL; | 258 return -EINVAL; |
259 260 memset(v,0,sizeof(*v)); |
|
234 strcpy(v->name, "FM"); | 261 strcpy(v->name, "FM"); |
235 mult = (fmr2->flags & VIDEO_TUNER_LOW) ? 1 : 1000; | 262 v->type = V4L2_TUNER_RADIO; 263 264 mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000; |
236 v->rangelow = RSF16_MINFREQ/mult; 237 v->rangehigh = RSF16_MAXFREQ/mult; | 265 v->rangelow = RSF16_MINFREQ/mult; 266 v->rangehigh = RSF16_MAXFREQ/mult; |
238 v->flags = fmr2->flags | VIDEO_AUDIO_MUTABLE; 239 if (fmr2->mute) 240 v->flags |= VIDEO_AUDIO_MUTE; 241 v->mode=VIDEO_MODE_AUTO; | 267 v->rxsubchans =V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO; 268 v->capability=fmr2->flags&V4L2_TUNER_CAP_LOW; 269 270 v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO: 271 V4L2_TUNER_MODE_MONO; |
242 mutex_lock(&lock); 243 v->signal = fmr2_getsigstr(fmr2); 244 mutex_unlock(&lock); | 272 mutex_lock(&lock); 273 v->signal = fmr2_getsigstr(fmr2); 274 mutex_unlock(&lock); |
275 |
|
245 return 0; 246 } | 276 return 0; 277 } |
247 case VIDIOCSTUNER: | 278 case VIDIOC_S_TUNER: |
248 { | 279 { |
249 struct video_tuner *v = arg; 250 if (v->tuner!=0) | 280 struct v4l2_tuner *v = arg; 281 282 if (v->index > 0) |
251 return -EINVAL; | 283 return -EINVAL; |
252 fmr2->flags = v->flags & VIDEO_TUNER_LOW; | 284 |
253 return 0; 254 } | 285 return 0; 286 } |
255 case VIDIOCGFREQ: | 287 case VIDIOC_S_FREQUENCY: |
256 { | 288 { |
257 unsigned long *freq = arg; 258 *freq = fmr2->curfreq; 259 if (!(fmr2->flags & VIDEO_TUNER_LOW)) 260 *freq /= 1000; 261 return 0; 262 } 263 case VIDIOCSFREQ: 264 { 265 unsigned long *freq = arg; 266 if (!(fmr2->flags & VIDEO_TUNER_LOW)) 267 *freq *= 1000; 268 if ( *freq < RSF16_MINFREQ || *freq > RSF16_MAXFREQ ) | 289 struct v4l2_frequency *f = arg; 290 291 if (!(fmr2->flags & V4L2_TUNER_CAP_LOW)) 292 f->frequency *= 1000; 293 if (f->frequency < RSF16_MINFREQ || 294 f->frequency > RSF16_MAXFREQ ) |
269 return -EINVAL; | 295 return -EINVAL; |
270 /* rounding in steps of 200 to match th freq 271 * that will be used 272 */ 273 fmr2->curfreq = (*freq/200)*200; | 296 /*rounding in steps of 200 to match th freq 297 that will be used */ 298 fmr2->curfreq = (f->frequency/200)*200; |
274 275 /* set card freq (if not muted) */ 276 if (fmr2->curvol && !fmr2->mute) 277 { 278 mutex_lock(&lock); 279 fmr2_setfreq(fmr2); 280 mutex_unlock(&lock); 281 } | 299 300 /* set card freq (if not muted) */ 301 if (fmr2->curvol && !fmr2->mute) 302 { 303 mutex_lock(&lock); 304 fmr2_setfreq(fmr2); 305 mutex_unlock(&lock); 306 } |
307 |
|
282 return 0; 283 } | 308 return 0; 309 } |
284 case VIDIOCGAUDIO: | 310 case VIDIOC_G_FREQUENCY: |
285 { | 311 { |
286 struct video_audio *v = arg; 287 memset(v,0,sizeof(*v)); 288 /* !!! do not return VIDEO_AUDIO_MUTE */ 289 v->flags = VIDEO_AUDIO_MUTABLE; 290 strcpy(v->name, "Radio"); 291 /* get current stereo mode */ 292 v->mode = fmr2->stereo ? VIDEO_SOUND_STEREO: VIDEO_SOUND_MONO; 293 /* volume supported ? */ 294 if (fmr2->card_type == 11) 295 { 296 v->flags |= VIDEO_AUDIO_VOLUME; 297 v->step = 1 << 12; 298 v->volume = fmr2->curvol; 299 } 300 debug_print((KERN_DEBUG "Get flags %d vol %d\n", v->flags, v->volume)); | 312 struct v4l2_frequency *f = arg; 313 314 f->type = V4L2_TUNER_RADIO; 315 f->frequency = fmr2->curfreq; 316 if (!(fmr2->flags & V4L2_TUNER_CAP_LOW)) 317 f->frequency /= 1000; 318 |
301 return 0; 302 } | 319 return 0; 320 } |
303 case VIDIOCSAUDIO: | 321 case VIDIOC_QUERYCTRL: |
304 { | 322 { |
305 struct video_audio *v = arg; 306 if(v->audio) 307 return -EINVAL; 308 debug_print((KERN_DEBUG "Set flags %d vol %d\n", v->flags, v->volume)); 309 /* set volume */ 310 if (v->flags & VIDEO_AUDIO_VOLUME) 311 fmr2->curvol = v->volume; /* !!! set with precision */ 312 if (fmr2->card_type != 11) fmr2->curvol = 65535; 313 fmr2->mute = 0; 314 if (v->flags & VIDEO_AUDIO_MUTE) 315 fmr2->mute = 1; | 323 struct v4l2_queryctrl *qc = arg; 324 int i; 325 326 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { 327 if ((fmr2->card_type != 11) 328 && V4L2_CID_AUDIO_VOLUME) 329 radio_qctrl[i].step=65535; 330 if (qc->id && qc->id == radio_qctrl[i].id) { 331 memcpy(qc, &(radio_qctrl[i]), 332 sizeof(*qc)); 333 return (0); 334 } 335 } 336 return -EINVAL; 337 } 338 case VIDIOC_G_CTRL: 339 { 340 struct v4l2_control *ctrl= arg; 341 342 switch (ctrl->id) { 343 case V4L2_CID_AUDIO_MUTE: 344 ctrl->value=fmr2->mute; 345 return (0); 346 case V4L2_CID_AUDIO_VOLUME: 347 ctrl->value=fmr2->curvol; 348 return (0); 349 } 350 return -EINVAL; 351 } 352 case VIDIOC_S_CTRL: 353 { 354 struct v4l2_control *ctrl= arg; 355 356 switch (ctrl->id) { 357 case V4L2_CID_AUDIO_MUTE: 358 fmr2->mute=ctrl->value; 359 if (fmr2->card_type != 11) { 360 if (!fmr2->mute) { 361 fmr2->curvol = 65535; 362 } else { 363 fmr2->curvol = 0; 364 } 365 } 366 break; 367 case V4L2_CID_AUDIO_VOLUME: 368 fmr2->curvol = ctrl->value; 369 if (fmr2->card_type != 11) { 370 if (fmr2->curvol) { 371 fmr2->curvol = 65535; 372 fmr2->mute = 0; 373 } else { 374 fmr2->curvol = 0; 375 fmr2->mute = 1; 376 } 377 } 378 break; 379 default: 380 return -EINVAL; 381 } |
316#ifdef DEBUG 317 if (fmr2->curvol && !fmr2->mute) 318 printk(KERN_DEBUG "unmute\n"); 319 else 320 printk(KERN_DEBUG "mute\n"); 321#endif 322 mutex_lock(&lock); | 382#ifdef DEBUG 383 if (fmr2->curvol && !fmr2->mute) 384 printk(KERN_DEBUG "unmute\n"); 385 else 386 printk(KERN_DEBUG "mute\n"); 387#endif 388 mutex_lock(&lock); |
323 if (fmr2->curvol && !fmr2->mute) 324 { | 389 if (fmr2->curvol && !fmr2->mute) { |
325 fmr2_setvolume(fmr2); 326 fmr2_setfreq(fmr2); | 390 fmr2_setvolume(fmr2); 391 fmr2_setfreq(fmr2); |
327 } 328 else fmr2_mute(fmr2->port); | 392 } else 393 fmr2_mute(fmr2->port); |
329 mutex_unlock(&lock); | 394 mutex_unlock(&lock); |
330 return 0; | 395 return (0); |
331 } | 396 } |
332 case VIDIOCGUNIT: 333 { 334 struct video_unit *v = arg; 335 v->video=VIDEO_NO_UNIT; 336 v->vbi=VIDEO_NO_UNIT; 337 v->radio=dev->minor; 338 v->audio=0; /* How do we find out this??? */ 339 v->teletext=VIDEO_NO_UNIT; 340 return 0; 341 } | |
342 default: | 397 default: |
343 return -ENOIOCTLCMD; | 398 return v4l_compat_translate_ioctl(inode,file,cmd,arg, 399 az_do_ioctl); 400 |
344 } 345} 346 347static int fmr2_ioctl(struct inode *inode, struct file *file, 348 unsigned int cmd, unsigned long arg) 349 { 350 return video_usercopy(inode, file, cmd, arg, fmr2_do_ioctl); 351} --- 9 unchanged lines hidden (view full) --- 361 .llseek = no_llseek, 362}; 363 364static struct video_device fmr2_radio= 365{ 366 .owner = THIS_MODULE, 367 .name = "SF16FMR2 radio", 368 . type = VID_TYPE_TUNER, | 401 } 402} 403 404static int fmr2_ioctl(struct inode *inode, struct file *file, 405 unsigned int cmd, unsigned long arg) 406 { 407 return video_usercopy(inode, file, cmd, arg, fmr2_do_ioctl); 408} --- 9 unchanged lines hidden (view full) --- 418 .llseek = no_llseek, 419}; 420 421static struct video_device fmr2_radio= 422{ 423 .owner = THIS_MODULE, 424 .name = "SF16FMR2 radio", 425 . type = VID_TYPE_TUNER, |
369 .hardware = VID_HARDWARE_SF16FMR2, | 426 .hardware = 0, |
370 .fops = &fmr2_fops, 371}; 372 373static int __init fmr2_init(void) 374{ 375 fmr2_unit.port = io; 376 fmr2_unit.curvol = 0; 377 fmr2_unit.mute = 0; 378 fmr2_unit.curfreq = 0; 379 fmr2_unit.stereo = 1; | 427 .fops = &fmr2_fops, 428}; 429 430static int __init fmr2_init(void) 431{ 432 fmr2_unit.port = io; 433 fmr2_unit.curvol = 0; 434 fmr2_unit.mute = 0; 435 fmr2_unit.curfreq = 0; 436 fmr2_unit.stereo = 1; |
380 fmr2_unit.flags = VIDEO_TUNER_LOW; | 437 fmr2_unit.flags = V4L2_TUNER_CAP_LOW; |
381 fmr2_unit.card_type = 0; 382 fmr2_radio.priv = &fmr2_unit; 383 384 mutex_init(&lock); 385 386 if (request_region(io, 2, "sf16fmr2")) 387 { 388 printk(KERN_ERR "fmr2: port 0x%x already in use\n", io); 389 return -EBUSY; 390 } 391 392 if(video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr)==-1) 393 { 394 release_region(io, 2); 395 return -EINVAL; 396 } 397 398 printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io); | 438 fmr2_unit.card_type = 0; 439 fmr2_radio.priv = &fmr2_unit; 440 441 mutex_init(&lock); 442 443 if (request_region(io, 2, "sf16fmr2")) 444 { 445 printk(KERN_ERR "fmr2: port 0x%x already in use\n", io); 446 return -EBUSY; 447 } 448 449 if(video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr)==-1) 450 { 451 release_region(io, 2); 452 return -EINVAL; 453 } 454 455 printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io); |
399 debug_print((KERN_DEBUG "Mute %d Low %d\n",VIDEO_AUDIO_MUTE,VIDEO_TUNER_LOW)); | |
400 /* mute card - prevents noisy bootups */ 401 mutex_lock(&lock); 402 fmr2_mute(io); 403 fmr2_product_info(&fmr2_unit); 404 mutex_unlock(&lock); 405 debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type)); 406 return 0; 407} --- 29 unchanged lines hidden --- | 456 /* mute card - prevents noisy bootups */ 457 mutex_lock(&lock); 458 fmr2_mute(io); 459 fmr2_product_info(&fmr2_unit); 460 mutex_unlock(&lock); 461 debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type)); 462 return 0; 463} --- 29 unchanged lines hidden --- |