Import 2.1.118
[davej-history.git] / drivers / char / radio-sf16fmi.c
blob192fa5236f536937352fbf662891d6e76bacd175
1 /* SF16FMI radio driver for Linux radio support
2 * heavily based on rtrack driver...
3 * (c) 1997 M. Kirkwood
4 * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz
6 * Fitted to new interface by Alan Cox <alan.cox@linux.org>
8 * Notes on the hardware
10 * Frequency control is done digitally -- ie out(port,encodefreq(95.8));
11 * No volume control - only mute/unmute - you have to use line volume
12 * control on SB-part of SF16FMI
16 #include <linux/module.h> /* Modules */
17 #include <linux/init.h> /* Initdata */
18 #include <linux/ioport.h> /* check_region, request_region */
19 #include <linux/delay.h> /* udelay */
20 #include <asm/io.h> /* outb, outb_p */
21 #include <asm/uaccess.h> /* copy to/from user */
22 #include <linux/videodev.h> /* kernel radio structs */
23 #include <linux/config.h> /* CONFIG_RADIO_SF16MI_PORT */
25 struct fmi_device
27 int port;
28 int curvol; /* 1 or 0 */
29 unsigned long curfreq; /* RSF16_PREC * freq in MHz */
30 __u32 flags;
33 #ifndef CONFIG_RADIO_SF16FMI_PORT
34 #define CONFIG_RADIO_SF16FMI_PORT -1
35 #endif
37 static int io = CONFIG_RADIO_SF16FMI_PORT;
38 static int users = 0;
40 /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
41 /* It is only usefull to give freq in intervall of 800 (=0.05Mhz),
42 * other bits will be truncated, e.g 92.7400016 -> 92.7, but
43 * 92.7400017 -> 92.75
45 #define RSF16_ENCODE(x) ((x)/800+214)
46 #define RSF16_MINFREQ 88*16000
47 #define RSF16_MAXFREQ 108*16000
49 static void outbits(int bits, unsigned int data, int port)
51 while(bits--) {
52 if(data & 1) {
53 outb(5, port);
54 udelay(6);
55 outb(7, port);
56 udelay(6);
57 } else {
58 outb(1, port);
59 udelay(6);
60 outb(3, port);
61 udelay(6);
63 data>>=1;
67 static void fmi_mute(int port)
69 outb(0x00, port);
72 static void fmi_unmute(int port)
74 outb(0x08, port);
77 static int fmi_setfreq(struct fmi_device *dev, unsigned long freq)
79 int myport = dev->port;
81 outbits(16, RSF16_ENCODE(freq), myport);
82 outbits(8, 0xC0, myport);
83 /* we should wait here... */
84 return 0;
87 static int fmi_getsigstr(struct fmi_device *dev)
89 int val;
90 int res;
91 int myport = dev->port;
93 val = dev->curvol ? 0x08 : 0x00; /* unmute/mute */
94 outb(val, myport);
95 outb(val | 0x10, myport);
96 udelay(140000);
97 res = (int)inb(myport+1);
98 outb(val, myport);
99 return (res & 2) ? 0 : 1;
102 static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
104 struct fmi_device *fmi=dev->priv;
106 switch(cmd)
108 case VIDIOCGCAP:
110 struct video_capability v;
111 strcpy(v.name, "SF16-FMx radio");
112 v.type=VID_TYPE_TUNER;
113 v.channels=1;
114 v.audios=1;
115 /* No we don't do pictures */
116 v.maxwidth=0;
117 v.maxheight=0;
118 v.minwidth=0;
119 v.minheight=0;
120 if(copy_to_user(arg,&v,sizeof(v)))
121 return -EFAULT;
122 return 0;
124 case VIDIOCGTUNER:
126 struct video_tuner v;
127 int mult;
129 if(copy_from_user(&v, arg,sizeof(v))!=0)
130 return -EFAULT;
131 if(v.tuner) /* Only 1 tuner */
132 return -EINVAL;
133 strcpy(v.name, "FM");
134 mult = (fmi->flags & VIDEO_TUNER_LOW) ? 1 : 1000;
135 v.rangelow = RSF16_MINFREQ/mult;
136 v.rangehigh = RSF16_MAXFREQ/mult;
137 v.flags=fmi->flags;
138 v.mode=VIDEO_MODE_AUTO;
139 v.signal=0xFFFF*fmi_getsigstr(fmi);
140 if(copy_to_user(arg,&v, sizeof(v)))
141 return -EFAULT;
142 return 0;
144 case VIDIOCSTUNER:
146 struct video_tuner v;
147 if(copy_from_user(&v, arg, sizeof(v)))
148 return -EFAULT;
149 if(v.tuner!=0)
150 return -EINVAL;
151 fmi->flags = v.flags & VIDEO_TUNER_LOW;
152 /* Only 1 tuner so no setting needed ! */
153 return 0;
155 case VIDIOCGFREQ:
157 unsigned long tmp = fmi->curfreq;
158 if (!(fmi->flags & VIDEO_TUNER_LOW))
159 tmp /= 1000;
160 if(copy_to_user(arg, &tmp, sizeof(tmp)))
161 return -EFAULT;
162 return 0;
164 case VIDIOCSFREQ:
166 unsigned long tmp;
167 if(copy_from_user(&tmp, arg, sizeof(tmp)))
168 return -EFAULT;
169 if (!(fmi->flags & VIDEO_TUNER_LOW))
170 tmp *= 1000;
171 if ( tmp<RSF16_MINFREQ || tmp>RSF16_MAXFREQ )
172 return -EINVAL;
173 fmi->curfreq = tmp;
174 fmi_setfreq(fmi, fmi->curfreq);
175 return 0;
177 case VIDIOCGAUDIO:
179 struct video_audio v;
180 v.audio=0;
181 v.volume=0;
182 v.bass=0;
183 v.treble=0;
184 v.flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
185 strcpy(v.name, "Radio");
186 v.mode=VIDEO_SOUND_MONO;
187 v.balance=0;
188 v.step=0; /* No volume, just (un)mute */
189 if(copy_to_user(arg,&v, sizeof(v)))
190 return -EFAULT;
191 return 0;
193 case VIDIOCSAUDIO:
195 struct video_audio v;
196 if(copy_from_user(&v, arg, sizeof(v)))
197 return -EFAULT;
198 if(v.audio)
199 return -EINVAL;
200 fmi->curvol= v.flags&VIDEO_AUDIO_MUTE ? 0 : 1;
201 fmi->curvol ?
202 fmi_unmute(fmi->port) : fmi_mute(fmi->port);
203 return 0;
205 case VIDIOCGUNIT:
207 struct video_unit v;
208 v.video=VIDEO_NO_UNIT;
209 v.vbi=VIDEO_NO_UNIT;
210 v.radio=dev->minor;
211 v.audio=0; /* How do we find out this??? */
212 v.teletext=VIDEO_NO_UNIT;
213 if(copy_to_user(arg, &v, sizeof(v)))
214 return -EFAULT;
215 return 0;
217 default:
218 return -ENOIOCTLCMD;
222 static int fmi_open(struct video_device *dev, int flags)
224 if(users)
225 return -EBUSY;
226 users++;
227 MOD_INC_USE_COUNT;
228 return 0;
231 static void fmi_close(struct video_device *dev)
233 users--;
234 MOD_DEC_USE_COUNT;
237 static struct fmi_device fmi_unit;
239 static struct video_device fmi_radio=
241 "SF16FMx radio",
242 VID_TYPE_TUNER,
243 VID_HARDWARE_SF16MI,
244 fmi_open,
245 fmi_close,
246 NULL, /* Can't read (no capture ability) */
247 NULL, /* Can't write */
248 NULL, /* Can't poll */
249 fmi_ioctl,
250 NULL,
251 NULL
254 __initfunc(int fmi_init(struct video_init *v))
256 if (check_region(io, 2))
258 printk(KERN_ERR "fmi: port 0x%x already in use\n", io);
259 return -EBUSY;
262 fmi_unit.port = io;
263 fmi_unit.curvol = 0;
264 fmi_unit.curfreq = 0;
265 fmi_unit.flags = VIDEO_TUNER_LOW;
266 fmi_radio.priv = &fmi_unit;
268 if(video_register_device(&fmi_radio, VFL_TYPE_RADIO)==-1)
269 return -EINVAL;
271 request_region(io, 2, "fmi");
272 printk(KERN_INFO "SF16FMx radio card driver at 0x%x.\n", io);
273 printk(KERN_INFO "(c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz.\n");
274 /* mute card - prevents noisy bootups */
275 fmi_mute(io);
276 return 0;
279 #ifdef MODULE
281 MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
282 MODULE_DESCRIPTION("A driver for the SF16MI radio.");
283 MODULE_PARM(io, "i");
284 MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)");
286 EXPORT_NO_SYMBOLS;
288 int init_module(void)
290 if(io==-1)
292 printk(KERN_ERR "You must set an I/O address with io=0x???\n");
293 return -EINVAL;
295 return fmi_init(NULL);
298 void cleanup_module(void)
300 video_unregister_device(&fmi_radio);
301 release_region(io,2);
304 #endif