radio-sf16fmi.c (0a1340c185734a57fbf4775927966ad4a1347b02) radio-sf16fmi.c (a2ef73af4cd6cb46be13b11f9ce64d6b44f0350b)
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
5 *
6 * Fitted to new interface by Alan Cox <alan.cox@linux.org>
7 * Made working and cleaned up functions <mikael.hedin@irf.se>
8 * Support for ISAPnP by Ladislav Michl <ladis@psi.cz>
9 *
10 * Notes on the hardware
11 *
12 * Frequency control is done digitally -- ie out(port,encodefreq(95.8));
13 * No volume control - only mute/unmute - you have to use line volume
14 * control on SB-part of SF16FMI
15 *
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
5 *
6 * Fitted to new interface by Alan Cox <alan.cox@linux.org>
7 * Made working and cleaned up functions <mikael.hedin@irf.se>
8 * Support for ISAPnP by Ladislav Michl <ladis@psi.cz>
9 *
10 * Notes on the hardware
11 *
12 * Frequency control is done digitally -- ie out(port,encodefreq(95.8));
13 * No volume control - only mute/unmute - you have to use line volume
14 * control on SB-part of SF16FMI
15 *
16 * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
16 */
17
18#include <linux/kernel.h> /* __setup */
19#include <linux/module.h> /* Modules */
20#include <linux/init.h> /* Initdata */
21#include <linux/ioport.h> /* request_region */
22#include <linux/delay.h> /* udelay */
17 */
18
19#include <linux/kernel.h> /* __setup */
20#include <linux/module.h> /* Modules */
21#include <linux/init.h> /* Initdata */
22#include <linux/ioport.h> /* request_region */
23#include <linux/delay.h> /* udelay */
23#include <linux/videodev.h> /* kernel radio structs */
24#include <linux/videodev2.h> /* kernel radio structs */
24#include <media/v4l2-common.h>
25#include <linux/isapnp.h>
26#include <asm/io.h> /* outb, outb_p */
27#include <asm/uaccess.h> /* copy to/from user */
28#include <linux/mutex.h>
29
25#include <media/v4l2-common.h>
26#include <linux/isapnp.h>
27#include <asm/io.h> /* outb, outb_p */
28#include <asm/uaccess.h> /* copy to/from user */
29#include <linux/mutex.h>
30
31#define RADIO_VERSION KERNEL_VERSION(0,0,2)
32
33static struct v4l2_queryctrl radio_qctrl[] = {
34 {
35 .id = V4L2_CID_AUDIO_MUTE,
36 .name = "Mute",
37 .minimum = 0,
38 .maximum = 1,
39 .default_value = 1,
40 .type = V4L2_CTRL_TYPE_BOOLEAN,
41 }
42};
43
30struct fmi_device
31{
32 int port;
33 int curvol; /* 1 or 0 */
34 unsigned long curfreq; /* freq in kHz */
35 __u32 flags;
36};
37

--- 80 unchanged lines hidden (view full) ---

118static int fmi_do_ioctl(struct inode *inode, struct file *file,
119 unsigned int cmd, void *arg)
120{
121 struct video_device *dev = video_devdata(file);
122 struct fmi_device *fmi=dev->priv;
123
124 switch(cmd)
125 {
44struct fmi_device
45{
46 int port;
47 int curvol; /* 1 or 0 */
48 unsigned long curfreq; /* freq in kHz */
49 __u32 flags;
50};
51

--- 80 unchanged lines hidden (view full) ---

132static int fmi_do_ioctl(struct inode *inode, struct file *file,
133 unsigned int cmd, void *arg)
134{
135 struct video_device *dev = video_devdata(file);
136 struct fmi_device *fmi=dev->priv;
137
138 switch(cmd)
139 {
126 case VIDIOCGCAP:
140 case VIDIOC_QUERYCAP:
127 {
141 {
128 struct video_capability *v = arg;
142 struct v4l2_capability *v = arg;
129 memset(v,0,sizeof(*v));
143 memset(v,0,sizeof(*v));
130 strcpy(v->name, "SF16-FMx radio");
131 v->type=VID_TYPE_TUNER;
132 v->channels=1;
133 v->audios=1;
144 strlcpy(v->driver, "radio-sf16fmi", sizeof (v->driver));
145 strlcpy(v->card, "SF16-FMx radio", sizeof (v->card));
146 sprintf(v->bus_info,"ISA");
147 v->version = RADIO_VERSION;
148 v->capabilities = V4L2_CAP_TUNER;
149
134 return 0;
135 }
150 return 0;
151 }
136 case VIDIOCGTUNER:
152 case VIDIOC_G_TUNER:
137 {
153 {
138 struct video_tuner *v = arg;
154 struct v4l2_tuner *v = arg;
139 int mult;
140
155 int mult;
156
141 if(v->tuner) /* Only 1 tuner */
157 if (v->index > 0)
142 return -EINVAL;
158 return -EINVAL;
159
160 memset(v,0,sizeof(*v));
143 strcpy(v->name, "FM");
161 strcpy(v->name, "FM");
144 mult = (fmi->flags & VIDEO_TUNER_LOW) ? 1 : 1000;
162 v->type = V4L2_TUNER_RADIO;
163
164 mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
145 v->rangelow = RSF16_MINFREQ/mult;
146 v->rangehigh = RSF16_MAXFREQ/mult;
165 v->rangelow = RSF16_MINFREQ/mult;
166 v->rangehigh = RSF16_MAXFREQ/mult;
147 v->flags=fmi->flags;
148 v->mode=VIDEO_MODE_AUTO;
167 v->rxsubchans =V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
168 v->capability=fmi->flags;
169 v->audmode = V4L2_TUNER_MODE_STEREO;
149 v->signal = fmi_getsigstr(fmi);
170 v->signal = fmi_getsigstr(fmi);
171
150 return 0;
151 }
172 return 0;
173 }
152 case VIDIOCSTUNER:
174 case VIDIOC_S_TUNER:
153 {
175 {
154 struct video_tuner *v = arg;
155 if(v->tuner!=0)
176 struct v4l2_tuner *v = arg;
177
178 if (v->index > 0)
156 return -EINVAL;
179 return -EINVAL;
157 fmi->flags = v->flags & VIDEO_TUNER_LOW;
158 /* Only 1 tuner so no setting needed ! */
180
159 return 0;
160 }
181 return 0;
182 }
161 case VIDIOCGFREQ:
183 case VIDIOC_S_FREQUENCY:
162 {
184 {
163 unsigned long *freq = arg;
164 *freq = fmi->curfreq;
165 if (!(fmi->flags & VIDEO_TUNER_LOW))
166 *freq /= 1000;
167 return 0;
168 }
169 case VIDIOCSFREQ:
170 {
171 unsigned long *freq = arg;
172 if (!(fmi->flags & VIDEO_TUNER_LOW))
173 *freq *= 1000;
174 if (*freq < RSF16_MINFREQ || *freq > RSF16_MAXFREQ )
185 struct v4l2_frequency *f = arg;
186
187 if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
188 f->frequency *= 1000;
189 if (f->frequency < RSF16_MINFREQ ||
190 f->frequency > RSF16_MAXFREQ )
175 return -EINVAL;
176 /*rounding in steps of 800 to match th freq
177 that will be used */
191 return -EINVAL;
192 /*rounding in steps of 800 to match th freq
193 that will be used */
178 fmi->curfreq = (*freq/800)*800;
194 fmi->curfreq = (f->frequency/800)*800;
179 fmi_setfreq(fmi);
195 fmi_setfreq(fmi);
196
180 return 0;
181 }
197 return 0;
198 }
182 case VIDIOCGAUDIO:
199 case VIDIOC_G_FREQUENCY:
183 {
200 {
184 struct video_audio *v = arg;
185 memset(v,0,sizeof(*v));
186 v->flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
187 strcpy(v->name, "Radio");
188 v->mode=VIDEO_SOUND_STEREO;
201 struct v4l2_frequency *f = arg;
202
203 f->type = V4L2_TUNER_RADIO;
204 f->frequency = fmi->curfreq;
205 if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
206 f->frequency /= 1000;
207
189 return 0;
190 }
208 return 0;
209 }
191 case VIDIOCSAUDIO:
210 case VIDIOC_QUERYCTRL:
192 {
211 {
193 struct video_audio *v = arg;
194 if(v->audio)
195 return -EINVAL;
196 fmi->curvol= v->flags&VIDEO_AUDIO_MUTE ? 0 : 1;
197 fmi->curvol ?
198 fmi_unmute(fmi->port) : fmi_mute(fmi->port);
199 return 0;
212 struct v4l2_queryctrl *qc = arg;
213 int i;
214
215 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
216 if (qc->id && qc->id == radio_qctrl[i].id) {
217 memcpy(qc, &(radio_qctrl[i]),
218 sizeof(*qc));
219 return (0);
220 }
221 }
222 return -EINVAL;
200 }
223 }
201 case VIDIOCGUNIT:
224 case VIDIOC_G_CTRL:
202 {
225 {
203 struct video_unit *v = arg;
204 v->video=VIDEO_NO_UNIT;
205 v->vbi=VIDEO_NO_UNIT;
206 v->radio=dev->minor;
207 v->audio=0; /* How do we find out this??? */
208 v->teletext=VIDEO_NO_UNIT;
209 return 0;
226 struct v4l2_control *ctrl= arg;
227
228 switch (ctrl->id) {
229 case V4L2_CID_AUDIO_MUTE:
230 ctrl->value=fmi->curvol;
231 return (0);
232 }
233 return -EINVAL;
210 }
234 }
235 case VIDIOC_S_CTRL:
236 {
237 struct v4l2_control *ctrl= arg;
238
239 switch (ctrl->id) {
240 case V4L2_CID_AUDIO_MUTE:
241 {
242 if (ctrl->value)
243 fmi_mute(fmi->port);
244 else
245 fmi_unmute(fmi->port);
246
247 fmi->curvol=ctrl->value;
248 return (0);
249 }
250 }
251 return -EINVAL;
252 }
211 default:
253 default:
212 return -ENOIOCTLCMD;
254 return v4l_compat_translate_ioctl(inode,file,cmd,arg,
255 fmi_do_ioctl);
213 }
214}
215
216static int fmi_ioctl(struct inode *inode, struct file *file,
217 unsigned int cmd, unsigned long arg)
218{
219 return video_usercopy(inode, file, cmd, arg, fmi_do_ioctl);
220}

--- 9 unchanged lines hidden (view full) ---

230 .llseek = no_llseek,
231};
232
233static struct video_device fmi_radio=
234{
235 .owner = THIS_MODULE,
236 .name = "SF16FMx radio",
237 .type = VID_TYPE_TUNER,
256 }
257}
258
259static int fmi_ioctl(struct inode *inode, struct file *file,
260 unsigned int cmd, unsigned long arg)
261{
262 return video_usercopy(inode, file, cmd, arg, fmi_do_ioctl);
263}

--- 9 unchanged lines hidden (view full) ---

273 .llseek = no_llseek,
274};
275
276static struct video_device fmi_radio=
277{
278 .owner = THIS_MODULE,
279 .name = "SF16FMx radio",
280 .type = VID_TYPE_TUNER,
238 .hardware = VID_HARDWARE_SF16MI,
281 .hardware = 0,
239 .fops = &fmi_fops,
240};
241
242/* ladis: this is my card. does any other types exist? */
243static struct isapnp_device_id id_table[] __devinitdata = {
244 { ISAPNP_ANY_ID, ISAPNP_ANY_ID,
245 ISAPNP_VENDOR('M','F','R'), ISAPNP_FUNCTION(0xad10), 0},
246 { ISAPNP_CARD_END, },

--- 42 unchanged lines hidden (view full) ---

289 if (!request_region(io, 2, "radio-sf16fmi")) {
290 printk(KERN_ERR "radio-sf16fmi: port 0x%x already in use\n", io);
291 return -EBUSY;
292 }
293
294 fmi_unit.port = io;
295 fmi_unit.curvol = 0;
296 fmi_unit.curfreq = 0;
282 .fops = &fmi_fops,
283};
284
285/* ladis: this is my card. does any other types exist? */
286static struct isapnp_device_id id_table[] __devinitdata = {
287 { ISAPNP_ANY_ID, ISAPNP_ANY_ID,
288 ISAPNP_VENDOR('M','F','R'), ISAPNP_FUNCTION(0xad10), 0},
289 { ISAPNP_CARD_END, },

--- 42 unchanged lines hidden (view full) ---

332 if (!request_region(io, 2, "radio-sf16fmi")) {
333 printk(KERN_ERR "radio-sf16fmi: port 0x%x already in use\n", io);
334 return -EBUSY;
335 }
336
337 fmi_unit.port = io;
338 fmi_unit.curvol = 0;
339 fmi_unit.curfreq = 0;
297 fmi_unit.flags = VIDEO_TUNER_LOW;
340 fmi_unit.flags = V4L2_TUNER_CAP_LOW;
298 fmi_radio.priv = &fmi_unit;
299
300 mutex_init(&lock);
301
302 if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) == -1) {
303 release_region(io, 2);
304 return -EINVAL;
305 }

--- 25 unchanged lines hidden ---
341 fmi_radio.priv = &fmi_unit;
342
343 mutex_init(&lock);
344
345 if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) == -1) {
346 release_region(io, 2);
347 return -EINVAL;
348 }

--- 25 unchanged lines hidden ---