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 --- |