1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include <linux/module.h>
27#include <linux/init.h>
28#include <linux/ioport.h>
29#include <linux/delay.h>
30#include <asm/io.h>
31#include <asm/uaccess.h>
32#include <linux/videodev.h>
33#include <linux/config.h>
34#include <linux/spinlock.h>
35
36#ifndef CONFIG_RADIO_TERRATEC_PORT
37#define CONFIG_RADIO_TERRATEC_PORT 0x590
38#endif
39
40
41#define BASEPORT 0x590
42#define VOLPORT 0x591
43#define WRT_DIS 0x00
44#define CLK_OFF 0x00
45#define IIC_DATA 0x01
46#define IIC_CLK 0x02
47#define DATA 0x04
48#define CLK_ON 0x08
49#define WRT_EN 0x10
50
51
52static int io = CONFIG_RADIO_TERRATEC_PORT;
53static int radio_nr = -1;
54static int users = 0;
55static spinlock_t lock;
56
57struct tt_device
58{
59 int port;
60 int curvol;
61 unsigned long curfreq;
62 int muted;
63};
64
65
66
67
68static void cardWriteVol(int volume)
69{
70 int i;
71 volume = volume+(volume * 32);
72 spin_lock(&lock);
73 for (i=0;i<8;i++)
74 {
75 if (volume & (0x80>>i))
76 outb(0x80, VOLPORT);
77 else outb(0x00, VOLPORT);
78 }
79 spin_unlock(&lock);
80}
81
82
83
84static void tt_mute(struct tt_device *dev)
85{
86 dev->muted = 1;
87 cardWriteVol(0);
88}
89
90static int tt_setvol(struct tt_device *dev, int vol)
91{
92
93
94
95 if(vol == dev->curvol) {
96 if (dev->muted) {
97 dev->muted = 0;
98 cardWriteVol(vol);
99 }
100
101 return 0;
102 }
103
104 if(vol == 0) {
105 cardWriteVol(0);
106 dev->curvol = vol;
107 return 0;
108 }
109
110 dev->muted = 0;
111
112 cardWriteVol(vol);
113
114 dev->curvol = vol;
115
116 return 0;
117
118}
119
120
121
122
123
124static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
125{
126 int freq;
127 int i;
128 int p;
129 int temp;
130 long rest;
131
132 unsigned char buffer[25];
133 freq = freq1/160;
134 for(i=24;i>-1;i--)
135 buffer[i]=0;
136
137 rest = freq*10+10700;
138
139 i=13;
140 p=10;
141 temp=102400;
142 while (rest!=0)
143 {
144 if (rest%temp == rest)
145 buffer[i] = 0;
146 else
147 {
148 buffer[i] = 1;
149 rest = rest-temp;
150 }
151 i--;
152 p--;
153 temp = temp/2;
154 }
155
156 spin_lock(&lock);
157
158 for (i=24;i>-1;i--)
159 {
160 if (buffer[i]==1)
161 {
162 outb(WRT_EN|DATA, BASEPORT);
163 outb(WRT_EN|DATA|CLK_ON , BASEPORT);
164 outb(WRT_EN|DATA, BASEPORT);
165 }
166 else
167 {
168 outb(WRT_EN|0x00, BASEPORT);
169 outb(WRT_EN|0x00|CLK_ON , BASEPORT);
170 }
171 }
172 outb(0x00, BASEPORT);
173
174 spin_unlock(&lock);
175
176 return 0;
177}
178
179int tt_getsigstr(struct tt_device *dev)
180{
181 if (inb(io) & 2)
182 return 0;
183 return 1;
184}
185
186
187
188
189static int tt_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
190{
191 struct tt_device *tt=dev->priv;
192
193 switch(cmd)
194 {
195 case VIDIOCGCAP:
196 {
197 struct video_capability v;
198 v.type=VID_TYPE_TUNER;
199 v.channels=1;
200 v.audios=1;
201
202 v.maxwidth=0;
203 v.maxheight=0;
204 v.minwidth=0;
205 v.minheight=0;
206 strcpy(v.name, "ActiveRadio");
207 if(copy_to_user(arg,&v,sizeof(v)))
208 return -EFAULT;
209 return 0;
210 }
211 case VIDIOCGTUNER:
212 {
213 struct video_tuner v;
214 if(copy_from_user(&v, arg,sizeof(v))!=0)
215 return -EFAULT;
216 if(v.tuner)
217 return -EINVAL;
218 v.rangelow=(87*16000);
219 v.rangehigh=(108*16000);
220 v.flags=VIDEO_TUNER_LOW;
221 v.mode=VIDEO_MODE_AUTO;
222 strcpy(v.name, "FM");
223 v.signal=0xFFFF*tt_getsigstr(tt);
224 if(copy_to_user(arg,&v, sizeof(v)))
225 return -EFAULT;
226 return 0;
227 }
228 case VIDIOCSTUNER:
229 {
230 struct video_tuner v;
231 if(copy_from_user(&v, arg, sizeof(v)))
232 return -EFAULT;
233 if(v.tuner!=0)
234 return -EINVAL;
235
236 return 0;
237 }
238 case VIDIOCGFREQ:
239 if(copy_to_user(arg, &tt->curfreq, sizeof(tt->curfreq)))
240 return -EFAULT;
241 return 0;
242 case VIDIOCSFREQ:
243 if(copy_from_user(&tt->curfreq, arg,sizeof(tt->curfreq)))
244 return -EFAULT;
245 tt_setfreq(tt, tt->curfreq);
246 return 0;
247 case VIDIOCGAUDIO:
248 {
249 struct video_audio v;
250 memset(&v,0, sizeof(v));
251 v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
252 v.volume=tt->curvol * 6554;
253 v.step=6554;
254 strcpy(v.name, "Radio");
255 if(copy_to_user(arg,&v, sizeof(v)))
256 return -EFAULT;
257 return 0;
258 }
259 case VIDIOCSAUDIO:
260 {
261 struct video_audio v;
262 if(copy_from_user(&v, arg, sizeof(v)))
263 return -EFAULT;
264 if(v.audio)
265 return -EINVAL;
266
267 if(v.flags&VIDEO_AUDIO_MUTE)
268 tt_mute(tt);
269 else
270 tt_setvol(tt,v.volume/6554);
271
272 return 0;
273 }
274 default:
275 return -ENOIOCTLCMD;
276 }
277}
278
279static int tt_open(struct video_device *dev, int flags)
280{
281 if(users)
282 return -EBUSY;
283 users++;
284 return 0;
285}
286
287static void tt_close(struct video_device *dev)
288{
289 users--;
290}
291
292static struct tt_device terratec_unit;
293
294static struct video_device terratec_radio=
295{
296 owner: THIS_MODULE,
297 name: "TerraTec ActiveRadio",
298 type: VID_TYPE_TUNER,
299 hardware: VID_HARDWARE_TERRATEC,
300 open: tt_open,
301 close: tt_close,
302 ioctl: tt_ioctl,
303};
304
305static int __init terratec_init(void)
306{
307 if(io==-1)
308 {
309 printk(KERN_ERR "You must set an I/O address with io=0x???\n");
310 return -EINVAL;
311 }
312 if (!request_region(io, 2, "terratec"))
313 {
314 printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io);
315 return -EBUSY;
316 }
317
318 terratec_radio.priv=&terratec_unit;
319
320 spin_lock_init(&lock);
321
322 if(video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr)==-1)
323 {
324 release_region(io,2);
325 return -EINVAL;
326 }
327
328 printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n");
329
330
331
332
333 cardWriteVol(0);
334 terratec_unit.curvol = 0;
335
336 return 0;
337}
338
339MODULE_AUTHOR("R.OFFERMANNS & others");
340MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
341MODULE_LICENSE("GPL");
342MODULE_PARM(io, "i");
343MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)");
344MODULE_PARM(radio_nr, "i");
345
346EXPORT_NO_SYMBOLS;
347
348static void __exit terratec_cleanup_module(void)
349{
350 video_unregister_device(&terratec_radio);
351 release_region(io,2);
352 printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n");
353}
354
355module_init(terratec_init);
356module_exit(terratec_cleanup_module);
357
358