OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [media/] [video/] [tvmixer.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.