radio-sf16fmr2: add PnP support for SF16-FMD2
PATCH RESEND 1/1 radio-sf16fmr2: add PnP support for SF16-FMD2
Add PnP support to radio-sf16fmr2 driver to support SF16-FMD2 card (SB16 + TEA5757). The driver can now handle two cards (FMR2 is hardwired to 0x384, FMD2 can be put at 0x384 or 0x284 by PnP).
Tested with both SF16-FMR2 and SF16-FMD2 (the can work at the same time by using kernel parameter "pnp_reserve_io=0x384,2" so the FMD2 is put at 0x284).
drivers/media/radio/Kconfig +1 -1
@@ -329,7 +329,7 @@ config RADIO_SF16FMI module will be called radio-sf16fmi. config RADIO_SF16FMR2 - tristate "SF16FMR2 Radio" + tristate "SF16-FMR2/SF16-FMD2 Radio" depends on ISA && VIDEO_V4L2 && SND ---help--- Choose Y here if you have one of these FM radio cards.
drivers/media/radio/radio-sf16fmr2.c +113 -31
226 lines not on this page · raw message
Signature · 1 line
Ondrej Zary
Quoted 7 lines · On Thu May 17 2012 10:55:01 Ondrej Zary wrote:
Add PnP support to radio-sf16fmr2 driver to support SF16-FMD2 card (SB16 + TEA5757). The driver can now handle two cards (FMR2 is hardwired to
0x384, FMD2 can be put at0x384or0x284by PnP).
Tested with both SF16-FMR2 and SF16-FMD2 (the can work at the same time by using kernel parameter "pnp_reserve_io=0x384,2" so the FMD2 is put at0x284).Signed-off-by Ondrej Zary <[email protected]>
Quoted 249 lines
drivers/media/radio/Kconfig +1
-1@@ -329,7 +329,7 @@ config RADIO_SF16FMI module will be called radio-sf16fmi. config RADIO_SF16FMR2 - tristate "SF16FMR2 Radio" + tristate "SF16-FMR2/SF16-FMD2 Radio" depends on ISA && VIDEO_V4L2 && SND ---help--- Choose Y here if you have one of these FM radio cards.drivers/media/radio/radio-sf16fmr2.c +113
-31@@ -1,4 +1,4 @@ -/* SF16-FMR2 radio driver for Linux +/* SF16-FMR2 and SF16-FMD2 radio driver for Linux * Copyright (c) 2011 Ondrej Zary * * Original driver was (c) 2000-2002 Ziglio Frediano, [email protected] @@ -13,15 +13,19 @@#include <linux/ioport.h> /* request_region */ #include <linux/io.h> /* outb, outb_p */ #include <linux/isa.h> +#include <linux/pnp.h> #include <sound/tea575x-tuner.h> MODULE_AUTHOR ("Ondrej Zary" ); -MODULE_DESCRIPTION ("MediaForte SF16-FMR2 FM radio card driver" ); +MODULE_DESCRIPTION ("MediaForte SF16-FMR2 and SF16-FMD2 FM radio card driver" );MODULE_LICENSE ("GPL" ); -static int radio_nr =-1 ; -module_param (radio_nr, int,0444 ); -MODULE_PARM_DESC (radio_nr,"Radio device number" ); +/* these cards can only use two different ports (0x384 and 0x284) */ +#define FMR2_MAX 2 + +static int radio_nr[FMR2_MAX ] = { [0 ... (FMR2_MAX -1 )] =-1 }; +module_param_array (radio_nr, int,NULL ,0444 ); +MODULE_PARM_DESC (radio_nr,"Radio device numbers" );struct fmr2 {int io;@@ -29,9 +33,15 @@ struct fmr2 {struct snd_tea575x tea;struct v4l2_ctrl *volume;struct v4l2_ctrl *balance; +bool is_fmd2; }; -/* the port is hardwired so no need to support multiple cards */ +static int num_fmr2_cards; +static struct fmr2 *fmr2_cards[FMR2_MAX ]; +static bool isa_registered; +static bool pnp_registered; + +/* the port is hardwired on SF16-FMR2 */ #define FMR2_PORT 0x384/* TEA575x tuner pins */ @@ -174,7 +184,8 @@ static int fmr2_tea_ext_init(struct snd_tea575x *tea) {struct fmr2 *fmr2 = tea->private_data; -if (inb (fmr2->io) &FMR2_HASVOL ) { +/* FMR2 can have volume control, FMD2 can't (uses SB16 mixer) */ +if (!fmr2->is_fmd2 &&inb (fmr2->io) &FMR2_HASVOL ) { fmr2->volume =v4l2_ctrl_new_std (&tea->ctrl_handler, &fmr2_ctrl_ops,V4L2_CID_AUDIO_VOLUME ,0 ,68 ,2 ,56 ); fmr2->balance =v4l2_ctrl_new_std (&tea->ctrl_handler, &fmr2_ctrl_ops,V4L2_CID_AUDIO_BALANCE ,-68 ,68 ,2 ,0 );if (tea->ctrl_handler.error) {@@ -186,22 +197,28 @@ static int fmr2_tea_ext_init(struct snd_tea575x *tea)return 0 ; } -static int __devinit fmr2_probe (struct device *pdev,unsigned int dev) +static struct pnp_device_id fmr2_pnp_ids[]__devinitdata = { + { .id ="MFRad13" },/* tuner subdevice of SF16-FMD2 */ + { .id ="" } +}; +MODULE_DEVICE_TABLE (pnp, fmr2_pnp_ids); + +static int __devinit fmr2_probe (struct fmr2 *fmr2,struct device *pdev,int io) { -struct fmr2 *fmr2; -int err; +int err, i; +char *card_name = fmr2->is_fmd2 ?"SF16-FMD2" :"SF16-FMR2" ; - fmr2 =kzalloc (sizeof (*fmr2),GFP_KERNEL ); -if (fmr2 ==NULL ) -return -ENOMEM ; +/* avoid errors if a card was already registered at given port */ +for (i =0 ; i < num_fmr2_cards; i++) +if (io == fmr2_cards[i]->io) +return -EBUSY ; -strlcpy (fmr2->v4l2_dev.name,dev_name (pdev), -sizeof (fmr2->v4l2_dev.name)); - fmr2->io =FMR2_PORT ; +strlcpy (fmr2->v4l2_dev.name,"radio-sf16fmr2" , +sizeof (fmr2->v4l2_dev.name)), + fmr2->io = io;if (!request_region (fmr2->io,2 , fmr2->v4l2_dev.name)) {printk (KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n" , fmr2->io); -kfree (fmr2);return -EBUSY ; }@@ -210,56 +227,121 @@ static int __devinit fmr2_probe(struct device *pdev, unsigned int dev)if (err <0 ) {v4l2_err (&fmr2->v4l2_dev,"Could not register v4l2_device\n" );release_region (fmr2->io,2 ); -kfree (fmr2);return err; } fmr2->tea.v4l2_dev = &fmr2->v4l2_dev; fmr2->tea.private_data = fmr2; - fmr2->tea.radio_nr = radio_nr; + fmr2->tea.radio_nr = radio_nr[num_fmr2_cards]; fmr2->tea.ops = &fmr2_tea_ops; fmr2->tea.ext_init = fmr2_tea_ext_init; -strlcpy (fmr2->tea.card,"SF16-FMR2" ,sizeof (fmr2->tea.card)); -snprintf (fmr2->tea.bus_info,sizeof (fmr2->tea.bus_info),"ISA:%s" , - fmr2->v4l2_dev.name); +strlcpy (fmr2->tea.card, card_name,sizeof (fmr2->tea.card)); +snprintf (fmr2->tea.bus_info,sizeof (fmr2->tea.bus_info),"%s:%s" , + fmr2->is_fmd2 ?"PnP" :"ISA" ,dev_name (pdev));if (snd_tea575x_init (&fmr2->tea)) {printk (KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n" );release_region (fmr2->io,2 ); -kfree (fmr2);return -ENODEV ; } -printk (KERN_INFO "radio-sf16fmr2: SF16-FMR2 radio card at 0x%x.\n" , fmr2->io); +printk (KERN_INFO "radio-sf16fmr2: %s radio card at 0x%x.\n" , + card_name, fmr2->io);return 0 ; } -static int __exit fmr2_remove(struct device *pdev, unsigned int dev) +static int __devinit fmr2_isa_match (struct device *pdev,unsigned int ndev) +{ +struct fmr2 *fmr2 =kzalloc (sizeof (*fmr2),GFP_KERNEL ); +if (!fmr2) +return 0 ; + +if (fmr2_probe (fmr2, pdev,FMR2_PORT )) { +kfree (fmr2); +return 0 ; + } +dev_set_drvdata (pdev, fmr2); + fmr2_cards[num_fmr2_cards++] = fmr2; + +return 1 ; +} + +static int __devinit fmr2_pnp_probe (struct pnp_dev *pdev, +const struct pnp_device_id *id) { -struct fmr2 *fmr2 =dev_get_drvdata (pdev); +int ret; +struct fmr2 *fmr2 =kzalloc (sizeof (*fmr2),GFP_KERNEL ); +if (!fmr2) +return -ENOMEM ; + fmr2->is_fmd2 = true; + ret =fmr2_probe (fmr2, &pdev->dev,pnp_port_start (pdev,0 )); +if (ret) { +kfree (fmr2); +return ret; + } +pnp_set_drvdata (pdev, fmr2); + fmr2_cards[num_fmr2_cards++] = fmr2; + +return 0 ; +} + +static void __devexit fmr2_remove(struct fmr2 *fmr2) +{snd_tea575x_exit (&fmr2->tea);release_region (fmr2->io,2 );v4l2_device_unregister (&fmr2->v4l2_dev);kfree (fmr2); +} + +static int __devexit fmr2_isa_remove(struct device *pdev, unsigned int ndev) +{ +fmr2_remove (dev_get_drvdata (pdev)); +dev_set_drvdata (pdev,NULL ); +return 0 ; } -struct isa_driver fmr2_driver = { - .probe = fmr2_probe, - .remove = fmr2_remove, +static void __devexit fmr2_pnp_remove(struct pnp_dev *pdev) +{ +fmr2_remove (pnp_get_drvdata (pdev)); +pnp_set_drvdata (pdev,NULL ); +} + +struct isa_driver fmr2_isa_driver = { + .match = fmr2_isa_match, + .remove =__devexit_p (fmr2_isa_remove), .driver = { .name ="radio-sf16fmr2" , }, }; +struct pnp_driver fmr2_pnp_driver = { + .name ="radio-sf16fmr2" , + .id_table = fmr2_pnp_ids, + .probe = fmr2_pnp_probe, + .remove =__devexit_p (fmr2_pnp_remove), +}; +static int __init fmr2_init (void ) { -return isa_register_driver (&fmr2_driver,1 ); +int ret; + + ret =pnp_register_driver (&fmr2_pnp_driver); +if (!ret) + pnp_registered = true; + ret =isa_register_driver (&fmr2_isa_driver,1 ); +if (!ret) + isa_registered = true; + +return (pnp_registered || isa_registered) ?0 : ret; } static void __exit fmr2_exit(void) { -isa_unregister_driver (&fmr2_driver); +if (pnp_registered) +pnp_unregister_driver (&fmr2_pnp_driver); +if (isa_registered) +isa_unregister_driver (&fmr2_isa_driver); }module_init (fmr2_init);