📄 pcxhr.c
字号:
struct snd_pcxhr *chip = snd_pcm_substream_chip(subs); struct pcxhr_mgr *mgr = chip->mgr; struct pcxhr_stream *stream = subs->runtime->private_data; down(&mgr->setup_mutex); snd_printdd("pcxhr_close chip%d subs%d\n", chip->chip_idx, subs->number); /* sample rate released */ if (--mgr->ref_count_rate == 0) { mgr->sample_rate = 0; /* the sample rate is no more locked */ pcxhr_hardware_timer(mgr, 0); /* stop the DSP-timer */ } stream->status = PCXHR_STREAM_STATUS_FREE; stream->substream = NULL; up(&mgr->setup_mutex); return 0;}static snd_pcm_uframes_t pcxhr_stream_pointer(struct snd_pcm_substream *subs){ unsigned long flags; u_int32_t timer_period_frag; int timer_buf_periods; struct snd_pcxhr *chip = snd_pcm_substream_chip(subs); struct snd_pcm_runtime *runtime = subs->runtime; struct pcxhr_stream *stream = runtime->private_data; spin_lock_irqsave(&chip->mgr->lock, flags); /* get the period fragment and the nb of periods in the buffer */ timer_period_frag = stream->timer_period_frag; timer_buf_periods = stream->timer_buf_periods; spin_unlock_irqrestore(&chip->mgr->lock, flags); return (snd_pcm_uframes_t)((timer_buf_periods * runtime->period_size) + timer_period_frag);}static struct snd_pcm_ops pcxhr_ops = { .open = pcxhr_open, .close = pcxhr_close, .ioctl = snd_pcm_lib_ioctl, .prepare = pcxhr_prepare, .hw_params = pcxhr_hw_params, .hw_free = pcxhr_hw_free, .trigger = pcxhr_trigger, .pointer = pcxhr_stream_pointer,};/* */int pcxhr_create_pcm(struct snd_pcxhr *chip){ int err; struct snd_pcm *pcm; char name[32]; sprintf(name, "pcxhr %d", chip->chip_idx); if ((err = snd_pcm_new(chip->card, name, 0, chip->nb_streams_play, chip->nb_streams_capt, &pcm)) < 0) { snd_printk(KERN_ERR "cannot create pcm %s\n", name); return err; } pcm->private_data = chip; if (chip->nb_streams_play) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcxhr_ops); if (chip->nb_streams_capt) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcxhr_ops); pcm->info_flags = 0; strcpy(pcm->name, name); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->mgr->pci), 32*1024, 32*1024); chip->pcm = pcm; return 0;}static int pcxhr_chip_free(struct snd_pcxhr *chip){ kfree(chip); return 0;}static int pcxhr_chip_dev_free(struct snd_device *device){ struct snd_pcxhr *chip = device->device_data; return pcxhr_chip_free(chip);}/* */static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card, int idx){ int err; struct snd_pcxhr *chip; static struct snd_device_ops ops = { .dev_free = pcxhr_chip_dev_free, }; mgr->chip[idx] = chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (! chip) { snd_printk(KERN_ERR "cannot allocate chip\n"); return -ENOMEM; } chip->card = card; chip->chip_idx = idx; chip->mgr = mgr; if (idx < mgr->playback_chips) /* stereo or mono streams */ chip->nb_streams_play = PCXHR_PLAYBACK_STREAMS; if (idx < mgr->capture_chips) { if (mgr->mono_capture) chip->nb_streams_capt = 2; /* 2 mono streams (left+right) */ else chip->nb_streams_capt = 1; /* or 1 stereo stream */ } if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { pcxhr_chip_free(chip); return err; } snd_card_set_dev(card, &mgr->pci->dev); return 0;}/* proc interface */static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer){ struct snd_pcxhr *chip = entry->private_data; struct pcxhr_mgr *mgr = chip->mgr; snd_iprintf(buffer, "\n%s\n", mgr->longname); /* stats available when embedded DSP is running */ if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) { struct pcxhr_rmh rmh; short ver_maj = (mgr->dsp_version >> 16) & 0xff; short ver_min = (mgr->dsp_version >> 8) & 0xff; short ver_build = mgr->dsp_version & 0xff; snd_iprintf(buffer, "module version %s\n", PCXHR_DRIVER_VERSION_STRING); snd_iprintf(buffer, "dsp version %d.%d.%d\n", ver_maj, ver_min, ver_build); if (mgr->board_has_analog) snd_iprintf(buffer, "analog io available\n"); else snd_iprintf(buffer, "digital only board\n"); /* calc cpu load of the dsp */ pcxhr_init_rmh(&rmh, CMD_GET_DSP_RESOURCES); if( ! pcxhr_send_msg(mgr, &rmh) ) { int cur = rmh.stat[0]; int ref = rmh.stat[1]; if (ref > 0) { if (mgr->sample_rate_real != 0 && mgr->sample_rate_real != 48000) { ref = (ref * 48000) / mgr->sample_rate_real; if (mgr->sample_rate_real >= PCXHR_IRQ_TIMER_FREQ) ref *= 2; } cur = 100 - (100 * cur) / ref; snd_iprintf(buffer, "cpu load %d%%\n", cur); snd_iprintf(buffer, "buffer pool %d/%d kWords\n", rmh.stat[2], rmh.stat[3]); } } snd_iprintf(buffer, "dma granularity : %d\n", PCXHR_GRANULARITY); snd_iprintf(buffer, "dsp time errors : %d\n", mgr->dsp_time_err); snd_iprintf(buffer, "dsp async pipe xrun errors : %d\n", mgr->async_err_pipe_xrun); snd_iprintf(buffer, "dsp async stream xrun errors : %d\n", mgr->async_err_stream_xrun); snd_iprintf(buffer, "dsp async last other error : %x\n", mgr->async_err_other_last); /* debug zone dsp */ rmh.cmd[0] = 0x4200 + PCXHR_SIZE_MAX_STATUS; rmh.cmd_len = 1; rmh.stat_len = PCXHR_SIZE_MAX_STATUS; rmh.dsp_stat = 0; rmh.cmd_idx = CMD_LAST_INDEX; if( ! pcxhr_send_msg(mgr, &rmh) ) { int i; for (i = 0; i < rmh.stat_len; i++) snd_iprintf(buffer, "debug[%02d] = %06x\n", i, rmh.stat[i]); } } else snd_iprintf(buffer, "no firmware loaded\n"); snd_iprintf(buffer, "\n");}static void pcxhr_proc_sync(struct snd_info_entry *entry, struct snd_info_buffer *buffer){ struct snd_pcxhr *chip = entry->private_data; struct pcxhr_mgr *mgr = chip->mgr; static char *texts[7] = { "Internal", "Word", "AES Sync", "AES 1", "AES 2", "AES 3", "AES 4" }; snd_iprintf(buffer, "\n%s\n", mgr->longname); snd_iprintf(buffer, "Current Sample Clock\t: %s\n", texts[mgr->cur_clock_type]); snd_iprintf(buffer, "Current Sample Rate\t= %d\n", mgr->sample_rate_real); /* commands available when embedded DSP is running */ if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) { int i, err, sample_rate; for (i = PCXHR_CLOCK_TYPE_WORD_CLOCK; i< (3 + mgr->capture_chips); i++) { err = pcxhr_get_external_clock(mgr, i, &sample_rate); if (err) break; snd_iprintf(buffer, "%s Clock\t\t= %d\n", texts[i], sample_rate); } } else snd_iprintf(buffer, "no firmware loaded\n"); snd_iprintf(buffer, "\n");}static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip){ struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "info", &entry)) snd_info_set_text_ops(entry, chip, 1024, pcxhr_proc_info); if (! snd_card_proc_new(chip->card, "sync", &entry)) snd_info_set_text_ops(entry, chip, 1024, pcxhr_proc_sync);}/* end of proc interface *//* * release all the cards assigned to a manager instance */static int pcxhr_free(struct pcxhr_mgr *mgr){ unsigned int i; for (i = 0; i < mgr->num_cards; i++) { if (mgr->chip[i]) snd_card_free(mgr->chip[i]->card); } /* reset board if some firmware was loaded */ if(mgr->dsp_loaded) { pcxhr_reset_board(mgr); snd_printdd("reset pcxhr !\n"); } /* release irq */ if (mgr->irq >= 0) free_irq(mgr->irq, mgr); pci_release_regions(mgr->pci); /* free hostport purgebuffer */ if (mgr->hostport.area) { snd_dma_free_pages(&mgr->hostport); mgr->hostport.area = NULL; } kfree(mgr->prmh); pci_disable_device(mgr->pci); kfree(mgr); return 0;}/* * probe function - creates the card manager */static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id *pci_id){ static int dev; struct pcxhr_mgr *mgr; unsigned int i; int err; size_t size; char *card_name; if (dev >= SNDRV_CARDS) return -ENODEV; if (! enable[dev]) { dev++; return -ENOENT; } /* enable PCI device */ if ((err = pci_enable_device(pci)) < 0) return err; pci_set_master(pci); /* check if we can restrict PCI DMA transfers to 32 bits */ if (pci_set_dma_mask(pci, 0xffffffff) < 0) { snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } /* alloc card manager */ mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); if (! mgr) { pci_disable_device(pci); return -ENOMEM; } snd_assert(pci_id->driver_data < PCI_ID_LAST, return -ENODEV); card_name = pcxhr_board_params[pci_id->driver_data].board_name; mgr->playback_chips = pcxhr_board_params[pci_id->driver_data].playback_chips; mgr->capture_chips = pcxhr_board_params[pci_id->driver_data].capture_chips; mgr->firmware_num = pcxhr_board_params[pci_id->driver_data].firmware_num; mgr->mono_capture = mono[dev]; /* resource assignment */ if ((err = pci_request_regions(pci, card_name)) < 0) { kfree(mgr); pci_disable_device(pci); return err; } for (i = 0; i < 3; i++) mgr->port[i] = pci_resource_start(pci, i); mgr->pci = pci; mgr->irq = -1; if (request_irq(pci->irq, pcxhr_interrupt, SA_INTERRUPT|SA_SHIRQ, card_name, mgr)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); pcxhr_free(mgr); return -EBUSY; } mgr->irq = pci->irq; sprintf(mgr->shortname, "Digigram %s", card_name); sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, 0x%lx irq %i", mgr->shortname, mgr->port[0], mgr->port[1], mgr->port[2], mgr->irq); /* ISR spinlock */ spin_lock_init(&mgr->lock); spin_lock_init(&mgr->msg_lock); /* init setup mutex*/ init_MUTEX(&mgr->setup_mutex); /* init taslket */ tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet, (unsigned long) mgr); tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet, (unsigned long) mgr); mgr->prmh = kmalloc(sizeof(*mgr->prmh) + sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS - PCXHR_SIZE_MAX_STATUS), GFP_KERNEL); if (! mgr->prmh) { pcxhr_free(mgr); return -ENOMEM; } for (i=0; i < PCXHR_MAX_CARDS; i++) { struct snd_card *card; char tmpid[16]; int idx; if (i >= max(mgr->playback_chips, mgr->capture_chips)) break; mgr->num_cards++; if (index[dev] < 0) idx = index[dev]; else idx = index[dev] + i; snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev] ? id[dev] : card_name, i); card = snd_card_new(idx, tmpid, THIS_MODULE, 0); if (! card) { snd_printk(KERN_ERR "cannot allocate the card %d\n", i); pcxhr_free(mgr); return -ENOMEM; } strcpy(card->driver, DRIVER_NAME); sprintf(card->shortname, "%s [PCM #%d]", mgr->shortname, i); sprintf(card->longname, "%s [PCM #%d]", mgr->longname, i); if ((err = pcxhr_create(mgr, card, i)) < 0) { pcxhr_free(mgr); return err; } if (i == 0) /* init proc interface only for chip0 */ pcxhr_proc_init(mgr->chip[i]); if ((err = snd_card_register(card)) < 0) { pcxhr_free(mgr); return err; } } /* create hostport purgebuffer */ size = PAGE_ALIGN(sizeof(struct pcxhr_hostport)); if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), size, &mgr->hostport) < 0) { pcxhr_free(mgr); return -ENOMEM; } /* init purgebuffer */ memset(mgr->hostport.area, 0, size); /* create a DSP loader */ err = pcxhr_setup_firmware(mgr); if (err < 0) { pcxhr_free(mgr); return err; } pci_set_drvdata(pci, mgr); dev++; return 0;}static void __devexit pcxhr_remove(struct pci_dev *pci){ pcxhr_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL);}static struct pci_driver driver = { .name = "Digigram pcxhr", .id_table = pcxhr_ids, .probe = pcxhr_probe, .remove = __devexit_p(pcxhr_remove),};static int __init pcxhr_module_init(void){ return pci_register_driver(&driver);}static void __exit pcxhr_module_exit(void){ pci_unregister_driver(&driver);}module_init(pcxhr_module_init)module_exit(pcxhr_module_exit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -