1 /* aztech.c - Aztech radio card driver for Linux 2.1 by Russell Kroll
3 * Heavily modified to support the new 2.1 radio card interfaces by
4 * Russell Kroll (rkroll@exploits.org)
10 * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
11 * Scott McGrath (smcgrath@twilight.vtc.vsc.edu)
12 * William McGrath (wmcgrath@twilight.vtc.vsc.edu)
14 * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/
15 * along with more information on the card itself.
17 * Notable changes from the original source:
18 * - includes stripped down to the essentials
19 * - for loops used as delays replaced with udelay()
20 * - #defines removed, changed to static values
21 * - tuning structure changed - no more character arrays, other changes
24 #include <linux/module.h> /* Modules */
25 #include <linux/init.h> /* Initdata */
26 #include <linux/ioport.h> /* check_region, request_region */
27 #include <linux/delay.h> /* udelay */
28 #include <asm/io.h> /* outb, outb_p */
29 #include <asm/uaccess.h> /* copy to/from user */
30 #include <linux/videodev.h> /* kernel radio structs */
31 #include <linux/config.h> /* CONFIG_RADIO_AZTECH_PORT */
33 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
35 #ifndef CONFIG_RADIO_AZTECH_PORT
36 #define CONFIG_RADIO_AZTECH_PORT -1
39 static int io
= CONFIG_RADIO_AZTECH_PORT
;
40 static int radio_wait_time
= 1000;
46 unsigned long curfreq
;
50 static int volconvert(int level
)
52 level
>>=14; /* Map 16bits down to 2 bit */
55 /* convert to card-friendly values */
67 return 0; /* Quieten gcc */
70 static void send_0_byte (struct az_device
*dev
)
72 udelay(radio_wait_time
);
73 outb_p(2+volconvert(dev
->curvol
), io
);
74 outb_p(64+2+volconvert(dev
->curvol
), io
);
77 static void send_1_byte (struct az_device
*dev
)
79 udelay (radio_wait_time
);
80 outb_p(128+2+volconvert(dev
->curvol
), io
);
81 outb_p(128+64+2+volconvert(dev
->curvol
), io
);
84 static int az_setvol(struct az_device
*dev
, int vol
)
86 outb (volconvert(vol
), io
);
90 /* thanks to Michael Dwyer for giving me a dose of clues in
91 * the signal strength department..
93 * This card has a stereo bit - bit 0 set = mono, not set = stereo
94 * It also has a "signal" bit - bit 1 set = bad signal, not set = good
98 static int az_getsigstr(struct az_device
*dev
)
100 if (inb(io
) & 2) /* bit set = no signal present */
102 return 1; /* signal present */
105 static int az_getstereo(struct az_device
*dev
)
107 if (inb(io
) & 1) /* bit set = mono */
109 return 1; /* stereo */
112 static int az_setfreq(struct az_device
*dev
, unsigned long frequency
)
116 frequency
= (frequency
* 100) / 16; /* massage data a bit */
118 frequency
+= 1070; /* tuning needs 24 data bits */
121 send_0_byte (dev
); /* 0: LSB of frequency */
123 for (i
= 0; i
< 13; i
++) /* : frequency bits (1-13) */
124 if (frequency
& (1 << i
))
129 send_0_byte (dev
); /* 14: test bit - always 0 */
130 send_0_byte (dev
); /* 15: test bit - always 0 */
131 send_0_byte (dev
); /* 16: band data 0 - always 0 */
132 if (dev
->stereo
) /* 17: stereo (1 to enable) */
137 send_1_byte (dev
); /* 18: band data 1 - unknown */
138 send_0_byte (dev
); /* 19: time base - always 0 */
139 send_0_byte (dev
); /* 20: spacing (0 = 25 kHz) */
140 send_1_byte (dev
); /* 21: spacing (1 = 25 kHz) */
141 send_0_byte (dev
); /* 22: spacing (0 = 25 kHz) */
142 send_1_byte (dev
); /* 23: AM/FM (FM = 1, always) */
144 /* latch frequency */
146 udelay (radio_wait_time
);
147 outb_p(128+64+volconvert(dev
->curvol
), io
);
152 static int az_ioctl(struct video_device
*dev
, unsigned int cmd
, void *arg
)
154 struct az_device
*az
=dev
->priv
;
160 struct video_capability v
;
161 v
.type
=VID_TYPE_TUNER
;
164 /* No we don't do pictures */
169 if(copy_to_user(arg
,&v
,sizeof(v
)))
175 struct video_tuner v
;
176 if(copy_from_user(&v
, arg
,sizeof(v
))!=0)
178 if(v
.tuner
) /* Only 1 tuner */
180 v
.rangelow
=(879*16)/10;
181 v
.rangehigh
=(1078*16)/10;
183 v
.mode
=VIDEO_MODE_AUTO
;
184 v
.signal
=0xFFFF*az_getsigstr(az
);
186 v
.flags
|=VIDEO_TUNER_STEREO_ON
;
187 if(copy_to_user(arg
,&v
, sizeof(v
)))
193 struct video_tuner v
;
194 if(copy_from_user(&v
, arg
, sizeof(v
)))
198 /* Only 1 tuner so no setting needed ! */
202 if(copy_to_user(arg
, &az
->curfreq
, sizeof(az
->curfreq
)))
206 if(copy_from_user(&az
->curfreq
, arg
,sizeof(az
->curfreq
)))
208 az_setfreq(az
, az
->curfreq
);
212 struct video_audio v
;
213 memset(&v
,0, sizeof(v
));
214 v
.flags
|=VIDEO_AUDIO_MUTABLE
|VIDEO_AUDIO_VOLUME
;
216 v
.mode
=VIDEO_SOUND_STEREO
;
218 v
.mode
=VIDEO_SOUND_MONO
;
220 strcpy(v
.name
, "Radio");
221 if(copy_to_user(arg
,&v
, sizeof(v
)))
227 struct video_audio v
;
228 if(copy_from_user(&v
, arg
, sizeof(v
)))
234 az
->stereo
=(v
.mode
&VIDEO_SOUND_STEREO
)?1:0;
235 if(v
.flags
&VIDEO_AUDIO_MUTE
)
238 az_setvol(az
,az
->curvol
);
246 static int az_open(struct video_device
*dev
, int flags
)
255 static void az_close(struct video_device
*dev
)
261 static struct az_device aztech_unit
;
263 static struct video_device aztech_radio
=
270 NULL
, /* Can't read (no capture ability) */
271 NULL
, /* Can't write */
277 __initfunc(int aztech_init(struct video_init
*v
))
279 if (check_region(io
, 2))
281 printk(KERN_ERR
"aztech: port 0x%x already in use\n", io
);
285 aztech_radio
.priv
=&aztech_unit
;
287 if(video_register_device(&aztech_radio
, VFL_TYPE_RADIO
)==-1)
290 request_region(io
, 2, "aztech");
291 printk(KERN_INFO
"Aztech radio card driver v0.40/19980422 rkroll@exploits.org\n");
292 /* mute card - prevents noisy bootups */
299 MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
300 MODULE_DESCRIPTION("A driver for the Aztech radio card.");
301 MODULE_PARM(io
, "i");
302 MODULE_PARM_DESC(io
, "I/O address of the Aztech card (0x350 or 0x358)");
306 int init_module(void)
310 printk(KERN_ERR
"You must set an I/O address with io=0x???\n");
313 return aztech_init(NULL
);
316 void cleanup_module(void)
318 video_unregister_device(&aztech_radio
);
319 release_region(io
,2);