diff options
Diffstat (limited to 'drivers/media/radio/radio-sf16fmr2.c')
-rw-r--r-- | drivers/media/radio/radio-sf16fmr2.c | 61 |
1 files changed, 54 insertions, 7 deletions
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index 7ab9afadf29b..7c69214334bf 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c | |||
@@ -9,16 +9,23 @@ | |||
9 | #include <linux/delay.h> | 9 | #include <linux/delay.h> |
10 | #include <linux/module.h> /* Modules */ | 10 | #include <linux/module.h> /* Modules */ |
11 | #include <linux/init.h> /* Initdata */ | 11 | #include <linux/init.h> /* Initdata */ |
12 | #include <linux/slab.h> | ||
12 | #include <linux/ioport.h> /* request_region */ | 13 | #include <linux/ioport.h> /* request_region */ |
13 | #include <linux/io.h> /* outb, outb_p */ | 14 | #include <linux/io.h> /* outb, outb_p */ |
15 | #include <linux/isa.h> | ||
14 | #include <sound/tea575x-tuner.h> | 16 | #include <sound/tea575x-tuner.h> |
15 | 17 | ||
16 | MODULE_AUTHOR("Ondrej Zary"); | 18 | MODULE_AUTHOR("Ondrej Zary"); |
17 | MODULE_DESCRIPTION("MediaForte SF16-FMR2 FM radio card driver"); | 19 | MODULE_DESCRIPTION("MediaForte SF16-FMR2 FM radio card driver"); |
18 | MODULE_LICENSE("GPL"); | 20 | MODULE_LICENSE("GPL"); |
19 | 21 | ||
22 | static int radio_nr = -1; | ||
23 | module_param(radio_nr, int, 0444); | ||
24 | MODULE_PARM_DESC(radio_nr, "Radio device number"); | ||
25 | |||
20 | struct fmr2 { | 26 | struct fmr2 { |
21 | int io; | 27 | int io; |
28 | struct v4l2_device v4l2_dev; | ||
22 | struct snd_tea575x tea; | 29 | struct snd_tea575x tea; |
23 | struct v4l2_ctrl *volume; | 30 | struct v4l2_ctrl *volume; |
24 | struct v4l2_ctrl *balance; | 31 | struct v4l2_ctrl *balance; |
@@ -26,7 +33,6 @@ struct fmr2 { | |||
26 | 33 | ||
27 | /* the port is hardwired so no need to support multiple cards */ | 34 | /* the port is hardwired so no need to support multiple cards */ |
28 | #define FMR2_PORT 0x384 | 35 | #define FMR2_PORT 0x384 |
29 | static struct fmr2 fmr2_card; | ||
30 | 36 | ||
31 | /* TEA575x tuner pins */ | 37 | /* TEA575x tuner pins */ |
32 | #define STR_DATA (1 << 0) | 38 | #define STR_DATA (1 << 0) |
@@ -180,26 +186,46 @@ static int fmr2_tea_ext_init(struct snd_tea575x *tea) | |||
180 | return 0; | 186 | return 0; |
181 | } | 187 | } |
182 | 188 | ||
183 | static int __init fmr2_init(void) | 189 | static int __devinit fmr2_probe(struct device *pdev, unsigned int dev) |
184 | { | 190 | { |
185 | struct fmr2 *fmr2 = &fmr2_card; | 191 | struct fmr2 *fmr2; |
192 | int err; | ||
193 | |||
194 | fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL); | ||
195 | if (fmr2 == NULL) | ||
196 | return -ENOMEM; | ||
186 | 197 | ||
198 | strlcpy(fmr2->v4l2_dev.name, dev_name(pdev), | ||
199 | sizeof(fmr2->v4l2_dev.name)); | ||
187 | fmr2->io = FMR2_PORT; | 200 | fmr2->io = FMR2_PORT; |
188 | 201 | ||
189 | if (!request_region(fmr2->io, 2, "SF16-FMR2")) { | 202 | if (!request_region(fmr2->io, 2, fmr2->v4l2_dev.name)) { |
190 | printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io); | 203 | printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io); |
204 | kfree(fmr2); | ||
191 | return -EBUSY; | 205 | return -EBUSY; |
192 | } | 206 | } |
193 | 207 | ||
208 | dev_set_drvdata(pdev, fmr2); | ||
209 | err = v4l2_device_register(pdev, &fmr2->v4l2_dev); | ||
210 | if (err < 0) { | ||
211 | v4l2_err(&fmr2->v4l2_dev, "Could not register v4l2_device\n"); | ||
212 | release_region(fmr2->io, 2); | ||
213 | kfree(fmr2); | ||
214 | return err; | ||
215 | } | ||
216 | fmr2->tea.v4l2_dev = &fmr2->v4l2_dev; | ||
194 | fmr2->tea.private_data = fmr2; | 217 | fmr2->tea.private_data = fmr2; |
218 | fmr2->tea.radio_nr = radio_nr; | ||
195 | fmr2->tea.ops = &fmr2_tea_ops; | 219 | fmr2->tea.ops = &fmr2_tea_ops; |
196 | fmr2->tea.ext_init = fmr2_tea_ext_init; | 220 | fmr2->tea.ext_init = fmr2_tea_ext_init; |
197 | strlcpy(fmr2->tea.card, "SF16-FMR2", sizeof(fmr2->tea.card)); | 221 | strlcpy(fmr2->tea.card, "SF16-FMR2", sizeof(fmr2->tea.card)); |
198 | strcpy(fmr2->tea.bus_info, "ISA"); | 222 | snprintf(fmr2->tea.bus_info, sizeof(fmr2->tea.bus_info), "ISA:%s", |
223 | fmr2->v4l2_dev.name); | ||
199 | 224 | ||
200 | if (snd_tea575x_init(&fmr2->tea)) { | 225 | if (snd_tea575x_init(&fmr2->tea)) { |
201 | printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n"); | 226 | printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n"); |
202 | release_region(fmr2->io, 2); | 227 | release_region(fmr2->io, 2); |
228 | kfree(fmr2); | ||
203 | return -ENODEV; | 229 | return -ENODEV; |
204 | } | 230 | } |
205 | 231 | ||
@@ -207,12 +233,33 @@ static int __init fmr2_init(void) | |||
207 | return 0; | 233 | return 0; |
208 | } | 234 | } |
209 | 235 | ||
210 | static void __exit fmr2_exit(void) | 236 | static int __exit fmr2_remove(struct device *pdev, unsigned int dev) |
211 | { | 237 | { |
212 | struct fmr2 *fmr2 = &fmr2_card; | 238 | struct fmr2 *fmr2 = dev_get_drvdata(pdev); |
213 | 239 | ||
214 | snd_tea575x_exit(&fmr2->tea); | 240 | snd_tea575x_exit(&fmr2->tea); |
215 | release_region(fmr2->io, 2); | 241 | release_region(fmr2->io, 2); |
242 | v4l2_device_unregister(&fmr2->v4l2_dev); | ||
243 | kfree(fmr2); | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | struct isa_driver fmr2_driver = { | ||
248 | .probe = fmr2_probe, | ||
249 | .remove = fmr2_remove, | ||
250 | .driver = { | ||
251 | .name = "radio-sf16fmr2", | ||
252 | }, | ||
253 | }; | ||
254 | |||
255 | static int __init fmr2_init(void) | ||
256 | { | ||
257 | return isa_register_driver(&fmr2_driver, 1); | ||
258 | } | ||
259 | |||
260 | static void __exit fmr2_exit(void) | ||
261 | { | ||
262 | isa_unregister_driver(&fmr2_driver); | ||
216 | } | 263 | } |
217 | 264 | ||
218 | module_init(fmr2_init); | 265 | module_init(fmr2_init); |