📄 hda_intel.c
字号:
/* create modem PCMs */ pcm_dev = AZX_MAX_AUDIO_PCMS; list_for_each(p, &chip->bus->codec_list) { codec = list_entry(p, struct hda_codec, list); for (c = 0; c < codec->num_pcms; c++) { if (! codec->pcm_info[c].is_modem) continue; /* already created */ if (pcm_dev >= AZX_MAX_PCMS) { snd_printk(KERN_ERR SFX "Too many modem PCMs\n"); return -EINVAL; } err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev); if (err < 0) return err; chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM; pcm_dev++; } } return 0;}/* * mixer creation - all stuff is implemented in hda module */static int __devinit azx_mixer_create(azx_t *chip){ return snd_hda_build_controls(chip->bus);}/* * initialize SD streams */static int __devinit azx_init_stream(azx_t *chip){ int i; /* initialize each stream (aka device) * assign the starting bdl address to each stream (device) and initialize */ for (i = 0; i < chip->num_streams; i++) { unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4); azx_dev_t *azx_dev = &chip->azx_dev[i]; azx_dev->bdl = (u32 *)(chip->bdl.area + off); azx_dev->bdl_addr = chip->bdl.addr + off; azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8); /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ azx_dev->sd_int_sta_mask = 1 << i; /* stream tag: must be non-zero and unique */ azx_dev->index = i; azx_dev->stream_tag = i + 1; } return 0;}#ifdef CONFIG_PM/* * power management */static int azx_suspend(#ifndef SND_PCI_PM_CALLBACKS struct pci_dev *pci,#else snd_card_t *card,#endif pm_message_t state){#ifndef SND_PCI_PM_CALLBACKS struct snd_card *card = pci_get_drvdata(pci); azx_t *chip = card->private_data;#else azx_t *chip = card->pm_private_data;#endif int i;printk(KERN_ERR"%s: card=%p state=0x%x\n", __FUNCTION__, card, *((u32 *)&state)); for (i = 0; i < chip->pcm_devs; i++) if (chip->pcm[i]) snd_pcm_suspend_all(chip->pcm[i]); snd_hda_suspend(chip->bus, state); azx_free_cmd_io(chip); pci_disable_device(chip->pci);#ifndef SND_PCI_PM_CALLBACKS pci_save_state(pci);#endif return 0;}static int azx_resume(#ifndef SND_PCI_PM_CALLBACKS struct pci_dev *pci#else snd_card_t *card#endif){#ifndef SND_PCI_PM_CALLBACKS struct snd_card *card = pci_get_drvdata(pci); azx_t *chip = card->private_data;#else azx_t *chip = card->pm_private_data;#endifprintk(KERN_ERR"%s: card=%p\n", __FUNCTION__, card);#ifndef SND_PCI_PM_CALLBACKS pci_restore_state(pci);#endif pci_enable_device(chip->pci); pci_set_master(chip->pci); azx_init_chip(chip); snd_hda_resume(chip->bus);#ifndef SND_PCI_PM_CALLBACKS snd_power_change_state(card, SNDRV_CTL_POWER_D0);#endif return 0;}#endif /* CONFIG_PM *//* * destructor */static int azx_free(azx_t *chip){//printk(KERN_ERR"%s: chip=%p\n", __FUNCTION__, chip); if (chip->initialized) { int i; for (i = 0; i < chip->num_streams; i++) azx_stream_stop(chip, &chip->azx_dev[i]); /* disable interrupts */ azx_int_disable(chip); azx_int_clear(chip); /* disable CORB/RIRB */ azx_free_cmd_io(chip); /* disable position buffer */ azx_writel(chip, DPLBASE, 0); azx_writel(chip, DPUBASE, 0); /* wait a little for interrupts to finish */ msleep(1); } if (chip->remap_addr) iounmap(chip->remap_addr); if (chip->irq >= 0) free_irq(chip->irq, (void*)chip); if (chip->bdl.area) snd_dma_free_pages(&chip->bdl); if (chip->rb.area) snd_dma_free_pages(&chip->rb); if (chip->posbuf.area) snd_dma_free_pages(&chip->posbuf); pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip->azx_dev); kfree(chip); return 0;}static int azx_dev_free(snd_device_t *device){//printk(KERN_ERR"%s: device=%p\n", __FUNCTION__, device); return azx_free(device->device_data);}/* * constructor */static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, int posfix, int driver_type, azx_t **rchip){ azx_t *chip; int err = 0; static snd_device_ops_t ops = { .dev_free = azx_dev_free, };//printk(KERN_ERR"%s: pci=%p card=%p\n", __FUNCTION__, pci, card); *rchip = NULL; if ((err = pci_enable_device(pci)) < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (NULL == chip) { snd_printk(KERN_ERR SFX "cannot allocate chip\n"); pci_disable_device(pci); return -ENOMEM; } spin_lock_init(&chip->reg_lock); init_MUTEX(&chip->open_mutex); chip->card = card; chip->pci = pci; chip->irq = -1; chip->driver_type = driver_type; chip->position_fix = posfix;#if BITS_PER_LONG != 64 /* Fix up base address on ULI M5461 */ if (chip->driver_type == AZX_DRIVER_ULI) { u16 tmp3; pci_read_config_word(pci, 0x40, &tmp3); pci_write_config_word(pci, 0x40, tmp3 | 0x10); pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, 0); }#endif if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) { kfree(chip); pci_disable_device(pci); return err; } chip->addr = pci_resource_start(pci,0); chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci,0)); if (chip->remap_addr == NULL) { snd_printk(KERN_ERR SFX "ioremap error\n"); err = -ENXIO; goto errout; } if (request_irq(pci->irq, azx_interrupt, SA_INTERRUPT|SA_SHIRQ, "HDA Intel", (void*)chip)) { snd_printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq); err = -EBUSY; goto errout; } chip->irq = pci->irq; pci_set_master(pci); synchronize_irq(chip->irq); switch (chip->driver_type) { case AZX_DRIVER_ULI: chip->playback_streams = ULI_NUM_PLAYBACK; chip->capture_streams = ULI_NUM_CAPTURE; chip->playback_index_offset = ULI_PLAYBACK_INDEX; chip->capture_index_offset = ULI_CAPTURE_INDEX; break; default: chip->playback_streams = ICH6_NUM_PLAYBACK; chip->capture_streams = ICH6_NUM_CAPTURE; chip->playback_index_offset = ICH6_PLAYBACK_INDEX; chip->capture_index_offset = ICH6_CAPTURE_INDEX; break; } chip->num_streams = chip->playback_streams + chip->capture_streams; chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL); if (! chip->azx_dev) { snd_printk(KERN_ERR "cannot malloc azx_dev\n"); goto errout; } /* allocate memory for the BDL for each stream */ if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), BDL_SIZE, &chip->bdl)) < 0) { snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); goto errout; } /* allocate memory for the position buffer */ if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), chip->num_streams * 8, &chip->posbuf)) < 0) { snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); goto errout; } /* allocate CORB/RIRB */ if ((err = azx_alloc_cmd_io(chip)) < 0) goto errout; /* initialize streams */ azx_init_stream(chip); /* initialize chip */ azx_init_chip(chip); chip->initialized = 1; /* codec detection */ if (! chip->codec_mask) { snd_printk(KERN_ERR SFX "no codecs found!\n"); err = -ENODEV; goto errout; } if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) <0) { snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); goto errout; } strcpy(card->driver, "HDA-Intel"); strcpy(card->shortname, driver_short_names[chip->driver_type]); sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq); *rchip = chip; return 0; errout: azx_free(chip); return err;}static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id){ snd_card_t *card; azx_t *chip; int err = 0; card = snd_card_new(index, id, THIS_MODULE, 0); if (NULL == card) { snd_printk(KERN_ERR SFX "Error creating card!\n"); return -ENOMEM; } if ((err = azx_create(card, pci, position_fix, pci_id->driver_data, &chip)) < 0) { snd_card_free(card); return err; }#ifndef SND_PCI_PM_CALLBACKS card->private_data = chip;#endif /* create codec instances */ if ((err = azx_codec_create(chip, model)) < 0) { snd_card_free(card); return err; } /* create PCM streams */ if ((err = azx_pcm_create(chip)) < 0) { snd_card_free(card); return err; } /* create mixer controls */ if ((err = azx_mixer_create(chip)) < 0) { snd_card_free(card); return err; }#ifdef SND_PCI_PM_CALLBACKS snd_card_set_pm_callback(card, azx_suspend, azx_resume, chip);#endif snd_card_set_dev(card, &pci->dev); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; } pci_set_drvdata(pci, card); return err;}static void __devexit azx_remove(struct pci_dev *pci){ snd_card_t *card = pci_get_drvdata(pci);#ifndef SND_PCI_PM_CALLBACKS azx_t *chip = card->private_data;#else azx_t *chip = card->pm_private_data;#endif//printk(KERN_ERR"%s: pci=%p card=%p\n", __FUNCTION__, pci, pci_get_drvdata(pci)); snd_hda_codec_remove_notify_all(chip->bus); snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL);}/* PCI IDs */static struct pci_device_id azx_ids[] = { { 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH6 */ { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH7 */ { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ESB2 */ { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */ { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */ { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */ { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */ { 0x10de, 0x026c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 026c */ { 0x10de, 0x0371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 0371 */ { 0, }};MODULE_DEVICE_TABLE(pci, azx_ids);/* pci_driver definition */static struct pci_driver driver = { .name = "HDA Intel", .id_table = azx_ids, .probe = azx_probe, .remove = __devexit_p(azx_remove),#ifdef SND_PCI_PM_CALLBACKS SND_PCI_PM_CALLBACKS#else#ifdef CONFIG_PM .suspend = azx_suspend, .resume = azx_resume,#endif#endif};static int __init alsa_card_azx_init(void){ return pci_register_driver(&driver);}static void __exit alsa_card_azx_exit(void){//printk(KERN_ERR"%s\n", __FUNCTION__); pci_unregister_driver(&driver);}module_init(alsa_card_azx_init)module_exit(alsa_card_azx_exit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -