⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sound.c

📁 freebsd v4.4内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * snd/sound.c *  * Main sound driver for FreeBSD. This file provides the main * entry points for probe/attach and all i/o demultiplexing, including * default routines for generic devices. *  * (C) 1997 Luigi Rizzo (luigi@iet.unipi.it) *  * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above *    copyright notice, this list of conditions and the following *    disclaimer in the documentation and/or other materials provided *    with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE * AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * For each card type a template "snddev_info" structure contains * all the relevant parameters, both for configuration and runtime. * * In this file we build tables of pointers to the descriptors for * the various supported cards. The generic probe routine scans * the table(s) looking for a matching entry, then invokes the * board-specific probe routine. If successful, a pointer to the * correct snddev_info is stored in snddev_last_probed, for subsequent * use in the attach routine. The generic attach routine copies * the template to a permanent descriptor (pcm_info[unit] and * friends), initializes all generic parameters, and calls the * board-specific attach routine. * * On device calls, the generic routines do the checks on unit and * device parameters, then call the board-specific routines if * available, or try to perform the task using the default code. * */#include "opt_devfs.h"#include <i386/isa/snd/sound.h>#ifdef DEVFS#include <sys/devfsext.h>#endif /* DEVFS */#if NPCM > 0	/* from "snd.h" */#define SNDSTAT_BUF_SIZE        4000static char status_buf[SNDSTAT_BUF_SIZE] ;static int status_len = 0 ;static void init_status(snddev_info *d);static d_open_t sndopen;static d_close_t sndclose;static d_ioctl_t sndioctl;static d_read_t sndread;static d_write_t sndwrite;static d_mmap_t sndmmap;#define CDEV_MAJOR 30static struct cdevsw snd_cdevsw = {	sndopen, sndclose, sndread, sndwrite,	sndioctl, nxstop, nxreset, nxdevtotty,	sndselect, sndmmap, nxstrategy, "snd",	NULL, -1,};/* * descriptors for active devices. * */snddev_info pcm_info[NPCM_MAX] ;snddev_info midi_info[NPCM_MAX] ;snddev_info synth_info[NPCM_MAX] ;u_long nsnd = NPCM ;	/* total number of sound devices *//* * Hooks for APM support, but code not operational yet. */#include "apm.h"#include <i386/include/apm_bios.h>#if NAPM > 0static intsound_suspend(void *arg){	/*	 * I think i can safely do nothing here and	 * reserve all the work for wakeup time	 */	printf("Called APM sound suspend hook for unit %d\n", (int)arg);	return 0 ;}static intsound_resume(void *arg){    snddev_info *d = NULL ;    d = &pcm_info[(int)arg] ;	/*	 * reinitialize card registers.	 * Flush buffers and reinitialize DMA channels.	 * If a write was pending, pretend it is done	 * (and issue any wakeup we need).	 * If a read is pending, restart it.	 */    if (d->bd_id == MD_YM0020) {	DDB(printf("setting up yamaha registers\n"));	outb(0x370, 6 /* dma config */ ) ;	if (FULL_DUPLEX(d))	    outb(0x371, 0xa9 ); /* use both dma chans */	else	    outb(0x371, 0x8b ); /* use low dma chan */    }	printf("Called APM sound resume hook for unit %d\n", (int)arg);	return 0 ;}static voidinit_sound_apm(int unit){	struct apmhook *ap;        ap = malloc(sizeof *ap, M_DEVBUF, M_NOWAIT);        bzero(ap, sizeof *ap);	ap->ah_fun = sound_resume;	ap->ah_arg = (void *)unit;	ap->ah_name = "pcm resume handler";	ap->ah_order = APM_MID_ORDER;	apm_hook_establish(APM_HOOK_RESUME, ap);        ap = malloc(sizeof *ap, M_DEVBUF, M_NOWAIT);        bzero(ap, sizeof *ap);	ap->ah_fun = sound_suspend;	ap->ah_arg = (void *)unit;	ap->ah_name = "pcm suspend handler";	ap->ah_order = APM_MID_ORDER;	apm_hook_establish(APM_HOOK_SUSPEND, ap);}#endif /* NAPM *//* * the probe routine can only return an int to the upper layer. Hence, * it leaves the pointer to the last successfully * probed device descriptor in snddev_last_probed */snddev_info *snddev_last_probed = NULL ;static snddev_info *generic_snd_probe(struct isa_device * dev, snddev_info **p[], char *s);/* * here are the lists of known cards. Similar cards (e.g. all * sb clones, all mss clones, ... are in the same array. * All lists of devices of the same type (eg. all pcm, all midi...) * are in the same array. * Each probe for a device type gets the pointer to the main array * and then scans the sublists. * * XXX should use DATA_SET to create a linker set for sb_devs and other * such structures. */extern snddev_info sb_op_desc;extern snddev_info mss_op_desc;static snddev_info *sb_devs[] = {	/* all SB clones	 */    &sb_op_desc,    NULL,} ;static snddev_info *mss_devs[] = {	/* all MSS clones	*/    &mss_op_desc,    NULL,} ;static snddev_info **pcm_devslist[] = {	/* all pcm devices	*/    mss_devs,    sb_devs,    NULL} ;intpcmprobe(struct isa_device * dev){    bzero(&pcm_info[dev->id_unit], sizeof(pcm_info[dev->id_unit]) );    return generic_snd_probe(dev, pcm_devslist, "pcm") ? 1 : 0 ;}static snddev_info **midi_devslist[] = {/* all midi devices	*/    NULL} ;intmidiprobe(struct isa_device * dev){    bzero(&midi_info[dev->id_unit], sizeof(midi_info[dev->id_unit]) );    return 0 ;    return generic_snd_probe(dev, midi_devslist, "midi") ? 1 : 0 ;}intsynthprobe(struct isa_device * dev){    bzero(&synth_info[dev->id_unit], sizeof(synth_info[dev->id_unit]) );    return 0 ;}/* * this is the generic attach routine */intpcmattach(struct isa_device * dev){    snddev_info *d = NULL ;    struct isa_device *dvp;    int stat = 0;    dev_t isadev;    void *cookie;    if ( (dev->id_unit >= NPCM_MAX) ||		/* too many devs	*/	 (snddev_last_probed == NULL) ||	/* last probe failed	*/	 (snddev_last_probed->attach==NULL) )	/* no attach routine	*/	return 0 ; /* fail */    /*     * default initialization: copy generic parameters for the routine,     * initialize from the isa_device structure, and allocate memory.     * If everything succeeds, then call the attach routine for     * further initialization.     */    pcm_info[dev->id_unit] = *snddev_last_probed ;    d = &pcm_info[dev->id_unit] ;    d->io_base = dev->id_iobase ;    d->irq = ffs(dev->id_irq) - 1 ;    d->dbuf_out.chan = dev->id_drq ;    if (dev->id_flags != -1 && dev->id_flags & DV_F_DUAL_DMA &&	    (dev->id_flags & DV_F_DRQ_MASK) != 4 ) /* enable dma2 */	d->dbuf_in.chan = dev->id_flags & DV_F_DRQ_MASK ;    else	d->dbuf_in.chan = d->dbuf_out.chan ;#if 1 /* does this cause trouble with PnP cards ? */    if (d->bd_id == 0)	d->bd_id = (dev->id_flags & DV_F_DEV_MASK) >> DV_F_DEV_SHIFT ;#endif    d->status_ptr = 0;    /*     * Allocates memory and initializes the dma structs properly. We     * use independent buffers for each channel.  For the time being,     * this is done independently of the dma setting. In future     * revisions, if we see that we have a single dma, we might decide     * to use a single buffer to save memory.     */    alloc_dbuf( &(d->dbuf_out), d->bufsize );    alloc_dbuf( &(d->dbuf_in), d->bufsize );    isa_dma_acquire(d->dbuf_out.chan);    if (FULL_DUPLEX(d))	isa_dma_acquire(d->dbuf_in.chan);    /*     * initialize standard parameters for the device. This can be     * overridden by device-specific configurations but better do     * here the generic things.     */    d->play_speed = d->rec_speed = 8000 ;    d->play_blocksize = d->rec_blocksize = 2048 ;    d->play_fmt = d->rec_fmt = AFMT_MU_LAW ;    isadev = makedev(CDEV_MAJOR, 0);    cdevsw_add(&isadev, &snd_cdevsw, NULL);#ifdef DEVFS#define GID_SND UID_ROOT /* GID_GAMES */#define UID_SND UID_ROOT#define PERM_SND 0660    /*     * XXX remember to store the returned tokens if you want to     * be able to remove the device later     *     * Make links to first successfully probed unit.     * Attempts by later devices to make these links will fail.     */    cookie=devfs_add_devswf(&snd_cdevsw, (dev->id_unit << 4) | SND_DEV_DSP,	DV_CHR, UID_SND, GID_SND, PERM_SND, "dsp%n", dev->id_unit);    if (cookie) devfs_link(cookie, "dsp");    cookie=devfs_add_devswf(&snd_cdevsw, (dev->id_unit << 4) | SND_DEV_DSP16,	DV_CHR, UID_SND, GID_SND, PERM_SND, "dspW%n", dev->id_unit);    if (cookie) devfs_link(cookie, "dspW");    cookie=devfs_add_devswf(&snd_cdevsw, (dev->id_unit << 4) | SND_DEV_AUDIO,	DV_CHR, UID_SND, GID_SND, PERM_SND, "audio%n", dev->id_unit);    if (cookie) devfs_link(cookie, "audio");    cookie=devfs_add_devswf(&snd_cdevsw, (dev->id_unit << 4) | SND_DEV_CTL,	DV_CHR, UID_SND, GID_SND, PERM_SND, "mixer%n", dev->id_unit);    if (cookie) devfs_link(cookie, "mixer");    cookie=devfs_add_devswf(&snd_cdevsw, (dev->id_unit << 4) | SND_DEV_STATUS,	DV_CHR, UID_SND, GID_SND, PERM_SND, "sndstat%n", dev->id_unit);    if (cookie) devfs_link(cookie, "sndstat");#if 0 /* these two are still unsupported... */    cookie=devfs_add_devswf(&snd_cdevsw, (dev->id_unit << 4) | SND_DEV_MIDIN,	DV_CHR, UID_SND, GID_SND, PERM_SND, "midi%n", dev->id_unit);    if (cookie) devfs_link(cookie, "midi");    cookie=devfs_add_devswf(&snd_cdevsw, (dev->id_unit << 4) | SND_DEV_SYNTH,	DV_CHR, UID_SND, GID_SND, PERM_SND, "sequencer%n", dev->id_unit);    if (cookie) devfs_link(cookie, "sequencer");#endif#endif /* DEVFS */    /*     * should try and find a suitable value for id_id, otherwise     * the interrupt is not registered and dispatched properly.     * This is important for PnP devices, where "dev" is built on     * the fly and many field are not initialized.     */    if (dev->id_driver == NULL) {	dev->id_driver = &pcmdriver ;	dvp=find_isadev(isa_devtab_tty, &pcmdriver, 0);	if (dvp)	    dev->id_id = dvp->id_id;    }    d->magic = MAGIC(dev->id_unit); /* debugging... */    /*     * and finally, call the device attach routine     * XXX I should probably use d->attach(dev)     */    stat = snddev_last_probed->attach(dev);#if 0    /*     * XXX hooks for synt support. Try probe and attach...     */    if (d->synth_base && opl3_probe(dev) ) {	opl3_attach(dev);    }#endif    snddev_last_probed = NULL ;#if NAPM > 0    init_sound_apm(dev->id_unit);#endif    return stat ;}int midiattach(struct isa_device * dev) { return 0 ; }int synthattach(struct isa_device * dev) { return 0 ; }struct isa_driver pcmdriver = { pcmprobe, pcmattach, "pcm" } ;struct isa_driver mididriver = { midiprobe, midiattach, "midi" } ;struct isa_driver synthdriver = { synthprobe, synthattach, "synth" } ;voidpcmintr(int unit){    DEB(printf("__/\\/ pcmintr -- unit %d\n", unit));    pcm_info[unit].interrupts++;    if (pcm_info[unit].isr)	pcm_info[unit].isr(unit);#if 0 /* these do not exist at the moment. */    if (midi_info[unit].isr)	midi_info[unit].isr(unit);    if (synth_info[unit].isr)	synth_info[unit].isr(unit);#endif}static snddev_info *generic_snd_probe(struct isa_device * dev, snddev_info **p[], char *s){    snddev_info **q ;    struct isa_device saved_dev ;    snddev_last_probed = NULL ;    saved_dev = *dev ; /* the probe routine might alter parameters */    /*     * XXX todo: should try to match flags with device type.     */    for ( ; p[0] != NULL ; p++ )	for ( q = *p ; q[0] ; q++ )	    if (q[0]->probe && q[0]->probe(dev))		return (snddev_last_probed = q[0]) ;	    else		*dev = saved_dev ;    return NULL ;}/* * a small utility function which, given a device number, returns * a pointer to the associated snddev_info struct, and sets the unit * number. */static snddev_info *get_snddev_info(dev_t dev, int *unit){    int u;    snddev_info *d = NULL ;    dev = minor(dev);    u = dev >> 4 ;    if (unit)	*unit = u ;    if (u >= NPCM_MAX ||	( pcm_info[u].io_base == 0 && (dev & 0x0f) != SND_DEV_STATUS)) {	int i;	for (i = 0 ; i < NPCM_MAX ; i++)	    if (pcm_info[i].io_base)		break ;	if (i != NPCM_MAX) 	    printf("pcm%d: unit not configured, perhaps you want pcm%d ?\n",		 u, i);	else	    printf("no pcm units configured\b");	return NULL ;    }    switch(dev & 0x0f) {    case SND_DEV_CTL :	/* /dev/mixer handled by pcm */    case SND_DEV_STATUS : /* /dev/sndstat handled by pcm */    case SND_DEV_SNDPROC :	/* /dev/sndproc handled by pcm */    case SND_DEV_DSP :    case SND_DEV_DSP16 :    case SND_DEV_AUDIO :    case SND_DEV_SEQ : /* XXX when enabled... */	d = & pcm_info[u] ;	break ;    case SND_DEV_SEQ2 :    case SND_DEV_MIDIN:    default:	printf("unsupported subdevice %d\n", dev & 0xf);	return NULL ;    }    return d ;}/* * here are the switches for the main functions. The switches do * all necessary checks on the device number to make sure * that the device is configured. They also provide some default * functionalities so that device-specific drivers have to deal * only with special cases. */static intsndopen(dev_t i_dev, int flags, int mode, struct proc * p){    int dev, unit ;    snddev_info *d;    dev = minor(i_dev);    d = get_snddev_info(dev, &unit);    DEB(printf("open snd%d subdev %d flags 0x%08x mode 0x%08x\n",	unit, dev & 0xf, flags, mode));    if (d == NULL)	return (ENXIO) ;    switch(dev & 0x0f) {    case SND_DEV_SEQ:	/* sequencer. Hack... */#if 0 /* XXX hook for opl3 support */	if (d->synth_base)	    return opl3_open(i_dev, flags, mode, p);	else#endif	    return ENXIO ;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -