Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Driver for Digigram VXpocket V2/440 soundcards
0004  *
0005  * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
0006 
0007  */
0008 
0009 
0010 #include <linux/init.h>
0011 #include <linux/module.h>
0012 #include <linux/slab.h>
0013 #include <sound/core.h>
0014 #include "vxpocket.h"
0015 #include <pcmcia/ciscode.h>
0016 #include <pcmcia/cisreg.h>
0017 #include <sound/initval.h>
0018 #include <sound/tlv.h>
0019 
0020 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
0021 MODULE_DESCRIPTION("Digigram VXPocket");
0022 MODULE_LICENSE("GPL");
0023 
0024 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;  /* Index 0-MAX */
0025 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;   /* ID for this card */
0026 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable switches */
0027 static int ibl[SNDRV_CARDS];
0028 
0029 module_param_array(index, int, NULL, 0444);
0030 MODULE_PARM_DESC(index, "Index value for VXPocket soundcard.");
0031 module_param_array(id, charp, NULL, 0444);
0032 MODULE_PARM_DESC(id, "ID string for VXPocket soundcard.");
0033 module_param_array(enable, bool, NULL, 0444);
0034 MODULE_PARM_DESC(enable, "Enable VXPocket soundcard.");
0035 module_param_array(ibl, int, NULL, 0444);
0036 MODULE_PARM_DESC(ibl, "Capture IBL size for VXPocket soundcard.");
0037  
0038 
0039 /*
0040  */
0041 
0042 static unsigned int card_alloc;
0043 
0044 
0045 /*
0046  */
0047 static void vxpocket_release(struct pcmcia_device *link)
0048 {
0049     free_irq(link->irq, link->priv);
0050     pcmcia_disable_device(link);
0051 }
0052 
0053 /*
0054  * Hardware information
0055  */
0056 
0057 /* VX-pocket V2
0058  *
0059  * 1 DSP, 1 sync UER
0060  * 1 programmable clock (NIY)
0061  * 1 stereo analog input (line/micro)
0062  * 1 stereo analog output
0063  * Only output levels can be modified
0064  */
0065 
0066 static const DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0);
0067 
0068 static const struct snd_vx_hardware vxpocket_hw = {
0069     .name = "VXPocket",
0070     .type = VX_TYPE_VXPOCKET,
0071 
0072     /* hardware specs */
0073     .num_codecs = 1,
0074     .num_ins = 1,
0075     .num_outs = 1,
0076     .output_level_max = VX_ANALOG_OUT_LEVEL_MAX,
0077     .output_level_db_scale = db_scale_old_vol,
0078 };  
0079 
0080 /* VX-pocket 440
0081  *
0082  * 1 DSP, 1 sync UER, 1 sync World Clock (NIY)
0083  * SMPTE (NIY)
0084  * 2 stereo analog input (line/micro)
0085  * 2 stereo analog output
0086  * Only output levels can be modified
0087  * UER, but only for the first two inputs and outputs.
0088  */
0089 
0090 static const struct snd_vx_hardware vxp440_hw = {
0091     .name = "VXPocket440",
0092     .type = VX_TYPE_VXP440,
0093 
0094     /* hardware specs */
0095     .num_codecs = 2,
0096     .num_ins = 2,
0097     .num_outs = 2,
0098     .output_level_max = VX_ANALOG_OUT_LEVEL_MAX,
0099     .output_level_db_scale = db_scale_old_vol,
0100 };  
0101 
0102 
0103 /*
0104  * create vxpocket instance
0105  */
0106 static int snd_vxpocket_new(struct snd_card *card, int ibl,
0107                 struct pcmcia_device *link,
0108                 struct snd_vxpocket **chip_ret)
0109 {
0110     struct vx_core *chip;
0111     struct snd_vxpocket *vxp;
0112 
0113     chip = snd_vx_create(card, &vxpocket_hw, &snd_vxpocket_ops,
0114                  sizeof(struct snd_vxpocket) - sizeof(struct vx_core));
0115     if (!chip)
0116         return -ENOMEM;
0117 
0118     chip->ibl.size = ibl;
0119 
0120     vxp = to_vxpocket(chip);
0121 
0122     vxp->p_dev = link;
0123     link->priv = chip;
0124 
0125     link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
0126     link->resource[0]->end = 16;
0127 
0128     link->config_flags |= CONF_ENABLE_IRQ;
0129     link->config_index = 1;
0130     link->config_regs = PRESENT_OPTION;
0131 
0132     *chip_ret = vxp;
0133     return 0;
0134 }
0135 
0136 
0137 /**
0138  * snd_vxpocket_assign_resources - initialize the hardware and card instance.
0139  * @chip: VX core instance
0140  * @port: i/o port for the card
0141  * @irq: irq number for the card
0142  *
0143  * this function assigns the specified port and irq, boot the card,
0144  * create pcm and control instances, and initialize the rest hardware.
0145  *
0146  * returns 0 if successful, or a negative error code.
0147  */
0148 static int snd_vxpocket_assign_resources(struct vx_core *chip, int port, int irq)
0149 {
0150     int err;
0151     struct snd_card *card = chip->card;
0152     struct snd_vxpocket *vxp = to_vxpocket(chip);
0153 
0154     snd_printdd(KERN_DEBUG "vxpocket assign resources: port = 0x%x, irq = %d\n", port, irq);
0155     vxp->port = port;
0156 
0157     sprintf(card->shortname, "Digigram %s", card->driver);
0158     sprintf(card->longname, "%s at 0x%x, irq %i",
0159         card->shortname, port, irq);
0160 
0161     chip->irq = irq;
0162     card->sync_irq = chip->irq;
0163 
0164     err = snd_vx_setup_firmware(chip);
0165     if (err < 0)
0166         return err;
0167 
0168     return 0;
0169 }
0170 
0171 
0172 /*
0173  * configuration callback
0174  */
0175 
0176 static int vxpocket_config(struct pcmcia_device *link)
0177 {
0178     struct vx_core *chip = link->priv;
0179     int ret;
0180 
0181     snd_printdd(KERN_DEBUG "vxpocket_config called\n");
0182 
0183     /* redefine hardware record according to the VERSION1 string */
0184     if (!strcmp(link->prod_id[1], "VX-POCKET")) {
0185         snd_printdd("VX-pocket is detected\n");
0186     } else {
0187         snd_printdd("VX-pocket 440 is detected\n");
0188         /* overwrite the hardware information */
0189         chip->hw = &vxp440_hw;
0190         chip->type = vxp440_hw.type;
0191         strcpy(chip->card->driver, vxp440_hw.name);
0192     }
0193 
0194     ret = pcmcia_request_io(link);
0195     if (ret)
0196         goto failed_preirq;
0197 
0198     ret = request_threaded_irq(link->irq, snd_vx_irq_handler,
0199                    snd_vx_threaded_irq_handler,
0200                    IRQF_SHARED, link->devname, link->priv);
0201     if (ret)
0202         goto failed_preirq;
0203 
0204     ret = pcmcia_enable_device(link);
0205     if (ret)
0206         goto failed;
0207 
0208     chip->dev = &link->dev;
0209 
0210     if (snd_vxpocket_assign_resources(chip, link->resource[0]->start,
0211                         link->irq) < 0)
0212         goto failed;
0213 
0214     return 0;
0215 
0216  failed:
0217     free_irq(link->irq, link->priv);
0218 failed_preirq:
0219     pcmcia_disable_device(link);
0220     return -ENODEV;
0221 }
0222 
0223 #ifdef CONFIG_PM
0224 
0225 static int vxp_suspend(struct pcmcia_device *link)
0226 {
0227     struct vx_core *chip = link->priv;
0228 
0229     snd_printdd(KERN_DEBUG "SUSPEND\n");
0230     if (chip) {
0231         snd_printdd(KERN_DEBUG "snd_vx_suspend calling\n");
0232         snd_vx_suspend(chip);
0233     }
0234 
0235     return 0;
0236 }
0237 
0238 static int vxp_resume(struct pcmcia_device *link)
0239 {
0240     struct vx_core *chip = link->priv;
0241 
0242     snd_printdd(KERN_DEBUG "RESUME\n");
0243     if (pcmcia_dev_present(link)) {
0244         //struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
0245         if (chip) {
0246             snd_printdd(KERN_DEBUG "calling snd_vx_resume\n");
0247             snd_vx_resume(chip);
0248         }
0249     }
0250     snd_printdd(KERN_DEBUG "resume done!\n");
0251 
0252     return 0;
0253 }
0254 
0255 #endif
0256 
0257 
0258 /*
0259  */
0260 static int vxpocket_probe(struct pcmcia_device *p_dev)
0261 {
0262     struct snd_card *card;
0263     struct snd_vxpocket *vxp;
0264     int i, err;
0265 
0266     /* find an empty slot from the card list */
0267     for (i = 0; i < SNDRV_CARDS; i++) {
0268         if (!(card_alloc & (1 << i)))
0269             break;
0270     }
0271     if (i >= SNDRV_CARDS) {
0272         snd_printk(KERN_ERR "vxpocket: too many cards found\n");
0273         return -EINVAL;
0274     }
0275     if (! enable[i])
0276         return -ENODEV; /* disabled explicitly */
0277 
0278     /* ok, create a card instance */
0279     err = snd_card_new(&p_dev->dev, index[i], id[i], THIS_MODULE,
0280                0, &card);
0281     if (err < 0) {
0282         snd_printk(KERN_ERR "vxpocket: cannot create a card instance\n");
0283         return err;
0284     }
0285 
0286     err = snd_vxpocket_new(card, ibl[i], p_dev, &vxp);
0287     if (err < 0) {
0288         snd_card_free(card);
0289         return err;
0290     }
0291     card->private_data = vxp;
0292 
0293     vxp->index = i;
0294     card_alloc |= 1 << i;
0295 
0296     vxp->p_dev = p_dev;
0297 
0298     return vxpocket_config(p_dev);
0299 }
0300 
0301 static void vxpocket_detach(struct pcmcia_device *link)
0302 {
0303     struct snd_vxpocket *vxp;
0304     struct vx_core *chip;
0305 
0306     if (! link)
0307         return;
0308 
0309     vxp = link->priv;
0310     chip = (struct vx_core *)vxp;
0311     card_alloc &= ~(1 << vxp->index);
0312 
0313     chip->chip_status |= VX_STAT_IS_STALE; /* to be sure */
0314     snd_card_disconnect(chip->card);
0315     vxpocket_release(link);
0316     snd_card_free_when_closed(chip->card);
0317 }
0318 
0319 /*
0320  * Module entry points
0321  */
0322 
0323 static const struct pcmcia_device_id vxp_ids[] = {
0324     PCMCIA_DEVICE_MANF_CARD(0x01f1, 0x0100),
0325     PCMCIA_DEVICE_NULL
0326 };
0327 MODULE_DEVICE_TABLE(pcmcia, vxp_ids);
0328 
0329 static struct pcmcia_driver vxp_cs_driver = {
0330     .owner      = THIS_MODULE,
0331     .name       = "snd-vxpocket",
0332     .probe      = vxpocket_probe,
0333     .remove     = vxpocket_detach,
0334     .id_table   = vxp_ids,
0335 #ifdef CONFIG_PM
0336     .suspend    = vxp_suspend,
0337     .resume     = vxp_resume,
0338 #endif
0339 };
0340 module_pcmcia_driver(vxp_cs_driver);