diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2009-03-06 11:53:26 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-30 11:43:13 -0400 |
commit | c32a9d7155307414bb6e120f4e6581a32ed708d3 (patch) | |
tree | 9defa21bbd429818daf9db6847c10383fae2e9be /drivers/media/radio/radio-sf16fmr2.c | |
parent | c41269fd9275cce88b90af644969c6a5e2067657 (diff) |
V4L/DVB (10889): radio-sf16fmr2: convert to v4l2_device.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/radio/radio-sf16fmr2.c')
-rw-r--r-- | drivers/media/radio/radio-sf16fmr2.c | 372 |
1 files changed, 175 insertions, 197 deletions
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index 92f17a347fa7..19fb7fec4135 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c | |||
@@ -18,40 +18,29 @@ | |||
18 | #include <linux/init.h> /* Initdata */ | 18 | #include <linux/init.h> /* Initdata */ |
19 | #include <linux/ioport.h> /* request_region */ | 19 | #include <linux/ioport.h> /* request_region */ |
20 | #include <linux/delay.h> /* udelay */ | 20 | #include <linux/delay.h> /* udelay */ |
21 | #include <asm/io.h> /* outb, outb_p */ | ||
22 | #include <asm/uaccess.h> /* copy to/from user */ | ||
23 | #include <linux/videodev2.h> /* kernel radio structs */ | 21 | #include <linux/videodev2.h> /* kernel radio structs */ |
24 | #include <media/v4l2-common.h> | ||
25 | #include <media/v4l2-ioctl.h> | ||
26 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
23 | #include <linux/version.h> /* for KERNEL_VERSION MACRO */ | ||
24 | #include <linux/io.h> /* outb, outb_p */ | ||
25 | #include <linux/uaccess.h> /* copy to/from user */ | ||
26 | #include <media/v4l2-device.h> | ||
27 | #include <media/v4l2-ioctl.h> | ||
27 | 28 | ||
28 | static struct mutex lock; | 29 | MODULE_AUTHOR("Ziglio Frediano, freddy77@angelfire.com"); |
30 | MODULE_DESCRIPTION("A driver for the SF16FMR2 radio."); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | static int io = 0x384; | ||
34 | static int radio_nr = -1; | ||
35 | |||
36 | module_param(io, int, 0); | ||
37 | MODULE_PARM_DESC(io, "I/O address of the SF16FMR2 card (should be 0x384, if do not work try 0x284)"); | ||
38 | module_param(radio_nr, int, 0); | ||
29 | 39 | ||
30 | #include <linux/version.h> /* for KERNEL_VERSION MACRO */ | ||
31 | #define RADIO_VERSION KERNEL_VERSION(0,0,2) | 40 | #define RADIO_VERSION KERNEL_VERSION(0,0,2) |
32 | 41 | ||
33 | #define AUD_VOL_INDEX 1 | 42 | #define AUD_VOL_INDEX 1 |
34 | 43 | ||
35 | static struct v4l2_queryctrl radio_qctrl[] = { | ||
36 | { | ||
37 | .id = V4L2_CID_AUDIO_MUTE, | ||
38 | .name = "Mute", | ||
39 | .minimum = 0, | ||
40 | .maximum = 1, | ||
41 | .default_value = 1, | ||
42 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
43 | }, | ||
44 | [AUD_VOL_INDEX] = { | ||
45 | .id = V4L2_CID_AUDIO_VOLUME, | ||
46 | .name = "Volume", | ||
47 | .minimum = 0, | ||
48 | .maximum = 15, | ||
49 | .step = 1, | ||
50 | .default_value = 0, | ||
51 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
52 | } | ||
53 | }; | ||
54 | |||
55 | #undef DEBUG | 44 | #undef DEBUG |
56 | //#define DEBUG 1 | 45 | //#define DEBUG 1 |
57 | 46 | ||
@@ -62,156 +51,160 @@ static struct v4l2_queryctrl radio_qctrl[] = { | |||
62 | #endif | 51 | #endif |
63 | 52 | ||
64 | /* this should be static vars for module size */ | 53 | /* this should be static vars for module size */ |
65 | struct fmr2_device | 54 | struct fmr2 |
66 | { | 55 | { |
67 | unsigned long in_use; | 56 | struct v4l2_device v4l2_dev; |
68 | int port; | 57 | struct video_device vdev; |
58 | struct mutex lock; | ||
59 | int io; | ||
69 | int curvol; /* 0-15 */ | 60 | int curvol; /* 0-15 */ |
70 | int mute; | 61 | int mute; |
71 | int stereo; /* card is producing stereo audio */ | 62 | int stereo; /* card is producing stereo audio */ |
72 | unsigned long curfreq; /* freq in kHz */ | 63 | unsigned long curfreq; /* freq in kHz */ |
73 | int card_type; | 64 | int card_type; |
74 | __u32 flags; | 65 | u32 flags; |
75 | }; | 66 | }; |
76 | 67 | ||
77 | static int io = 0x384; | 68 | static struct fmr2 fmr2_card; |
78 | static int radio_nr = -1; | ||
79 | 69 | ||
80 | /* hw precision is 12.5 kHz | 70 | /* hw precision is 12.5 kHz |
81 | * It is only useful to give freq in intervall of 200 (=0.0125Mhz), | 71 | * It is only useful to give freq in intervall of 200 (=0.0125Mhz), |
82 | * other bits will be truncated | 72 | * other bits will be truncated |
83 | */ | 73 | */ |
84 | #define RSF16_ENCODE(x) ((x)/200+856) | 74 | #define RSF16_ENCODE(x) ((x) / 200 + 856) |
85 | #define RSF16_MINFREQ 87*16000 | 75 | #define RSF16_MINFREQ (87 * 16000) |
86 | #define RSF16_MAXFREQ 108*16000 | 76 | #define RSF16_MAXFREQ (108 * 16000) |
87 | 77 | ||
88 | static inline void wait(int n,int port) | 78 | static inline void wait(int n, int io) |
89 | { | 79 | { |
90 | for (;n;--n) inb(port); | 80 | for (; n; --n) |
81 | inb(io); | ||
91 | } | 82 | } |
92 | 83 | ||
93 | static void outbits(int bits, unsigned int data, int nWait, int port) | 84 | static void outbits(int bits, unsigned int data, int nWait, int io) |
94 | { | 85 | { |
95 | int bit; | 86 | int bit; |
96 | for(;--bits>=0;) { | 87 | |
97 | bit = (data>>bits) & 1; | 88 | for (; --bits >= 0;) { |
98 | outb(bit,port); | 89 | bit = (data >> bits) & 1; |
99 | wait(nWait,port); | 90 | outb(bit, io); |
100 | outb(bit|2,port); | 91 | wait(nWait, io); |
101 | wait(nWait,port); | 92 | outb(bit | 2, io); |
102 | outb(bit,port); | 93 | wait(nWait, io); |
103 | wait(nWait,port); | 94 | outb(bit, io); |
95 | wait(nWait, io); | ||
104 | } | 96 | } |
105 | } | 97 | } |
106 | 98 | ||
107 | static inline void fmr2_mute(int port) | 99 | static inline void fmr2_mute(int io) |
108 | { | 100 | { |
109 | outb(0x00, port); | 101 | outb(0x00, io); |
110 | wait(4,port); | 102 | wait(4, io); |
111 | } | 103 | } |
112 | 104 | ||
113 | static inline void fmr2_unmute(int port) | 105 | static inline void fmr2_unmute(int io) |
114 | { | 106 | { |
115 | outb(0x04, port); | 107 | outb(0x04, io); |
116 | wait(4,port); | 108 | wait(4, io); |
117 | } | 109 | } |
118 | 110 | ||
119 | static inline int fmr2_stereo_mode(int port) | 111 | static inline int fmr2_stereo_mode(int io) |
120 | { | 112 | { |
121 | int n = inb(port); | 113 | int n = inb(io); |
122 | outb(6,port); | 114 | |
123 | inb(port); | 115 | outb(6, io); |
124 | n = ((n>>3)&1)^1; | 116 | inb(io); |
117 | n = ((n >> 3) & 1) ^ 1; | ||
125 | debug_print((KERN_DEBUG "stereo: %d\n", n)); | 118 | debug_print((KERN_DEBUG "stereo: %d\n", n)); |
126 | return n; | 119 | return n; |
127 | } | 120 | } |
128 | 121 | ||
129 | static int fmr2_product_info(struct fmr2_device *dev) | 122 | static int fmr2_product_info(struct fmr2 *dev) |
130 | { | 123 | { |
131 | int n = inb(dev->port); | 124 | int n = inb(dev->io); |
125 | |||
132 | n &= 0xC1; | 126 | n &= 0xC1; |
133 | if (n == 0) | 127 | if (n == 0) { |
134 | { | ||
135 | /* this should support volume set */ | 128 | /* this should support volume set */ |
136 | dev->card_type = 12; | 129 | dev->card_type = 12; |
137 | return 0; | 130 | return 0; |
138 | } | 131 | } |
139 | /* not volume (mine is 11) */ | 132 | /* not volume (mine is 11) */ |
140 | dev->card_type = (n==128)?11:0; | 133 | dev->card_type = (n == 128) ? 11 : 0; |
141 | return n; | 134 | return n; |
142 | } | 135 | } |
143 | 136 | ||
144 | static inline int fmr2_getsigstr(struct fmr2_device *dev) | 137 | static inline int fmr2_getsigstr(struct fmr2 *dev) |
145 | { | 138 | { |
146 | /* !!! work only if scanning freq */ | 139 | /* !!! works only if scanning freq */ |
147 | int port = dev->port, res = 0xffff; | 140 | int res = 0xffff; |
148 | outb(5,port); | 141 | |
149 | wait(4,port); | 142 | outb(5, dev->io); |
150 | if (!(inb(port)&1)) res = 0; | 143 | wait(4, dev->io); |
144 | if (!(inb(dev->io) & 1)) | ||
145 | res = 0; | ||
151 | debug_print((KERN_DEBUG "signal: %d\n", res)); | 146 | debug_print((KERN_DEBUG "signal: %d\n", res)); |
152 | return res; | 147 | return res; |
153 | } | 148 | } |
154 | 149 | ||
155 | /* set frequency and unmute card */ | 150 | /* set frequency and unmute card */ |
156 | static int fmr2_setfreq(struct fmr2_device *dev) | 151 | static int fmr2_setfreq(struct fmr2 *dev) |
157 | { | 152 | { |
158 | int port = dev->port; | ||
159 | unsigned long freq = dev->curfreq; | 153 | unsigned long freq = dev->curfreq; |
160 | 154 | ||
161 | fmr2_mute(port); | 155 | fmr2_mute(dev->io); |
162 | 156 | ||
163 | /* 0x42 for mono output | 157 | /* 0x42 for mono output |
164 | * 0x102 forward scanning | 158 | * 0x102 forward scanning |
165 | * 0x182 scansione avanti | 159 | * 0x182 scansione avanti |
166 | */ | 160 | */ |
167 | outbits(9,0x2,3,port); | 161 | outbits(9, 0x2, 3, dev->io); |
168 | outbits(16,RSF16_ENCODE(freq),2,port); | 162 | outbits(16, RSF16_ENCODE(freq), 2, dev->io); |
169 | 163 | ||
170 | fmr2_unmute(port); | 164 | fmr2_unmute(dev->io); |
171 | 165 | ||
172 | /* wait 0.11 sec */ | 166 | /* wait 0.11 sec */ |
173 | msleep(110); | 167 | msleep(110); |
174 | 168 | ||
175 | /* NOTE if mute this stop radio | 169 | /* NOTE if mute this stop radio |
176 | you must set freq on unmute */ | 170 | you must set freq on unmute */ |
177 | dev->stereo = fmr2_stereo_mode(port); | 171 | dev->stereo = fmr2_stereo_mode(dev->io); |
178 | return 0; | 172 | return 0; |
179 | } | 173 | } |
180 | 174 | ||
181 | /* !!! not tested, in my card this does't work !!! */ | 175 | /* !!! not tested, in my card this does't work !!! */ |
182 | static int fmr2_setvolume(struct fmr2_device *dev) | 176 | static int fmr2_setvolume(struct fmr2 *dev) |
183 | { | 177 | { |
184 | int vol[16] = { 0x021, 0x084, 0x090, 0x104, | 178 | int vol[16] = { 0x021, 0x084, 0x090, 0x104, |
185 | 0x110, 0x204, 0x210, 0x402, | 179 | 0x110, 0x204, 0x210, 0x402, |
186 | 0x404, 0x408, 0x410, 0x801, | 180 | 0x404, 0x408, 0x410, 0x801, |
187 | 0x802, 0x804, 0x808, 0x810 }; | 181 | 0x802, 0x804, 0x808, 0x810 }; |
188 | int i, a, port = dev->port; | 182 | int i, a; |
189 | int n = vol[dev->curvol & 0x0f]; | 183 | int n = vol[dev->curvol & 0x0f]; |
190 | 184 | ||
191 | if (dev->card_type != 11) | 185 | if (dev->card_type != 11) |
192 | return 1; | 186 | return 1; |
193 | 187 | ||
194 | for (i = 12; --i >= 0; ) { | 188 | for (i = 12; --i >= 0; ) { |
195 | a = ((n >> i) & 1) << 6; /* if (a=0) a= 0; else a= 0x40; */ | 189 | a = ((n >> i) & 1) << 6; /* if (a==0) a = 0; else a = 0x40; */ |
196 | outb(a | 4, port); | 190 | outb(a | 4, dev->io); |
197 | wait(4, port); | 191 | wait(4, dev->io); |
198 | outb(a | 0x24, port); | 192 | outb(a | 0x24, dev->io); |
199 | wait(4, port); | 193 | wait(4, dev->io); |
200 | outb(a | 4, port); | 194 | outb(a | 4, dev->io); |
201 | wait(4, port); | 195 | wait(4, dev->io); |
202 | } | 196 | } |
203 | for (i = 6; --i >= 0; ) { | 197 | for (i = 6; --i >= 0; ) { |
204 | a = ((0x18 >> i) & 1) << 6; | 198 | a = ((0x18 >> i) & 1) << 6; |
205 | outb(a | 4, port); | 199 | outb(a | 4, dev->io); |
206 | wait(4,port); | 200 | wait(4, dev->io); |
207 | outb(a | 0x24, port); | 201 | outb(a | 0x24, dev->io); |
208 | wait(4,port); | 202 | wait(4, dev->io); |
209 | outb(a|4, port); | 203 | outb(a | 4, dev->io); |
210 | wait(4,port); | 204 | wait(4, dev->io); |
211 | } | 205 | } |
212 | wait(4, port); | 206 | wait(4, dev->io); |
213 | outb(0x14, port); | 207 | outb(0x14, dev->io); |
214 | |||
215 | return 0; | 208 | return 0; |
216 | } | 209 | } |
217 | 210 | ||
@@ -220,9 +213,9 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
220 | { | 213 | { |
221 | strlcpy(v->driver, "radio-sf16fmr2", sizeof(v->driver)); | 214 | strlcpy(v->driver, "radio-sf16fmr2", sizeof(v->driver)); |
222 | strlcpy(v->card, "SF16-FMR2 radio", sizeof(v->card)); | 215 | strlcpy(v->card, "SF16-FMR2 radio", sizeof(v->card)); |
223 | sprintf(v->bus_info, "ISA"); | 216 | strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); |
224 | v->version = RADIO_VERSION; | 217 | v->version = RADIO_VERSION; |
225 | v->capabilities = V4L2_CAP_TUNER; | 218 | v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; |
226 | return 0; | 219 | return 0; |
227 | } | 220 | } |
228 | 221 | ||
@@ -230,54 +223,52 @@ static int vidioc_g_tuner(struct file *file, void *priv, | |||
230 | struct v4l2_tuner *v) | 223 | struct v4l2_tuner *v) |
231 | { | 224 | { |
232 | int mult; | 225 | int mult; |
233 | struct fmr2_device *fmr2 = video_drvdata(file); | 226 | struct fmr2 *fmr2 = video_drvdata(file); |
234 | 227 | ||
235 | if (v->index > 0) | 228 | if (v->index > 0) |
236 | return -EINVAL; | 229 | return -EINVAL; |
237 | 230 | ||
238 | strcpy(v->name, "FM"); | 231 | strlcpy(v->name, "FM", sizeof(v->name)); |
239 | v->type = V4L2_TUNER_RADIO; | 232 | v->type = V4L2_TUNER_RADIO; |
240 | 233 | ||
241 | mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000; | 234 | mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000; |
242 | v->rangelow = RSF16_MINFREQ/mult; | 235 | v->rangelow = RSF16_MINFREQ / mult; |
243 | v->rangehigh = RSF16_MAXFREQ/mult; | 236 | v->rangehigh = RSF16_MAXFREQ / mult; |
244 | v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO; | 237 | v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO; |
245 | v->capability = fmr2->flags&V4L2_TUNER_CAP_LOW; | 238 | v->capability = fmr2->flags&V4L2_TUNER_CAP_LOW; |
246 | v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO: | 239 | v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO: |
247 | V4L2_TUNER_MODE_MONO; | 240 | V4L2_TUNER_MODE_MONO; |
248 | mutex_lock(&lock); | 241 | mutex_lock(&fmr2->lock); |
249 | v->signal = fmr2_getsigstr(fmr2); | 242 | v->signal = fmr2_getsigstr(fmr2); |
250 | mutex_unlock(&lock); | 243 | mutex_unlock(&fmr2->lock); |
251 | return 0; | 244 | return 0; |
252 | } | 245 | } |
253 | 246 | ||
254 | static int vidioc_s_tuner(struct file *file, void *priv, | 247 | static int vidioc_s_tuner(struct file *file, void *priv, |
255 | struct v4l2_tuner *v) | 248 | struct v4l2_tuner *v) |
256 | { | 249 | { |
257 | if (v->index > 0) | 250 | return v->index ? -EINVAL : 0; |
258 | return -EINVAL; | ||
259 | return 0; | ||
260 | } | 251 | } |
261 | 252 | ||
262 | static int vidioc_s_frequency(struct file *file, void *priv, | 253 | static int vidioc_s_frequency(struct file *file, void *priv, |
263 | struct v4l2_frequency *f) | 254 | struct v4l2_frequency *f) |
264 | { | 255 | { |
265 | struct fmr2_device *fmr2 = video_drvdata(file); | 256 | struct fmr2 *fmr2 = video_drvdata(file); |
266 | 257 | ||
267 | if (!(fmr2->flags & V4L2_TUNER_CAP_LOW)) | 258 | if (!(fmr2->flags & V4L2_TUNER_CAP_LOW)) |
268 | f->frequency *= 1000; | 259 | f->frequency *= 1000; |
269 | if (f->frequency < RSF16_MINFREQ || | 260 | if (f->frequency < RSF16_MINFREQ || |
270 | f->frequency > RSF16_MAXFREQ ) | 261 | f->frequency > RSF16_MAXFREQ) |
271 | return -EINVAL; | 262 | return -EINVAL; |
272 | /*rounding in steps of 200 to match th freq | 263 | /* rounding in steps of 200 to match the freq |
273 | that will be used */ | 264 | that will be used */ |
274 | fmr2->curfreq = (f->frequency/200)*200; | 265 | fmr2->curfreq = (f->frequency / 200) * 200; |
275 | 266 | ||
276 | /* set card freq (if not muted) */ | 267 | /* set card freq (if not muted) */ |
277 | if (fmr2->curvol && !fmr2->mute) { | 268 | if (fmr2->curvol && !fmr2->mute) { |
278 | mutex_lock(&lock); | 269 | mutex_lock(&fmr2->lock); |
279 | fmr2_setfreq(fmr2); | 270 | fmr2_setfreq(fmr2); |
280 | mutex_unlock(&lock); | 271 | mutex_unlock(&fmr2->lock); |
281 | } | 272 | } |
282 | return 0; | 273 | return 0; |
283 | } | 274 | } |
@@ -285,7 +276,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
285 | static int vidioc_g_frequency(struct file *file, void *priv, | 276 | static int vidioc_g_frequency(struct file *file, void *priv, |
286 | struct v4l2_frequency *f) | 277 | struct v4l2_frequency *f) |
287 | { | 278 | { |
288 | struct fmr2_device *fmr2 = video_drvdata(file); | 279 | struct fmr2 *fmr2 = video_drvdata(file); |
289 | 280 | ||
290 | f->type = V4L2_TUNER_RADIO; | 281 | f->type = V4L2_TUNER_RADIO; |
291 | f->frequency = fmr2->curfreq; | 282 | f->frequency = fmr2->curfreq; |
@@ -297,13 +288,16 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
297 | static int vidioc_queryctrl(struct file *file, void *priv, | 288 | static int vidioc_queryctrl(struct file *file, void *priv, |
298 | struct v4l2_queryctrl *qc) | 289 | struct v4l2_queryctrl *qc) |
299 | { | 290 | { |
300 | int i; | 291 | struct fmr2 *fmr2 = video_drvdata(file); |
301 | 292 | ||
302 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | 293 | switch (qc->id) { |
303 | if (qc->id && qc->id == radio_qctrl[i].id) { | 294 | case V4L2_CID_AUDIO_MUTE: |
304 | memcpy(qc, &radio_qctrl[i], sizeof(*qc)); | 295 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); |
305 | return 0; | 296 | case V4L2_CID_AUDIO_VOLUME: |
306 | } | 297 | /* Only card_type == 11 implements volume */ |
298 | if (fmr2->card_type == 11) | ||
299 | return v4l2_ctrl_query_fill(qc, 0, 15, 1, 0); | ||
300 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | ||
307 | } | 301 | } |
308 | return -EINVAL; | 302 | return -EINVAL; |
309 | } | 303 | } |
@@ -311,7 +305,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, | |||
311 | static int vidioc_g_ctrl(struct file *file, void *priv, | 305 | static int vidioc_g_ctrl(struct file *file, void *priv, |
312 | struct v4l2_control *ctrl) | 306 | struct v4l2_control *ctrl) |
313 | { | 307 | { |
314 | struct fmr2_device *fmr2 = video_drvdata(file); | 308 | struct fmr2 *fmr2 = video_drvdata(file); |
315 | 309 | ||
316 | switch (ctrl->id) { | 310 | switch (ctrl->id) { |
317 | case V4L2_CID_AUDIO_MUTE: | 311 | case V4L2_CID_AUDIO_MUTE: |
@@ -327,18 +321,14 @@ static int vidioc_g_ctrl(struct file *file, void *priv, | |||
327 | static int vidioc_s_ctrl(struct file *file, void *priv, | 321 | static int vidioc_s_ctrl(struct file *file, void *priv, |
328 | struct v4l2_control *ctrl) | 322 | struct v4l2_control *ctrl) |
329 | { | 323 | { |
330 | struct fmr2_device *fmr2 = video_drvdata(file); | 324 | struct fmr2 *fmr2 = video_drvdata(file); |
331 | 325 | ||
332 | switch (ctrl->id) { | 326 | switch (ctrl->id) { |
333 | case V4L2_CID_AUDIO_MUTE: | 327 | case V4L2_CID_AUDIO_MUTE: |
334 | fmr2->mute = ctrl->value; | 328 | fmr2->mute = ctrl->value; |
335 | break; | 329 | break; |
336 | case V4L2_CID_AUDIO_VOLUME: | 330 | case V4L2_CID_AUDIO_VOLUME: |
337 | if (ctrl->value > radio_qctrl[AUD_VOL_INDEX].maximum) | 331 | fmr2->curvol = ctrl->value; |
338 | fmr2->curvol = radio_qctrl[AUD_VOL_INDEX].maximum; | ||
339 | else | ||
340 | fmr2->curvol = ctrl->value; | ||
341 | |||
342 | break; | 332 | break; |
343 | default: | 333 | default: |
344 | return -EINVAL; | 334 | return -EINVAL; |
@@ -351,25 +341,14 @@ static int vidioc_s_ctrl(struct file *file, void *priv, | |||
351 | printk(KERN_DEBUG "mute\n"); | 341 | printk(KERN_DEBUG "mute\n"); |
352 | #endif | 342 | #endif |
353 | 343 | ||
354 | mutex_lock(&lock); | 344 | mutex_lock(&fmr2->lock); |
355 | if (fmr2->curvol && !fmr2->mute) { | 345 | if (fmr2->curvol && !fmr2->mute) { |
356 | fmr2_setvolume(fmr2); | 346 | fmr2_setvolume(fmr2); |
357 | /* Set frequency and unmute card */ | 347 | /* Set frequency and unmute card */ |
358 | fmr2_setfreq(fmr2); | 348 | fmr2_setfreq(fmr2); |
359 | } else | 349 | } else |
360 | fmr2_mute(fmr2->port); | 350 | fmr2_mute(fmr2->io); |
361 | mutex_unlock(&lock); | 351 | mutex_unlock(&fmr2->lock); |
362 | return 0; | ||
363 | } | ||
364 | |||
365 | static int vidioc_g_audio(struct file *file, void *priv, | ||
366 | struct v4l2_audio *a) | ||
367 | { | ||
368 | if (a->index > 1) | ||
369 | return -EINVAL; | ||
370 | |||
371 | strcpy(a->name, "Radio"); | ||
372 | a->capability = V4L2_AUDCAP_STEREO; | ||
373 | return 0; | 352 | return 0; |
374 | } | 353 | } |
375 | 354 | ||
@@ -381,36 +360,38 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | |||
381 | 360 | ||
382 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | 361 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) |
383 | { | 362 | { |
384 | if (i != 0) | 363 | return i ? -EINVAL : 0; |
385 | return -EINVAL; | ||
386 | return 0; | ||
387 | } | 364 | } |
388 | 365 | ||
389 | static int vidioc_s_audio(struct file *file, void *priv, | 366 | static int vidioc_g_audio(struct file *file, void *priv, |
390 | struct v4l2_audio *a) | 367 | struct v4l2_audio *a) |
391 | { | 368 | { |
392 | if (a->index != 0) | 369 | a->index = 0; |
393 | return -EINVAL; | 370 | strlcpy(a->name, "Radio", sizeof(a->name)); |
371 | a->capability = V4L2_AUDCAP_STEREO; | ||
394 | return 0; | 372 | return 0; |
395 | } | 373 | } |
396 | 374 | ||
397 | static struct fmr2_device fmr2_unit; | 375 | static int vidioc_s_audio(struct file *file, void *priv, |
376 | struct v4l2_audio *a) | ||
377 | { | ||
378 | return a->index ? -EINVAL : 0; | ||
379 | } | ||
398 | 380 | ||
399 | static int fmr2_exclusive_open(struct file *file) | 381 | static int fmr2_open(struct file *file) |
400 | { | 382 | { |
401 | return test_and_set_bit(0, &fmr2_unit.in_use) ? -EBUSY : 0; | 383 | return 0; |
402 | } | 384 | } |
403 | 385 | ||
404 | static int fmr2_exclusive_release(struct file *file) | 386 | static int fmr2_release(struct file *file) |
405 | { | 387 | { |
406 | clear_bit(0, &fmr2_unit.in_use); | ||
407 | return 0; | 388 | return 0; |
408 | } | 389 | } |
409 | 390 | ||
410 | static const struct v4l2_file_operations fmr2_fops = { | 391 | static const struct v4l2_file_operations fmr2_fops = { |
411 | .owner = THIS_MODULE, | 392 | .owner = THIS_MODULE, |
412 | .open = fmr2_exclusive_open, | 393 | .open = fmr2_open, |
413 | .release = fmr2_exclusive_release, | 394 | .release = fmr2_release, |
414 | .ioctl = video_ioctl2, | 395 | .ioctl = video_ioctl2, |
415 | }; | 396 | }; |
416 | 397 | ||
@@ -429,67 +410,64 @@ static const struct v4l2_ioctl_ops fmr2_ioctl_ops = { | |||
429 | .vidioc_s_ctrl = vidioc_s_ctrl, | 410 | .vidioc_s_ctrl = vidioc_s_ctrl, |
430 | }; | 411 | }; |
431 | 412 | ||
432 | static struct video_device fmr2_radio = { | ||
433 | .name = "SF16FMR2 radio", | ||
434 | .fops = &fmr2_fops, | ||
435 | .ioctl_ops = &fmr2_ioctl_ops, | ||
436 | .release = video_device_release_empty, | ||
437 | }; | ||
438 | |||
439 | static int __init fmr2_init(void) | 413 | static int __init fmr2_init(void) |
440 | { | 414 | { |
441 | fmr2_unit.port = io; | 415 | struct fmr2 *fmr2 = &fmr2_card; |
442 | fmr2_unit.curvol = 0; | 416 | struct v4l2_device *v4l2_dev = &fmr2->v4l2_dev; |
443 | fmr2_unit.mute = 0; | 417 | int res; |
444 | fmr2_unit.curfreq = 0; | 418 | |
445 | fmr2_unit.stereo = 1; | 419 | strlcpy(v4l2_dev->name, "sf16fmr2", sizeof(v4l2_dev->name)); |
446 | fmr2_unit.flags = V4L2_TUNER_CAP_LOW; | 420 | fmr2->io = io; |
447 | fmr2_unit.card_type = 0; | 421 | fmr2->stereo = 1; |
448 | video_set_drvdata(&fmr2_radio, &fmr2_unit); | 422 | fmr2->flags = V4L2_TUNER_CAP_LOW; |
449 | 423 | mutex_init(&fmr2->lock); | |
450 | mutex_init(&lock); | 424 | |
451 | 425 | if (!request_region(fmr2->io, 2, "sf16fmr2")) { | |
452 | if (!request_region(io, 2, "sf16fmr2")) { | 426 | v4l2_err(v4l2_dev, "request_region failed!\n"); |
453 | printk(KERN_ERR "radio-sf16fmr2: request_region failed!\n"); | ||
454 | return -EBUSY; | 427 | return -EBUSY; |
455 | } | 428 | } |
456 | 429 | ||
457 | if (video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr) < 0) { | 430 | res = v4l2_device_register(NULL, v4l2_dev); |
458 | release_region(io, 2); | 431 | if (res < 0) { |
459 | return -EINVAL; | 432 | release_region(fmr2->io, 2); |
433 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | ||
434 | return res; | ||
460 | } | 435 | } |
461 | 436 | ||
462 | printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io); | 437 | strlcpy(fmr2->vdev.name, v4l2_dev->name, sizeof(fmr2->vdev.name)); |
463 | /* mute card - prevents noisy bootups */ | 438 | fmr2->vdev.v4l2_dev = v4l2_dev; |
464 | mutex_lock(&lock); | 439 | fmr2->vdev.fops = &fmr2_fops; |
465 | fmr2_mute(io); | 440 | fmr2->vdev.ioctl_ops = &fmr2_ioctl_ops; |
466 | fmr2_product_info(&fmr2_unit); | 441 | fmr2->vdev.release = video_device_release_empty; |
467 | mutex_unlock(&lock); | 442 | video_set_drvdata(&fmr2->vdev, fmr2); |
468 | debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type)); | ||
469 | 443 | ||
470 | /* Only card_type == 11 implements volume */ | 444 | if (video_register_device(&fmr2->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { |
471 | if (fmr2_unit.card_type != 11) | 445 | v4l2_device_unregister(v4l2_dev); |
472 | radio_qctrl[AUD_VOL_INDEX].maximum = 1; | 446 | release_region(fmr2->io, 2); |
447 | return -EINVAL; | ||
448 | } | ||
473 | 449 | ||
450 | v4l2_info(v4l2_dev, "SF16FMR2 radio card driver at 0x%x.\n", fmr2->io); | ||
451 | /* mute card - prevents noisy bootups */ | ||
452 | mutex_lock(&fmr2->lock); | ||
453 | fmr2_mute(fmr2->io); | ||
454 | fmr2_product_info(fmr2); | ||
455 | mutex_unlock(&fmr2->lock); | ||
456 | debug_print((KERN_DEBUG "card_type %d\n", fmr2->card_type)); | ||
474 | return 0; | 457 | return 0; |
475 | } | 458 | } |
476 | 459 | ||
477 | MODULE_AUTHOR("Ziglio Frediano, freddy77@angelfire.com"); | 460 | static void __exit fmr2_exit(void) |
478 | MODULE_DESCRIPTION("A driver for the SF16FMR2 radio."); | ||
479 | MODULE_LICENSE("GPL"); | ||
480 | |||
481 | module_param(io, int, 0); | ||
482 | MODULE_PARM_DESC(io, "I/O address of the SF16FMR2 card (should be 0x384, if do not work try 0x284)"); | ||
483 | module_param(radio_nr, int, 0); | ||
484 | |||
485 | static void __exit fmr2_cleanup_module(void) | ||
486 | { | 461 | { |
487 | video_unregister_device(&fmr2_radio); | 462 | struct fmr2 *fmr2 = &fmr2_card; |
488 | release_region(io,2); | 463 | |
464 | video_unregister_device(&fmr2->vdev); | ||
465 | v4l2_device_unregister(&fmr2->v4l2_dev); | ||
466 | release_region(fmr2->io, 2); | ||
489 | } | 467 | } |
490 | 468 | ||
491 | module_init(fmr2_init); | 469 | module_init(fmr2_init); |
492 | module_exit(fmr2_cleanup_module); | 470 | module_exit(fmr2_exit); |
493 | 471 | ||
494 | #ifndef MODULE | 472 | #ifndef MODULE |
495 | 473 | ||