1 /* SF16FMI radio driver for Linux radio support
2 * heavily based on rtrack driver...
4 * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz
6 * Fitted to new interface by Alan Cox <alan.cox@linux.org>
7 * Made working and cleaned up functions <mikael.hedin@irf.se>
9 * Notes on the hardware
11 * Frequency control is done digitally -- ie out(port,encodefreq(95.8));
12 * No volume control - only mute/unmute - you have to use line volume
13 * control on SB-part of SF16FMI
17 #include <linux/module.h> /* Modules */
18 #include <linux/init.h> /* Initdata */
19 #include <linux/ioport.h> /* check_region, 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 */
23 #include <linux/videodev.h> /* kernel radio structs */
24 #include <linux/config.h> /* CONFIG_RADIO_SF16MI_PORT */
25 #include <asm/semaphore.h>
30 int curvol
; /* 1 or 0 */
31 unsigned long curfreq
; /* freq in kHz */
35 #ifndef CONFIG_RADIO_SF16FMI_PORT
36 #define CONFIG_RADIO_SF16FMI_PORT -1
39 static int io
= CONFIG_RADIO_SF16FMI_PORT
;
41 static struct semaphore lock
;
43 /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
44 /* It is only usefull to give freq in intervall of 800 (=0.05Mhz),
45 * other bits will be truncated, e.g 92.7400016 -> 92.7, but
48 #define RSF16_ENCODE(x) ((x)/800+214)
49 #define RSF16_MINFREQ 87*16000
50 #define RSF16_MAXFREQ 108*16000
52 static void outbits(int bits
, unsigned int data
, int port
)
70 static inline void fmi_mute(int port
)
77 static inline void fmi_unmute(int port
)
84 static inline int fmi_setfreq(struct fmi_device
*dev
)
86 int myport
= dev
->port
;
87 unsigned long freq
= dev
->curfreq
;
92 outbits(16, RSF16_ENCODE(freq
), myport
);
93 outbits(8, 0xC0, myport
);
97 if(current
->need_resched
)
100 /* If this becomes allowed use it ...
101 current->state = TASK_UNINTERRUPTIBLE;
102 schedule_timeout(HZ/7);
106 if (dev
->curvol
) fmi_unmute(myport
);
110 static inline int fmi_getsigstr(struct fmi_device
*dev
)
114 int myport
= dev
->port
;
118 val
= dev
->curvol
? 0x08 : 0x00; /* unmute/mute */
120 outb(val
| 0x10, myport
);
121 for(i
=0; i
< 100; i
++)
124 if(current
->need_resched
)
127 /* If this becomes allowed use it ...
128 current->state = TASK_UNINTERRUPTIBLE;
129 schedule_timeout(HZ/7);
131 res
= (int)inb(myport
+1);
135 return (res
& 2) ? 0 : 0xFFFF;
138 static int fmi_ioctl(struct video_device
*dev
, unsigned int cmd
, void *arg
)
140 struct fmi_device
*fmi
=dev
->priv
;
146 struct video_capability v
;
147 strcpy(v
.name
, "SF16-FMx radio");
148 v
.type
=VID_TYPE_TUNER
;
151 /* No we don't do pictures */
156 if(copy_to_user(arg
,&v
,sizeof(v
)))
162 struct video_tuner v
;
165 if(copy_from_user(&v
, arg
,sizeof(v
))!=0)
167 if(v
.tuner
) /* Only 1 tuner */
169 strcpy(v
.name
, "FM");
170 mult
= (fmi
->flags
& VIDEO_TUNER_LOW
) ? 1 : 1000;
171 v
.rangelow
= RSF16_MINFREQ
/mult
;
172 v
.rangehigh
= RSF16_MAXFREQ
/mult
;
174 v
.mode
=VIDEO_MODE_AUTO
;
175 v
.signal
= fmi_getsigstr(fmi
);
176 if(copy_to_user(arg
,&v
, sizeof(v
)))
182 struct video_tuner v
;
183 if(copy_from_user(&v
, arg
, sizeof(v
)))
187 fmi
->flags
= v
.flags
& VIDEO_TUNER_LOW
;
188 /* Only 1 tuner so no setting needed ! */
193 unsigned long tmp
= fmi
->curfreq
;
194 if (!(fmi
->flags
& VIDEO_TUNER_LOW
))
196 if(copy_to_user(arg
, &tmp
, sizeof(tmp
)))
203 if(copy_from_user(&tmp
, arg
, sizeof(tmp
)))
205 if (!(fmi
->flags
& VIDEO_TUNER_LOW
))
207 if ( tmp
<RSF16_MINFREQ
|| tmp
>RSF16_MAXFREQ
)
209 /*rounding in steps of 800 to match th freq
211 fmi
->curfreq
= (tmp
/800)*800;
217 struct video_audio v
;
222 v
.flags
=( (!fmi
->curvol
)*VIDEO_AUDIO_MUTE
| VIDEO_AUDIO_MUTABLE
);
223 strcpy(v
.name
, "Radio");
224 v
.mode
=VIDEO_SOUND_STEREO
;
226 v
.step
=0; /* No volume, just (un)mute */
227 if(copy_to_user(arg
,&v
, sizeof(v
)))
233 struct video_audio v
;
234 if(copy_from_user(&v
, arg
, sizeof(v
)))
238 fmi
->curvol
= v
.flags
&VIDEO_AUDIO_MUTE
? 0 : 1;
240 fmi_unmute(fmi
->port
) : fmi_mute(fmi
->port
);
246 v
.video
=VIDEO_NO_UNIT
;
249 v
.audio
=0; /* How do we find out this??? */
250 v
.teletext
=VIDEO_NO_UNIT
;
251 if(copy_to_user(arg
, &v
, sizeof(v
)))
260 static int fmi_open(struct video_device
*dev
, int flags
)
269 static void fmi_close(struct video_device
*dev
)
275 static struct fmi_device fmi_unit
;
277 static struct video_device fmi_radio
=
279 name
: "SF16FMx radio",
280 type
: VID_TYPE_TUNER
,
281 hardware
: VID_HARDWARE_SF16MI
,
287 static int __init
fmi_init(void)
291 printk(KERN_ERR
"You must set an I/O address with io=0x???\n");
294 if (request_region(io
, 2, "fmi"))
296 printk(KERN_ERR
"fmi: port 0x%x already in use\n", io
);
302 fmi_unit
.curfreq
= 0;
303 fmi_unit
.flags
= VIDEO_TUNER_LOW
;
304 fmi_radio
.priv
= &fmi_unit
;
308 if(video_register_device(&fmi_radio
, VFL_TYPE_RADIO
)==-1)
310 release_region(io
, 2);
314 printk(KERN_INFO
"SF16FMx radio card driver at 0x%x.\n", io
);
315 printk(KERN_INFO
"(c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz.\n");
316 /* mute card - prevents noisy bootups */
321 MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
322 MODULE_DESCRIPTION("A driver for the SF16MI radio.");
323 MODULE_PARM(io
, "i");
324 MODULE_PARM_DESC(io
, "I/O address of the SF16MI card (0x284 or 0x384)");
328 static void __exit
fmi_cleanup_module(void)
330 video_unregister_device(&fmi_radio
);
331 release_region(io
,2);
334 module_init(fmi_init
);
335 module_exit(fmi_cleanup_module
);