diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2009-03-06 11:53:58 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-30 11:43:13 -0400 |
commit | 5ac3d5bf4aedf55721cf4f65ab44fb1f598585ce (patch) | |
tree | 7ecb431c7eee8f1638120aad0418b0c7071b8904 | |
parent | c32a9d7155307414bb6e120f4e6581a32ed708d3 (diff) |
V4L/DVB (10890): radio-terratec: convert to v4l2_device.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/radio/radio-terratec.c | 310 |
1 files changed, 147 insertions, 163 deletions
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index 0798d71abd00..5a37e0d797bf 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c | |||
@@ -28,15 +28,30 @@ | |||
28 | #include <linux/init.h> /* Initdata */ | 28 | #include <linux/init.h> /* Initdata */ |
29 | #include <linux/ioport.h> /* request_region */ | 29 | #include <linux/ioport.h> /* request_region */ |
30 | #include <linux/delay.h> /* udelay */ | 30 | #include <linux/delay.h> /* udelay */ |
31 | #include <asm/io.h> /* outb, outb_p */ | ||
32 | #include <asm/uaccess.h> /* copy to/from user */ | ||
33 | #include <linux/videodev2.h> /* kernel radio structs */ | 31 | #include <linux/videodev2.h> /* kernel radio structs */ |
34 | #include <media/v4l2-common.h> | 32 | #include <linux/mutex.h> |
33 | #include <linux/version.h> /* for KERNEL_VERSION MACRO */ | ||
34 | #include <linux/io.h> /* outb, outb_p */ | ||
35 | #include <linux/uaccess.h> /* copy to/from user */ | ||
36 | #include <media/v4l2-device.h> | ||
35 | #include <media/v4l2-ioctl.h> | 37 | #include <media/v4l2-ioctl.h> |
36 | #include <linux/spinlock.h> | ||
37 | 38 | ||
38 | #include <linux/version.h> /* for KERNEL_VERSION MACRO */ | 39 | MODULE_AUTHOR("R.OFFERMANNS & others"); |
39 | #define RADIO_VERSION KERNEL_VERSION(0,0,2) | 40 | MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card."); |
41 | MODULE_LICENSE("GPL"); | ||
42 | |||
43 | #ifndef CONFIG_RADIO_TERRATEC_PORT | ||
44 | #define CONFIG_RADIO_TERRATEC_PORT 0x590 | ||
45 | #endif | ||
46 | |||
47 | static int io = CONFIG_RADIO_TERRATEC_PORT; | ||
48 | static int radio_nr = -1; | ||
49 | |||
50 | module_param(io, int, 0); | ||
51 | MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)"); | ||
52 | module_param(radio_nr, int, 0); | ||
53 | |||
54 | #define RADIO_VERSION KERNEL_VERSION(0, 0, 2) | ||
40 | 55 | ||
41 | static struct v4l2_queryctrl radio_qctrl[] = { | 56 | static struct v4l2_queryctrl radio_qctrl[] = { |
42 | { | 57 | { |
@@ -57,13 +72,6 @@ static struct v4l2_queryctrl radio_qctrl[] = { | |||
57 | } | 72 | } |
58 | }; | 73 | }; |
59 | 74 | ||
60 | #ifndef CONFIG_RADIO_TERRATEC_PORT | ||
61 | #define CONFIG_RADIO_TERRATEC_PORT 0x590 | ||
62 | #endif | ||
63 | |||
64 | /**************** this ones are for the terratec *******************/ | ||
65 | #define BASEPORT 0x590 | ||
66 | #define VOLPORT 0x591 | ||
67 | #define WRT_DIS 0x00 | 75 | #define WRT_DIS 0x00 |
68 | #define CLK_OFF 0x00 | 76 | #define CLK_OFF 0x00 |
69 | #define IIC_DATA 0x01 | 77 | #define IIC_DATA 0x01 |
@@ -71,138 +79,124 @@ static struct v4l2_queryctrl radio_qctrl[] = { | |||
71 | #define DATA 0x04 | 79 | #define DATA 0x04 |
72 | #define CLK_ON 0x08 | 80 | #define CLK_ON 0x08 |
73 | #define WRT_EN 0x10 | 81 | #define WRT_EN 0x10 |
74 | /*******************************************************************/ | ||
75 | 82 | ||
76 | static int io = CONFIG_RADIO_TERRATEC_PORT; | 83 | struct terratec |
77 | static int radio_nr = -1; | ||
78 | static spinlock_t lock; | ||
79 | |||
80 | struct tt_device | ||
81 | { | 84 | { |
82 | unsigned long in_use; | 85 | struct v4l2_device v4l2_dev; |
83 | int port; | 86 | struct video_device vdev; |
87 | int io; | ||
84 | int curvol; | 88 | int curvol; |
85 | unsigned long curfreq; | 89 | unsigned long curfreq; |
86 | int muted; | 90 | int muted; |
91 | struct mutex lock; | ||
87 | }; | 92 | }; |
88 | 93 | ||
94 | static struct terratec terratec_card; | ||
89 | 95 | ||
90 | /* local things */ | 96 | /* local things */ |
91 | 97 | ||
92 | static void cardWriteVol(int volume) | 98 | static void tt_write_vol(struct terratec *tt, int volume) |
93 | { | 99 | { |
94 | int i; | 100 | int i; |
95 | volume = volume+(volume * 32); // change both channels | 101 | |
96 | spin_lock(&lock); | 102 | volume = volume + (volume * 32); /* change both channels */ |
97 | for (i=0;i<8;i++) | 103 | mutex_lock(&tt->lock); |
98 | { | 104 | for (i = 0; i < 8; i++) { |
99 | if (volume & (0x80>>i)) | 105 | if (volume & (0x80 >> i)) |
100 | outb(0x80, VOLPORT); | 106 | outb(0x80, tt->io + 1); |
101 | else outb(0x00, VOLPORT); | 107 | else |
108 | outb(0x00, tt->io + 1); | ||
102 | } | 109 | } |
103 | spin_unlock(&lock); | 110 | mutex_unlock(&tt->lock); |
104 | } | 111 | } |
105 | 112 | ||
106 | 113 | ||
107 | 114 | ||
108 | static void tt_mute(struct tt_device *dev) | 115 | static void tt_mute(struct terratec *tt) |
109 | { | 116 | { |
110 | dev->muted = 1; | 117 | tt->muted = 1; |
111 | cardWriteVol(0); | 118 | tt_write_vol(tt, 0); |
112 | } | 119 | } |
113 | 120 | ||
114 | static int tt_setvol(struct tt_device *dev, int vol) | 121 | static int tt_setvol(struct terratec *tt, int vol) |
115 | { | 122 | { |
116 | 123 | if (vol == tt->curvol) { /* requested volume = current */ | |
117 | // printk(KERN_ERR "setvol called, vol = %d\n", vol); | 124 | if (tt->muted) { /* user is unmuting the card */ |
118 | 125 | tt->muted = 0; | |
119 | if(vol == dev->curvol) { /* requested volume = current */ | 126 | tt_write_vol(tt, vol); /* enable card */ |
120 | if (dev->muted) { /* user is unmuting the card */ | ||
121 | dev->muted = 0; | ||
122 | cardWriteVol(vol); /* enable card */ | ||
123 | } | 127 | } |
124 | |||
125 | return 0; | 128 | return 0; |
126 | } | 129 | } |
127 | 130 | ||
128 | if(vol == 0) { /* volume = 0 means mute the card */ | 131 | if (vol == 0) { /* volume = 0 means mute the card */ |
129 | cardWriteVol(0); /* "turn off card" by setting vol to 0 */ | 132 | tt_write_vol(tt, 0); /* "turn off card" by setting vol to 0 */ |
130 | dev->curvol = vol; /* track the volume state! */ | 133 | tt->curvol = vol; /* track the volume state! */ |
131 | return 0; | 134 | return 0; |
132 | } | 135 | } |
133 | 136 | ||
134 | dev->muted = 0; | 137 | tt->muted = 0; |
135 | 138 | tt_write_vol(tt, vol); | |
136 | cardWriteVol(vol); | 139 | tt->curvol = vol; |
137 | |||
138 | dev->curvol = vol; | ||
139 | |||
140 | return 0; | 140 | return 0; |
141 | |||
142 | } | 141 | } |
143 | 142 | ||
144 | 143 | ||
145 | /* this is the worst part in this driver */ | 144 | /* this is the worst part in this driver */ |
146 | /* many more or less strange things are going on here, but hey, it works :) */ | 145 | /* many more or less strange things are going on here, but hey, it works :) */ |
147 | 146 | ||
148 | static int tt_setfreq(struct tt_device *dev, unsigned long freq1) | 147 | static int tt_setfreq(struct terratec *tt, unsigned long freq1) |
149 | { | 148 | { |
150 | int freq; | 149 | int freq; |
151 | int i; | 150 | int i; |
152 | int p; | 151 | int p; |
153 | int temp; | 152 | int temp; |
154 | long rest; | 153 | long rest; |
155 | |||
156 | unsigned char buffer[25]; /* we have to bit shift 25 registers */ | 154 | unsigned char buffer[25]; /* we have to bit shift 25 registers */ |
157 | freq = freq1/160; /* convert the freq. to a nice to handle value */ | ||
158 | for(i=24;i>-1;i--) | ||
159 | buffer[i]=0; | ||
160 | 155 | ||
161 | rest = freq*10+10700; /* i once had understood what is going on here */ | 156 | mutex_lock(&tt->lock); |
157 | |||
158 | tt->curfreq = freq1; | ||
159 | |||
160 | freq = freq1 / 160; /* convert the freq. to a nice to handle value */ | ||
161 | memset(buffer, 0, sizeof(buffer)); | ||
162 | |||
163 | rest = freq * 10 + 10700; /* I once had understood what is going on here */ | ||
162 | /* maybe some wise guy (friedhelm?) can comment this stuff */ | 164 | /* maybe some wise guy (friedhelm?) can comment this stuff */ |
163 | i=13; | 165 | i = 13; |
164 | p=10; | 166 | p = 10; |
165 | temp=102400; | 167 | temp = 102400; |
166 | while (rest!=0) | 168 | while (rest != 0) { |
167 | { | 169 | if (rest % temp == rest) |
168 | if (rest%temp == rest) | ||
169 | buffer[i] = 0; | 170 | buffer[i] = 0; |
170 | else | 171 | else { |
171 | { | ||
172 | buffer[i] = 1; | 172 | buffer[i] = 1; |
173 | rest = rest-temp; | 173 | rest = rest - temp; |
174 | } | 174 | } |
175 | i--; | 175 | i--; |
176 | p--; | 176 | p--; |
177 | temp = temp/2; | 177 | temp = temp / 2; |
178 | } | 178 | } |
179 | 179 | ||
180 | spin_lock(&lock); | 180 | for (i = 24; i > -1; i--) { /* bit shift the values to the radiocard */ |
181 | 181 | if (buffer[i] == 1) { | |
182 | for (i=24;i>-1;i--) /* bit shift the values to the radiocard */ | 182 | outb(WRT_EN | DATA, tt->io); |
183 | { | 183 | outb(WRT_EN | DATA | CLK_ON, tt->io); |
184 | if (buffer[i]==1) | 184 | outb(WRT_EN | DATA, tt->io); |
185 | { | 185 | } else { |
186 | outb(WRT_EN|DATA, BASEPORT); | 186 | outb(WRT_EN | 0x00, tt->io); |
187 | outb(WRT_EN|DATA|CLK_ON , BASEPORT); | 187 | outb(WRT_EN | 0x00 | CLK_ON, tt->io); |
188 | outb(WRT_EN|DATA, BASEPORT); | ||
189 | } | ||
190 | else | ||
191 | { | ||
192 | outb(WRT_EN|0x00, BASEPORT); | ||
193 | outb(WRT_EN|0x00|CLK_ON , BASEPORT); | ||
194 | } | 188 | } |
195 | } | 189 | } |
196 | outb(0x00, BASEPORT); | 190 | outb(0x00, tt->io); |
197 | 191 | ||
198 | spin_unlock(&lock); | 192 | mutex_unlock(&tt->lock); |
199 | 193 | ||
200 | return 0; | 194 | return 0; |
201 | } | 195 | } |
202 | 196 | ||
203 | static int tt_getsigstr(struct tt_device *dev) /* TODO */ | 197 | static int tt_getsigstr(struct terratec *tt) |
204 | { | 198 | { |
205 | if (inb(io) & 2) /* bit set = no signal present */ | 199 | if (inb(tt->io) & 2) /* bit set = no signal present */ |
206 | return 0; | 200 | return 0; |
207 | return 1; /* signal present */ | 201 | return 1; /* signal present */ |
208 | } | 202 | } |
@@ -212,53 +206,50 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
212 | { | 206 | { |
213 | strlcpy(v->driver, "radio-terratec", sizeof(v->driver)); | 207 | strlcpy(v->driver, "radio-terratec", sizeof(v->driver)); |
214 | strlcpy(v->card, "ActiveRadio", sizeof(v->card)); | 208 | strlcpy(v->card, "ActiveRadio", sizeof(v->card)); |
215 | sprintf(v->bus_info, "ISA"); | 209 | strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); |
216 | v->version = RADIO_VERSION; | 210 | v->version = RADIO_VERSION; |
217 | v->capabilities = V4L2_CAP_TUNER; | 211 | v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; |
218 | return 0; | 212 | return 0; |
219 | } | 213 | } |
220 | 214 | ||
221 | static int vidioc_g_tuner(struct file *file, void *priv, | 215 | static int vidioc_g_tuner(struct file *file, void *priv, |
222 | struct v4l2_tuner *v) | 216 | struct v4l2_tuner *v) |
223 | { | 217 | { |
224 | struct tt_device *tt = video_drvdata(file); | 218 | struct terratec *tt = video_drvdata(file); |
225 | 219 | ||
226 | if (v->index > 0) | 220 | if (v->index > 0) |
227 | return -EINVAL; | 221 | return -EINVAL; |
228 | 222 | ||
229 | strcpy(v->name, "FM"); | 223 | strlcpy(v->name, "FM", sizeof(v->name)); |
230 | v->type = V4L2_TUNER_RADIO; | 224 | v->type = V4L2_TUNER_RADIO; |
231 | v->rangelow = (87*16000); | 225 | v->rangelow = 87 * 16000; |
232 | v->rangehigh = (108*16000); | 226 | v->rangehigh = 108 * 16000; |
233 | v->rxsubchans = V4L2_TUNER_SUB_MONO; | 227 | v->rxsubchans = V4L2_TUNER_SUB_MONO; |
234 | v->capability = V4L2_TUNER_CAP_LOW; | 228 | v->capability = V4L2_TUNER_CAP_LOW; |
235 | v->audmode = V4L2_TUNER_MODE_MONO; | 229 | v->audmode = V4L2_TUNER_MODE_MONO; |
236 | v->signal = 0xFFFF*tt_getsigstr(tt); | 230 | v->signal = 0xFFFF * tt_getsigstr(tt); |
237 | return 0; | 231 | return 0; |
238 | } | 232 | } |
239 | 233 | ||
240 | static int vidioc_s_tuner(struct file *file, void *priv, | 234 | static int vidioc_s_tuner(struct file *file, void *priv, |
241 | struct v4l2_tuner *v) | 235 | struct v4l2_tuner *v) |
242 | { | 236 | { |
243 | if (v->index > 0) | 237 | return v->index ? -EINVAL : 0; |
244 | return -EINVAL; | ||
245 | return 0; | ||
246 | } | 238 | } |
247 | 239 | ||
248 | static int vidioc_s_frequency(struct file *file, void *priv, | 240 | static int vidioc_s_frequency(struct file *file, void *priv, |
249 | struct v4l2_frequency *f) | 241 | struct v4l2_frequency *f) |
250 | { | 242 | { |
251 | struct tt_device *tt = video_drvdata(file); | 243 | struct terratec *tt = video_drvdata(file); |
252 | 244 | ||
253 | tt->curfreq = f->frequency; | 245 | tt_setfreq(tt, f->frequency); |
254 | tt_setfreq(tt, tt->curfreq); | ||
255 | return 0; | 246 | return 0; |
256 | } | 247 | } |
257 | 248 | ||
258 | static int vidioc_g_frequency(struct file *file, void *priv, | 249 | static int vidioc_g_frequency(struct file *file, void *priv, |
259 | struct v4l2_frequency *f) | 250 | struct v4l2_frequency *f) |
260 | { | 251 | { |
261 | struct tt_device *tt = video_drvdata(file); | 252 | struct terratec *tt = video_drvdata(file); |
262 | 253 | ||
263 | f->type = V4L2_TUNER_RADIO; | 254 | f->type = V4L2_TUNER_RADIO; |
264 | f->frequency = tt->curfreq; | 255 | f->frequency = tt->curfreq; |
@@ -272,8 +263,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, | |||
272 | 263 | ||
273 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { | 264 | for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { |
274 | if (qc->id && qc->id == radio_qctrl[i].id) { | 265 | if (qc->id && qc->id == radio_qctrl[i].id) { |
275 | memcpy(qc, &(radio_qctrl[i]), | 266 | memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); |
276 | sizeof(*qc)); | ||
277 | return 0; | 267 | return 0; |
278 | } | 268 | } |
279 | } | 269 | } |
@@ -283,7 +273,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, | |||
283 | static int vidioc_g_ctrl(struct file *file, void *priv, | 273 | static int vidioc_g_ctrl(struct file *file, void *priv, |
284 | struct v4l2_control *ctrl) | 274 | struct v4l2_control *ctrl) |
285 | { | 275 | { |
286 | struct tt_device *tt = video_drvdata(file); | 276 | struct terratec *tt = video_drvdata(file); |
287 | 277 | ||
288 | switch (ctrl->id) { | 278 | switch (ctrl->id) { |
289 | case V4L2_CID_AUDIO_MUTE: | 279 | case V4L2_CID_AUDIO_MUTE: |
@@ -302,7 +292,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, | |||
302 | static int vidioc_s_ctrl(struct file *file, void *priv, | 292 | static int vidioc_s_ctrl(struct file *file, void *priv, |
303 | struct v4l2_control *ctrl) | 293 | struct v4l2_control *ctrl) |
304 | { | 294 | { |
305 | struct tt_device *tt = video_drvdata(file); | 295 | struct terratec *tt = video_drvdata(file); |
306 | 296 | ||
307 | switch (ctrl->id) { | 297 | switch (ctrl->id) { |
308 | case V4L2_CID_AUDIO_MUTE: | 298 | case V4L2_CID_AUDIO_MUTE: |
@@ -318,17 +308,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv, | |||
318 | return -EINVAL; | 308 | return -EINVAL; |
319 | } | 309 | } |
320 | 310 | ||
321 | static int vidioc_g_audio(struct file *file, void *priv, | ||
322 | struct v4l2_audio *a) | ||
323 | { | ||
324 | if (a->index > 1) | ||
325 | return -EINVAL; | ||
326 | |||
327 | strcpy(a->name, "Radio"); | ||
328 | a->capability = V4L2_AUDCAP_STEREO; | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | 311 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) |
333 | { | 312 | { |
334 | *i = 0; | 313 | *i = 0; |
@@ -337,36 +316,38 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | |||
337 | 316 | ||
338 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | 317 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) |
339 | { | 318 | { |
340 | if (i != 0) | 319 | return i ? -EINVAL : 0; |
341 | return -EINVAL; | ||
342 | return 0; | ||
343 | } | 320 | } |
344 | 321 | ||
345 | static int vidioc_s_audio(struct file *file, void *priv, | 322 | static int vidioc_g_audio(struct file *file, void *priv, |
346 | struct v4l2_audio *a) | 323 | struct v4l2_audio *a) |
347 | { | 324 | { |
348 | if (a->index != 0) | 325 | a->index = 0; |
349 | return -EINVAL; | 326 | strlcpy(a->name, "Radio", sizeof(a->name)); |
327 | a->capability = V4L2_AUDCAP_STEREO; | ||
350 | return 0; | 328 | return 0; |
351 | } | 329 | } |
352 | 330 | ||
353 | static struct tt_device terratec_unit; | 331 | static int vidioc_s_audio(struct file *file, void *priv, |
332 | struct v4l2_audio *a) | ||
333 | { | ||
334 | return a->index ? -EINVAL : 0; | ||
335 | } | ||
354 | 336 | ||
355 | static int terratec_exclusive_open(struct file *file) | 337 | static int terratec_open(struct file *file) |
356 | { | 338 | { |
357 | return test_and_set_bit(0, &terratec_unit.in_use) ? -EBUSY : 0; | 339 | return 0; |
358 | } | 340 | } |
359 | 341 | ||
360 | static int terratec_exclusive_release(struct file *file) | 342 | static int terratec_release(struct file *file) |
361 | { | 343 | { |
362 | clear_bit(0, &terratec_unit.in_use); | ||
363 | return 0; | 344 | return 0; |
364 | } | 345 | } |
365 | 346 | ||
366 | static const struct v4l2_file_operations terratec_fops = { | 347 | static const struct v4l2_file_operations terratec_fops = { |
367 | .owner = THIS_MODULE, | 348 | .owner = THIS_MODULE, |
368 | .open = terratec_exclusive_open, | 349 | .open = terratec_open, |
369 | .release = terratec_exclusive_release, | 350 | .release = terratec_release, |
370 | .ioctl = video_ioctl2, | 351 | .ioctl = video_ioctl2, |
371 | }; | 352 | }; |
372 | 353 | ||
@@ -385,60 +366,63 @@ static const struct v4l2_ioctl_ops terratec_ioctl_ops = { | |||
385 | .vidioc_s_input = vidioc_s_input, | 366 | .vidioc_s_input = vidioc_s_input, |
386 | }; | 367 | }; |
387 | 368 | ||
388 | static struct video_device terratec_radio = { | ||
389 | .name = "TerraTec ActiveRadio", | ||
390 | .fops = &terratec_fops, | ||
391 | .ioctl_ops = &terratec_ioctl_ops, | ||
392 | .release = video_device_release_empty, | ||
393 | }; | ||
394 | |||
395 | static int __init terratec_init(void) | 369 | static int __init terratec_init(void) |
396 | { | 370 | { |
397 | if(io==-1) | 371 | struct terratec *tt = &terratec_card; |
398 | { | 372 | struct v4l2_device *v4l2_dev = &tt->v4l2_dev; |
399 | printk(KERN_ERR "You must set an I/O address with io=0x???\n"); | 373 | int res; |
374 | |||
375 | strlcpy(v4l2_dev->name, "terratec", sizeof(v4l2_dev->name)); | ||
376 | tt->io = io; | ||
377 | if (tt->io == -1) { | ||
378 | v4l2_err(v4l2_dev, "you must set an I/O address with io=0x???\n"); | ||
400 | return -EINVAL; | 379 | return -EINVAL; |
401 | } | 380 | } |
402 | if (!request_region(io, 2, "terratec")) | 381 | if (!request_region(tt->io, 2, "terratec")) { |
403 | { | 382 | v4l2_err(v4l2_dev, "port 0x%x already in use\n", io); |
404 | printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io); | ||
405 | return -EBUSY; | 383 | return -EBUSY; |
406 | } | 384 | } |
407 | 385 | ||
408 | video_set_drvdata(&terratec_radio, &terratec_unit); | 386 | res = v4l2_device_register(NULL, v4l2_dev); |
387 | if (res < 0) { | ||
388 | release_region(tt->io, 2); | ||
389 | v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); | ||
390 | return res; | ||
391 | } | ||
392 | |||
393 | strlcpy(tt->vdev.name, v4l2_dev->name, sizeof(tt->vdev.name)); | ||
394 | tt->vdev.v4l2_dev = v4l2_dev; | ||
395 | tt->vdev.fops = &terratec_fops; | ||
396 | tt->vdev.ioctl_ops = &terratec_ioctl_ops; | ||
397 | tt->vdev.release = video_device_release_empty; | ||
398 | video_set_drvdata(&tt->vdev, tt); | ||
409 | 399 | ||
410 | spin_lock_init(&lock); | 400 | mutex_init(&tt->lock); |
411 | 401 | ||
412 | if (video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr) < 0) { | 402 | if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { |
413 | release_region(io,2); | 403 | v4l2_device_unregister(&tt->v4l2_dev); |
404 | release_region(tt->io, 2); | ||
414 | return -EINVAL; | 405 | return -EINVAL; |
415 | } | 406 | } |
416 | 407 | ||
417 | printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n"); | 408 | v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n"); |
418 | 409 | ||
419 | /* mute card - prevents noisy bootups */ | 410 | /* mute card - prevents noisy bootups */ |
420 | 411 | tt_write_vol(tt, 0); | |
421 | /* this ensures that the volume is all the way down */ | ||
422 | cardWriteVol(0); | ||
423 | terratec_unit.curvol = 0; | ||
424 | |||
425 | return 0; | 412 | return 0; |
426 | } | 413 | } |
427 | 414 | ||
428 | MODULE_AUTHOR("R.OFFERMANNS & others"); | 415 | static void __exit terratec_exit(void) |
429 | MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card."); | ||
430 | MODULE_LICENSE("GPL"); | ||
431 | module_param(io, int, 0); | ||
432 | MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)"); | ||
433 | module_param(radio_nr, int, 0); | ||
434 | |||
435 | static void __exit terratec_cleanup_module(void) | ||
436 | { | 416 | { |
437 | video_unregister_device(&terratec_radio); | 417 | struct terratec *tt = &terratec_card; |
438 | release_region(io,2); | 418 | struct v4l2_device *v4l2_dev = &tt->v4l2_dev; |
439 | printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n"); | 419 | |
420 | video_unregister_device(&tt->vdev); | ||
421 | v4l2_device_unregister(&tt->v4l2_dev); | ||
422 | release_region(tt->io, 2); | ||
423 | v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver unloaded.\n"); | ||
440 | } | 424 | } |
441 | 425 | ||
442 | module_init(terratec_init); | 426 | module_init(terratec_init); |
443 | module_exit(terratec_cleanup_module); | 427 | module_exit(terratec_exit); |
444 | 428 | ||