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

📄 sound.c

📁 freebsd v4.4内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
    case SND_DEV_CTL : /* mixer ... */	return 0 ;	/* always succeed */    case SND_DEV_STATUS : /* implemented right here */	init_status(&pcm_info[unit]);	d->status_ptr = 0 ;	return 0 ;    default:	if (d->open == NULL) {	    printf("open: unit %d not configured, perhaps you want unit %d ?\n",		unit, unit+1 );	    return (ENXIO) ;	} else	    return d->open(i_dev, flags, mode, p);    }    return ENXIO ;}static intsndclose(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("close snd%d subdev %d\n", unit, dev & 0xf));    if (d == NULL)	return (ENXIO) ;    switch(dev & 0xf) { /* only those for which close makes sense */    case SND_DEV_SEQ:#if 0	/* XXX hook for opl3 support */	if (d->synth_base)		return opl3_close(i_dev, flags, mode, p);	else#endif		return ENXIO ;    case SND_DEV_AUDIO :    case SND_DEV_DSP :    case SND_DEV_DSP16 :	if (d->close)	    return d->close(i_dev, flags, mode, p);    }    return 0 ;}static intsndread(dev_t i_dev, struct uio * buf, int flag){    int ret, dev, unit;    snddev_info *d ;    u_long s;    dev = minor(i_dev);    d = get_snddev_info(dev, &unit);    DEB(printf("read snd%d subdev %d flag 0x%08x\n", unit, dev & 0xf, flag));    if (d == NULL)	return ENXIO ;    if ( (dev & 0x0f) == SND_DEV_STATUS ) {	int l, c;	u_char *p;	l = buf->uio_resid;	s=spltty();	c = status_len - d->status_ptr ;	if (c < 0) /* should not happen! */	    c = 0 ;	if (c < l)	    l = c ;	p = status_buf + d->status_ptr ;	d->status_ptr += l ;	splx(s);	return uiomove(p, l, buf) ;    }    if (d->read)	/* device-specific read */	return d->read(i_dev, buf, flag);    /*     * the generic read routine. device-specific stuff should only     * be in the dma-handling procedures.     */    s = spltty();    if ( d->flags & SND_F_READING ) {        /* another reader is in, deny request */        splx(s);	DDB(printf("read denied, another reader is in\n"));	/*	 * sleep for a while to avoid killing the machine.	 */	tsleep( (void *)s, PZERO, "sndar", hz ) ;        return EBUSY ;    }    if ( ! FULL_DUPLEX(d) ) {           /* half duplex */        if ( d->flags & SND_F_WRITING ) {            /* another writer is in, deny request */            splx(s);	    DDB(printf("read denied, half duplex and a writer is in\n"));	    tsleep( (void *)s, PZERO, "sndaw", hz ) ;            return EBUSY ;        }        while ( d->dbuf_out.dl ) {	    /*	     * we have a pending dma operation, post a read request	     * and wait for the write to complete.	     */            d->flags |= SND_F_READING ;            DEB(printf("sndread: sleeping waiting for write to end\n"));            ret = tsleep( (caddr_t)&(d->dbuf_out),                 PRIBIO | PCATCH , "sndrdw", hz ) ;            if (ret == ERESTART || ret == EINTR) {                d->flags &= ~SND_F_READING ;                splx(s);                return EINTR ;            }        }    }    d->flags |= SND_F_READING ;    splx(s);        return dsp_read_body(d, buf);}static intsndwrite(dev_t i_dev, struct uio * buf, int flag){    int ret, dev, unit;    snddev_info *d;    u_long s;    dev = minor(i_dev);    d = get_snddev_info(dev, &unit);    DEB(printf("write snd%d subdev %d flag 0x%08x\n", unit, dev & 0xf, flag));    if (d == NULL)	return (ENXIO) ;    switch( dev & 0x0f) {	/* only writeable devices */    case SND_DEV_MIDIN:	/* XXX is this writable ? */    case SND_DEV_SEQ :    case SND_DEV_SEQ2 :    case SND_DEV_DSP :    case SND_DEV_DSP16 :    case SND_DEV_AUDIO :	break ;    default:	return EPERM ; /* for non-writeable devices ; */    }    if (d->write)	return d->write(i_dev, buf, flag);    /*     * Otherwise, use the generic write routine. device-specific     * stuff should only be in the dma-handling procedures.     */    s = spltty();    if ( d->flags & SND_F_WRITING ) {        /* another writer is in, deny request */        splx(s);	DDB(printf("write denied, another writer is in\n"));	tsleep( (void *)s, PZERO , "sndaw", hz ) ;        return EBUSY ;    }    if ( ! FULL_DUPLEX(d) ) {           /* half duplex */        if ( d->flags & SND_F_READING ) {            /* another reader is in, deny request */            splx(s);	    DDB(printf("write denied, half duplex and a reader is in\n"));	    tsleep( (void *)s, PZERO, "sndar", hz ) ;            return EBUSY ;        }        while ( d->dbuf_in.dl ) {	    /*	     * we have a pending read dma. Post a write request	     * and wait for the read to complete (in fact I could	     * abort the read dma...	     */            d->flags |= SND_F_WRITING ;            DEB(printf("sndwrite: sleeping waiting for read to end\n"));            ret = tsleep( (caddr_t)&(d->dbuf_out),                 PRIBIO | PCATCH , "sndwr", hz ) ;            if (ret == ERESTART || ret == EINTR) {                d->flags &= ~SND_F_WRITING ;                splx(s);                return EINTR ;            }        }    }    d->flags |= SND_F_WRITING ;    splx(s);        return dsp_write_body(d, buf);}/* * generic sound ioctl. Functions of the default driver can be * overridden by the device-specific ioctl call. * If a device-specific call returns ENOSYS (Function not implemented), * the default driver is called. Otherwise, the returned value * is passed up. * * The default handler, for many parameters, sets the value in the * descriptor, sets SND_F_INIT, and calls the callback function with * reason INIT. If successful, the callback returns 1 and the caller * can update the parameter. */static intsndioctl(dev_t i_dev, int cmd, caddr_t arg, int mode, struct proc * p){    int ret = ENOSYS, dev, unit ;    snddev_info *d;    u_long s;    dev = minor(i_dev);    d = get_snddev_info(dev, &unit);    if (d == NULL)	return (ENXIO) ;    if ( (dev & 0x0f) == SND_DEV_SEQ ) {	/* sequencer. Hack... */#if 0	if (d->synth_base)	    return opl3_ioctl(i_dev, cmd, arg, mode, p) ;	else#endif	    return ENXIO ;    }    if (d->ioctl)	ret = d->ioctl(dev, cmd, arg, mode, p);    if (ret != ENOSYS)	return ret ;    /*     * pass control to the default ioctl handler. Set ret to 0 now.     */    ret = 0 ;    /*     * The linux ioctl interface for the sound driver has a thousand     * different calls, and it is unpractical to put the names in     * the switch().  So we have some tests before for common routines,     * such as the ones related to the mixer.  But we really ought     * to redesign the interface!     *     * Reading from the mixer just requires to look at the cached     * copy in d->mix_levels[dev], so this routine should cover     * practically all needs for mixer reading.     */    if ( (cmd & MIXER_READ(0)) == MIXER_READ(0) && (cmd & 0xff) < 32 ) {	int dev = cmd & 0x1f ;	if ( d->mix_devs & (1<<dev) ) { /* supported */	    *(int *)arg = d->mix_levels[dev];	    return 0 ;	} else	    return EINVAL ;    }    /*     * all routines are called with int. blocked. Make sure that     * ints are re-enabled when calling slow or blocking functions!     */    s = spltty();    switch(cmd) {    /*     * we start with the new ioctl interface.     */    case AIONWRITE :	/* how many bytes can write ? */	if (d->dbuf_out.dl)	    dsp_wr_dmaupdate(&(d->dbuf_out));	*(int *)arg = d->dbuf_out.fl;	break;    case AIOSSIZE :     /* set the current blocksize */	{	    struct snd_size *p = (struct snd_size *)arg;	    if (p->play_size <= 1 && p->rec_size <= 1) { /* means no blocks */		d->flags &= ~SND_F_HAS_SIZE ;	    } else {		RANGE (p->play_size, 40, d->dbuf_out.bufsize /4);		d->play_blocksize = p->play_size  & ~3 ;		RANGE (p->rec_size, 40, d->dbuf_in.bufsize /4);		d->rec_blocksize = p->rec_size  & ~3 ;		d->flags |= SND_F_HAS_SIZE ;	    }	}	splx(s);	ask_init(d);	/* FALLTHROUGH */    case AIOGSIZE :	/* get the current blocksize */	{	    struct snd_size *p = (struct snd_size *)arg;	    p->play_size = d->play_blocksize ;	    p->rec_size = d->rec_blocksize ;	}	break ;    case AIOSFMT :	{	    snd_chan_param *p = (snd_chan_param *)arg;	    d->play_speed = p->play_rate;	    d->rec_speed = p->play_rate; /* XXX one speed allowed */	    if (p->play_format & AFMT_STEREO)		d->flags |= SND_F_STEREO ;	    else		d->flags &= ~SND_F_STEREO ;	    d->play_fmt = p->play_format & ~AFMT_STEREO ;	    d->rec_fmt = p->rec_format & ~AFMT_STEREO ;	}	splx(s);	if (!ask_init(d))	    break ; /* could not reinit */	/* FALLTHROUGH */    case AIOGFMT :	{	    snd_chan_param *p = (snd_chan_param *)arg;	    p->play_rate = d->play_speed;	    p->rec_rate = d->rec_speed;	    p->play_format = d->play_fmt;	    p->rec_format = d->rec_fmt;	    if (d->flags & SND_F_STEREO) {		p->play_format |= AFMT_STEREO ;		p->rec_format |= AFMT_STEREO ;	    }	}	break;    case AIOGCAP :     /* get capabilities */	/* this should really be implemented by the driver */	{	    snd_capabilities *p = (snd_capabilities *)arg;	    p->rate_min = 5000;	    p->rate_max = 48000; /* default */	    p->bufsize = d->bufsize;	    p->formats = d->audio_fmt; /* default */	    p->mixers = 1 ; /* default: one mixer */	    p->inputs = d->mix_devs ;	    p->left = p->right = 255 ;	}	break ;    case AIOSTOP:	if (*(int *)arg == AIOSYNC_PLAY) /* play */	    *(int *)arg = dsp_wrabort(d, 1 /* restart */);	else if (*(int *)arg == AIOSYNC_CAPTURE)	    *(int *)arg = dsp_rdabort(d, 1 /* restart */);	else {	    splx(s);	    printf("AIOSTOP: bad channel 0x%x\n", *(int *)arg);	    *(int *)arg = 0 ;	}	break ;    case AIOSYNC:	printf("AIOSYNC chan 0x%03lx pos %d unimplemented\n",	    ((snd_sync_parm *)arg)->chan,	    ((snd_sync_parm *)arg)->pos);	break;    /*     * here follow the standard ioctls (filio.h etc.)     */    case FIONREAD : /* get # bytes to read */	if ( d->dbuf_in.dl )	    dsp_rd_dmaupdate(&(d->dbuf_in));	*(int *)arg = d->dbuf_in.rl;	break;    case FIOASYNC: /*set/clear async i/o */	printf("FIOASYNC\n");	break;    case SNDCTL_DSP_NONBLOCK :    case FIONBIO : /* set/clear non-blocking i/o */	if ( *(int *)arg == 0 )	    d->flags &= ~SND_F_NBIO ;	else	    d->flags |= SND_F_NBIO ;	break ;    /*     * Finally, here is the linux-compatible ioctl interface     */#define THE_REAL_SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int)    case THE_REAL_SNDCTL_DSP_GETBLKSIZE:    case SNDCTL_DSP_GETBLKSIZE:	*(int *) arg = d->play_blocksize ;	break ;    case SNDCTL_DSP_SETBLKSIZE :	{	    int t = *(int *)arg;	    if (t <= 1) { /* means no blocks */		d->flags &= ~SND_F_HAS_SIZE ;	    } else {		RANGE (t, 40, d->dbuf_out.bufsize /4);		d->play_blocksize =		d->rec_blocksize = t  & ~3 ; /* align to multiple of 4 */		d->flags |= SND_F_HAS_SIZE ;	    }	}	splx(s);	ask_init(d);	break ;    case SNDCTL_DSP_RESET:	DEB(printf("dsp reset\n"));	dsp_wrabort(d, 1 /* restart */);	dsp_rdabort(d, 1 /* restart */);	break ;    case SNDCTL_DSP_SYNC:	DEB(printf("dsp sync\n"));	splx(s);	snd_sync(d, 1, d->dbuf_out.bufsize - 4); /* DMA does not start with <4 bytes */	break ;    case SNDCTL_DSP_SPEED:	d->play_speed = d->rec_speed = *(int *)arg ;	splx(s);	if (ask_init(d))	    *(int *)arg = d->play_speed ;	break ;    case SNDCTL_DSP_STEREO:	if ( *(int *)arg == 0 )	    d->flags &= ~SND_F_STEREO ; /* mono */	else if ( *(int *)arg == 1 )	    d->flags |= SND_F_STEREO ; /* stereo */	else {	    printf("dsp stereo: %d is invalid, assuming 1\n", *(int *)arg );	    d->flags |= SND_F_STEREO ; /* stereo */	}	splx(s);	if (ask_init(d))	    *(int *)arg = (d->flags & SND_F_STEREO) ? 1 : 0 ;	break ;    case SOUND_PCM_WRITE_CHANNELS:	if ( *(int *)arg == 1)	    d->flags &= ~SND_F_STEREO ; /* mono */	else if ( *(int *)arg == 2)	    d->flags |= SND_F_STEREO ; /* stereo */	else {	    ret = EINVAL ;	    break ;	}	splx(s);	if (ask_init(d))	    *(int *)arg = (d->flags & SND_F_STEREO) ? 2 : 1 ;	break ;    case SOUND_PCM_READ_RATE:	*(int *)arg = d->play_speed;	break ;    case SOUND_PCM_READ_CHANNELS:	*(int *)arg = (d->flags & SND_F_STEREO) ? 2 : 1;	break ;    case SNDCTL_DSP_GETFMTS:	/* returns a mask of supported fmts */	*(int *)arg = (int)d->audio_fmt ;	break ;    case SNDCTL_DSP_SETFMT:	/* sets _one_ format */	/*	 * when some card (SB16) is opened RDONLY or WRONLY,	 * only one of the fields is set, the other becomes 0.	 * This makes it possible to select DMA channels at runtime.	 */	if (d->play_fmt)	    d->play_fmt = *(int *)arg ;	if (d->rec_fmt)	    d->rec_fmt = *(int *)arg ;	splx(s);	if (ask_init(d))	    *(int *)arg = d->play_fmt ;	break ;    case SNDCTL_DSP_SUBDIVIDE:	/* XXX watch out, this is RW! */	DEB(printf("SNDCTL_DSP_SUBDIVIDE yet unimplemented\n");)	break;    case SNDCTL_DSP_SETFRAGMENT:	/* XXX watch out, this is RW! */	DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg));

⌨️ 快捷键说明

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