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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [media/] [radio/] [miropcm20-radio.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/* Miro PCM20 radio driver for Linux radio support
2
 * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
3
 * Thanks to Norberto Pellici for the ACI device interface specification
4
 * The API part is based on the radiotrack driver by M. Kirkwood
5
 * This driver relies on the aci mixer (drivers/sound/aci.c)
6
 * Look there for further info...
7
 */
8
 
9
/* Revision history:
10
 *
11
 *   1998        Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
12
 *   2000-09-05  Robert Siemer <Robert.Siemer@gmx.de>
13
 *        removed unfinished volume control (maybe adding it later again)
14
 *        use OSS-mixer; added stereo control
15
 */
16
 
17
/* What ever you think about the ACI, version 0x07 is not very well!
18
 * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono
19
 * conditions...                Robert
20
 */
21
 
22
#include <linux/module.h>
23
#include <linux/init.h>
24
#include <linux/videodev.h>
25
#include <media/v4l2-common.h>
26
#include "oss/aci.h"
27
#include "miropcm20-rds-core.h"
28
 
29
static int radio_nr = -1;
30
module_param(radio_nr, int, 0);
31
 
32
struct pcm20_device {
33
        unsigned long freq;
34
        int muted;
35
        int stereo;
36
};
37
 
38
 
39
static int pcm20_mute(struct pcm20_device *dev, unsigned char mute)
40
{
41
        dev->muted = mute;
42
        return aci_write_cmd(ACI_SET_TUNERMUTE, mute);
43
}
44
 
45
static int pcm20_stereo(struct pcm20_device *dev, unsigned char stereo)
46
{
47
        dev->stereo = stereo;
48
        return aci_write_cmd(ACI_SET_TUNERMONO, !stereo);
49
}
50
 
51
static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq)
52
{
53
        unsigned char freql;
54
        unsigned char freqh;
55
 
56
        dev->freq=freq;
57
 
58
        freq /= 160;
59
        if (!(aci_version==0x07 || aci_version>=0xb0))
60
                freq /= 10;  /* I don't know exactly which version
61
                              * needs this hack */
62
        freql = freq & 0xff;
63
        freqh = freq >> 8;
64
 
65
        aci_rds_cmd(RDS_RESET, NULL, 0);
66
        pcm20_stereo(dev, 1);
67
 
68
        return aci_rw_cmd(ACI_WRITE_TUNE, freql, freqh);
69
}
70
 
71
static int pcm20_getflags(struct pcm20_device *dev, __u32 *flags, __u16 *signal)
72
{
73
        /* okay, check for signal, stereo and rds here... */
74
        int i;
75
        unsigned char buf;
76
 
77
        if ((i=aci_rw_cmd(ACI_READ_TUNERSTATION, -1, -1))<0)
78
                return i;
79
        pr_debug("check_sig: 0x%x\n", i);
80
        if (i & 0x80) {
81
                /* no signal from tuner */
82
                *flags=0;
83
                *signal=0;
84
                return 0;
85
        } else
86
                *signal=0xffff;
87
 
88
        if ((i=aci_rw_cmd(ACI_READ_TUNERSTEREO, -1, -1))<0)
89
                return i;
90
        if (i & 0x40) {
91
                *flags=0;
92
        } else {
93
                /* stereo */
94
                *flags=VIDEO_TUNER_STEREO_ON;
95
                /* I can't see stereo, when forced to mono */
96
                dev->stereo=1;
97
        }
98
 
99
        if ((i=aci_rds_cmd(RDS_STATUS, &buf, 1))<0)
100
                return i;
101
        if (buf & 1)
102
                /* RDS available */
103
                *flags|=VIDEO_TUNER_RDS_ON;
104
        else
105
                return 0;
106
 
107
        if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0)
108
                return i;
109
        pr_debug("rds-signal: %d\n", buf);
110
        if (buf > 15) {
111
                printk("miropcm20-radio: RX strengths unexpected high...\n");
112
                buf=15;
113
        }
114
        /* refine signal */
115
        if ((*signal=SCALE(15, 0xffff, buf))==0)
116
                *signal = 1;
117
 
118
        return 0;
119
}
120
 
121
static int pcm20_do_ioctl(struct inode *inode, struct file *file,
122
                          unsigned int cmd, void *arg)
123
{
124
        struct video_device *dev = video_devdata(file);
125
        struct pcm20_device *pcm20 = dev->priv;
126
        int i;
127
 
128
        switch(cmd)
129
        {
130
                case VIDIOCGCAP:
131
                {
132
                        struct video_capability *v = arg;
133
                        memset(v,0,sizeof(*v));
134
                        v->type=VID_TYPE_TUNER;
135
                        strcpy(v->name, "Miro PCM20");
136
                        v->channels=1;
137
                        v->audios=1;
138
                        return 0;
139
                }
140
                case VIDIOCGTUNER:
141
                {
142
                        struct video_tuner *v = arg;
143
                        if(v->tuner)    /* Only 1 tuner */
144
                                return -EINVAL;
145
                        v->rangelow=87*16000;
146
                        v->rangehigh=108*16000;
147
                        pcm20_getflags(pcm20, &v->flags, &v->signal);
148
                        v->flags|=VIDEO_TUNER_LOW;
149
                        v->mode=VIDEO_MODE_AUTO;
150
                        strcpy(v->name, "FM");
151
                        return 0;
152
                }
153
                case VIDIOCSTUNER:
154
                {
155
                        struct video_tuner *v = arg;
156
                        if(v->tuner!=0)
157
                                return -EINVAL;
158
                        /* Only 1 tuner so no setting needed ! */
159
                        return 0;
160
                }
161
                case VIDIOCGFREQ:
162
                {
163
                        unsigned long *freq = arg;
164
                        *freq = pcm20->freq;
165
                        return 0;
166
                }
167
                case VIDIOCSFREQ:
168
                {
169
                        unsigned long *freq = arg;
170
                        pcm20->freq = *freq;
171
                        i=pcm20_setfreq(pcm20, pcm20->freq);
172
                        pr_debug("First view (setfreq): 0x%x\n", i);
173
                        return i;
174
                }
175
                case VIDIOCGAUDIO:
176
                {
177
                        struct video_audio *v = arg;
178
                        memset(v,0, sizeof(*v));
179
                        v->flags=VIDEO_AUDIO_MUTABLE;
180
                        if (pcm20->muted)
181
                                v->flags|=VIDEO_AUDIO_MUTE;
182
                        v->mode=VIDEO_SOUND_STEREO;
183
                        if (pcm20->stereo)
184
                                v->mode|=VIDEO_SOUND_MONO;
185
                        /* v->step=2048; */
186
                        strcpy(v->name, "Radio");
187
                        return 0;
188
                }
189
                case VIDIOCSAUDIO:
190
                {
191
                        struct video_audio *v = arg;
192
                        if(v->audio)
193
                                return -EINVAL;
194
 
195
                        pcm20_mute(pcm20, !!(v->flags&VIDEO_AUDIO_MUTE));
196
                        if(v->flags&VIDEO_SOUND_MONO)
197
                                pcm20_stereo(pcm20, 0);
198
                        if(v->flags&VIDEO_SOUND_STEREO)
199
                                pcm20_stereo(pcm20, 1);
200
 
201
                        return 0;
202
                }
203
                default:
204
                        return -ENOIOCTLCMD;
205
        }
206
}
207
 
208
static int pcm20_ioctl(struct inode *inode, struct file *file,
209
                       unsigned int cmd, unsigned long arg)
210
{
211
        return video_usercopy(inode, file, cmd, arg, pcm20_do_ioctl);
212
}
213
 
214
static struct pcm20_device pcm20_unit = {
215
        .freq   = 87*16000,
216
        .muted  = 1,
217
};
218
 
219
static const struct file_operations pcm20_fops = {
220
        .owner          = THIS_MODULE,
221
        .open           = video_exclusive_open,
222
        .release        = video_exclusive_release,
223
        .ioctl          = pcm20_ioctl,
224
        .compat_ioctl   = v4l_compat_ioctl32,
225
        .llseek         = no_llseek,
226
};
227
 
228
static struct video_device pcm20_radio = {
229
        .owner          = THIS_MODULE,
230
        .name           = "Miro PCM 20 radio",
231
        .type           = VID_TYPE_TUNER,
232
        .fops           = &pcm20_fops,
233
        .priv           = &pcm20_unit
234
};
235
 
236
static int __init pcm20_init(void)
237
{
238
        if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1)
239
                goto video_register_device;
240
 
241
        if(attach_aci_rds()<0)
242
                goto attach_aci_rds;
243
 
244
        printk(KERN_INFO "Miro PCM20 radio card driver.\n");
245
 
246
        return 0;
247
 
248
 attach_aci_rds:
249
        video_unregister_device(&pcm20_radio);
250
 video_register_device:
251
        return -EINVAL;
252
}
253
 
254
MODULE_AUTHOR("Ruurd Reitsma");
255
MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card.");
256
MODULE_LICENSE("GPL");
257
 
258
static void __exit pcm20_cleanup(void)
259
{
260
        unload_aci_rds();
261
        video_unregister_device(&pcm20_radio);
262
}
263
 
264
module_init(pcm20_init);
265
module_exit(pcm20_cleanup);

powered by: WebSVN 2.1.0

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