v2.4.8 -> v2.4.8.1
[opensuse:kernel.git] / drivers / media / video / tvmixer.c
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/sched.h>
4 #include <linux/string.h>
5 #include <linux/timer.h>
6 #include <linux/delay.h>
7 #include <linux/errno.h>
8 #include <linux/slab.h>
9 #include <linux/i2c.h>
10 #include <linux/videodev.h>
11 #include <asm/semaphore.h>
12 #include <linux/init.h>
13
14 #include <linux/sound.h>
15 #include <linux/soundcard.h>
16 #include <asm/uaccess.h>
17
18 #include "audiochip.h"
19 #include "id.h"
20
21 #define DEV_MAX  4
22
23 static int debug = 0;
24 static int devnr = -1;
25
26 MODULE_PARM(debug,"i");
27 MODULE_PARM(devnr,"i");
28
29 /* ----------------------------------------------------------------------- */
30
31 struct TVMIXER {
32         struct i2c_client *dev;
33         int minor;
34         int count;
35 };
36
37 static struct TVMIXER devices[DEV_MAX];
38
39 static int tvmixer_adapters(struct i2c_adapter *adap);
40 static int tvmixer_clients(struct i2c_client *client);
41
42 static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
43 static int tvmixer_open(struct inode *inode, struct file *file);
44 static int tvmixer_release(struct inode *inode, struct file *file);
45
46
47 static struct i2c_driver driver = {
48         name:            "tv card mixer driver",
49         id:              I2C_DRIVERID_TVMIXER,
50         flags:           I2C_DF_DUMMY,
51         attach_adapter:  tvmixer_adapters,
52         detach_client:   tvmixer_clients,
53 };
54
55 static struct file_operations tvmixer_fops = {
56         owner:          THIS_MODULE,
57         llseek:         no_llseek,
58         ioctl:          tvmixer_ioctl,
59         open:           tvmixer_open,
60         release:        tvmixer_release,
61 };
62
63 /* ----------------------------------------------------------------------- */
64
65 static int mix_to_v4l(int i)
66 {
67         int r;
68
69         r = ((i & 0xff) * 65536 + 50) / 100;
70         if (r > 65535) r = 65535;
71         if (r <     0) r =     0;
72         return r;
73 }
74
75 static int v4l_to_mix(int i)
76 {
77         int r;
78
79         r = (i * 100 + 32768) / 65536;
80         if (r > 100) r = 100;
81         if (r <   0) r =   0;
82         return r | (r << 8);
83 }
84
85 static int v4l_to_mix2(int l, int r)
86 {
87         r = (r * 100 + 32768) / 65536;
88         if (r > 100) r = 100;
89         if (r <   0) r =   0;
90         l = (l * 100 + 32768) / 65536;
91         if (l > 100) l = 100;
92         if (l <   0) l =   0;
93         return (r << 8) | l;
94 }
95
96 static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
97 {
98         struct video_audio va;
99         int left,right,ret,val = 0;
100         struct TVMIXER *mix = file->private_data;
101         struct i2c_client *client = mix->dev;
102
103         if (NULL == client)
104                 return -ENODEV;
105         
106         if (cmd == SOUND_MIXER_INFO) {
107                 mixer_info info;
108                 strncpy(info.id, "tv card", sizeof(info.id));
109                 strncpy(info.name, client->name, sizeof(info.name));
110                 info.modify_counter = 42 /* FIXME */;
111                 if (copy_to_user((void *)arg, &info, sizeof(info)))
112                         return -EFAULT;
113                 return 0;
114         }
115         if (cmd == SOUND_OLD_MIXER_INFO) {
116                 _old_mixer_info info;
117                 strncpy(info.id, "tv card", sizeof(info.id));
118                 strncpy(info.name, client->name, sizeof(info.name));
119                 if (copy_to_user((void *)arg, &info, sizeof(info)))
120                         return -EFAULT;
121                 return 0;
122         }
123         if (cmd == OSS_GETVERSION)
124                 return put_user(SOUND_VERSION, (int *)arg);
125
126         if (_SIOC_DIR(cmd) & _SIOC_WRITE)
127                 if (get_user(val, (int *)arg))
128                         return -EFAULT;
129
130         /* read state */
131         memset(&va,0,sizeof(va));
132         client->driver->command(client,VIDIOCGAUDIO,&va);
133
134         switch (cmd) {
135         case MIXER_READ(SOUND_MIXER_RECMASK):
136         case MIXER_READ(SOUND_MIXER_CAPS):
137         case MIXER_READ(SOUND_MIXER_RECSRC):
138         case MIXER_WRITE(SOUND_MIXER_RECSRC):
139                 ret = 0;
140                 break;
141
142         case MIXER_READ(SOUND_MIXER_STEREODEVS):
143                 ret = SOUND_MASK_VOLUME;
144                 break;
145         case MIXER_READ(SOUND_MIXER_DEVMASK):
146                 ret = SOUND_MASK_VOLUME;
147                 if (va.flags & VIDEO_AUDIO_BASS)
148                         ret |= SOUND_MASK_BASS;
149                 if (va.flags & VIDEO_AUDIO_TREBLE)
150                         ret |= SOUND_MASK_TREBLE;
151                 break;
152
153         case MIXER_WRITE(SOUND_MIXER_VOLUME):
154                 left  = mix_to_v4l(val);
155                 right = mix_to_v4l(val >> 8);
156                 va.volume  = MAX(left,right);
157                 va.balance = (32768*MIN(left,right)) / (va.volume ? va.volume : 1);
158                 va.balance = (left<right) ? (65535-va.balance) : va.balance;
159                 client->driver->command(client,VIDIOCSAUDIO,&va);
160                 client->driver->command(client,VIDIOCGAUDIO,&va);
161                 /* fall throuth */
162         case MIXER_READ(SOUND_MIXER_VOLUME):
163                 left  = (MIN(65536 - va.balance,32768) *
164                          va.volume) / 32768;
165                 right = (MIN(va.balance,32768) *
166                          va.volume) / 32768;
167                 ret = v4l_to_mix2(left,right);
168                 break;
169                 
170         case MIXER_WRITE(SOUND_MIXER_BASS):
171                 va.bass = mix_to_v4l(val);
172                 client->driver->command(client,VIDIOCSAUDIO,&va);
173                 client->driver->command(client,VIDIOCGAUDIO,&va);
174                 /* fall throuth  */
175         case MIXER_READ(SOUND_MIXER_BASS):
176                 ret = v4l_to_mix(va.bass);
177                 break;
178
179         case MIXER_WRITE(SOUND_MIXER_TREBLE):
180                 va.treble = mix_to_v4l(val);
181                 client->driver->command(client,VIDIOCSAUDIO,&va);
182                 client->driver->command(client,VIDIOCGAUDIO,&va);
183                 /* fall throuth */
184         case MIXER_READ(SOUND_MIXER_TREBLE):
185                 ret = v4l_to_mix(va.treble);
186                 break;
187
188         default:
189                 return -EINVAL;
190         }
191         if (put_user(ret, (int *)arg))
192                 return -EFAULT;
193         return 0;
194 }
195
196 static int tvmixer_open(struct inode *inode, struct file *file)
197 {
198         int i, minor = MINOR(inode->i_rdev);
199         struct TVMIXER *mix = NULL;
200         struct i2c_client *client = NULL;
201
202         for (i = 0; i < DEV_MAX; i++) {
203                 if (devices[i].minor == minor) {
204                         mix = devices+i;
205                         client = mix->dev;
206                         break;
207                 }
208         }
209
210         if (NULL == client)
211                 return -ENODEV;
212
213         /* lock bttv in memory while the mixer is in use  */
214         file->private_data = mix;
215         if (client->adapter->inc_use)
216                 client->adapter->inc_use(client->adapter);
217         return 0;
218 }
219
220 static int tvmixer_release(struct inode *inode, struct file *file)
221 {
222         struct TVMIXER *mix = file->private_data;
223         struct i2c_client *client;
224
225         client = mix->dev;
226         if (NULL == client) {
227                 return -ENODEV;
228         }
229
230         if (client->adapter->dec_use)
231                 client->adapter->dec_use(client->adapter);
232         return 0;
233 }
234
235 /* ----------------------------------------------------------------------- */
236
237 static int tvmixer_adapters(struct i2c_adapter *adap)
238 {
239         int i;
240
241         if (debug)
242                 printk("tvmixer: adapter %s\n",adap->name);
243         for (i=0; i<I2C_CLIENT_MAX; i++) {
244                 if (!adap->clients[i])
245                         continue;
246                 tvmixer_clients(adap->clients[i]);
247         }
248         return 0;
249 }
250
251 static int tvmixer_clients(struct i2c_client *client)
252 {
253         struct video_audio va;
254         int i,minor;
255
256         /* TV card ??? */
257         if (client->adapter->id != (I2C_ALGO_BIT | I2C_HW_B_BT848)) {
258                 if (debug)
259                         printk("tvmixer: %s is not a tv card\n",
260                                client->adapter->name);
261                 return -1;
262         }
263         printk("tvmixer: debug: %s\n",client->name);
264
265         /* unregister ?? */
266         for (i = 0; i < DEV_MAX; i++) {
267                 if (devices[i].dev == client) {
268                         /* unregister */
269                         unregister_sound_mixer(devices[i].minor);
270                         devices[i].dev = NULL;
271                         devices[i].minor = -1;
272                         printk("tvmixer: %s unregistered (#1)\n",client->name);
273                         return 0;
274                 }
275         }
276
277         /* look for a free slot */
278         for (i = 0; i < DEV_MAX; i++)
279                 if (NULL == devices[i].dev)
280                         break;
281         if (i == DEV_MAX) {
282                 printk(KERN_WARNING "tvmixer: DEV_MAX too small\n");
283                 return -1;
284         }
285
286         /* audio chip with mixer ??? */
287         if (NULL == client->driver->command) {
288                 if (debug)
289                         printk("tvmixer: %s: driver->command is NULL\n",
290                                client->driver->name);
291                 return -1;
292         }
293         memset(&va,0,sizeof(va));
294         if (0 != client->driver->command(client,VIDIOCGAUDIO,&va)) {
295                 if (debug)
296                         printk("tvmixer: %s: VIDIOCGAUDIO failed\n",
297                                client->name);
298                 return -1;
299         }
300         if (0 == (va.flags & VIDEO_AUDIO_VOLUME)) {
301                 if (debug)
302                         printk("tvmixer: %s: has no volume control\n",
303                                client->name);
304                 return -1;
305         }
306
307         /* everything is fine, register */
308         if ((minor = register_sound_mixer(&tvmixer_fops,devnr)) < 0) {
309                 printk(KERN_ERR "tvmixer: cannot allocate mixer device\n");
310                 return -1;
311         }
312
313         devices[i].minor = minor;
314         devices[i].count = 0;
315         devices[i].dev   = client;
316         printk("tvmixer: %s (%s) registered with minor %d\n",
317                client->name,client->adapter->name,minor);
318         
319         return 0;
320 }
321
322 /* ----------------------------------------------------------------------- */
323
324 int tvmixer_init_module(void)
325 {
326         int i;
327         
328         for (i = 0; i < DEV_MAX; i++)
329                 devices[i].minor = -1;
330         i2c_add_driver(&driver);
331         return 0;
332 }
333
334 void tvmixer_cleanup_module(void)
335 {
336         int i;
337         
338         i2c_del_driver(&driver);
339         for (i = 0; i < DEV_MAX; i++) {
340                 if (devices[i].minor != -1) {
341                         unregister_sound_mixer(devices[i].minor);
342                         printk("tvmixer: %s unregistered (#2)\n",
343                                devices[i].dev->name);
344                 }
345         }
346 }
347
348 module_init(tvmixer_init_module);
349 module_exit(tvmixer_cleanup_module);
350
351 /*
352  * Overrides for Emacs so that we follow Linus's tabbing style.
353  * ---------------------------------------------------------------------------
354  * Local variables:
355  * c-basic-offset: 8
356  * End:
357  */