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

📄 pcm86.c

📁 freebsd v4.4内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
}static voidfifo_recv_mono_16be(pcm_data *buf, int count, int uflag){    int i, cnt;    short d, d0, d1, el, er, zlev;    zlev = uflag ? -128 : 0;    cnt = count / 2;    if (pcm_s.speed == pcm_s.chipspeed) {	/* No reason to convert the pcm speed. */	for (i = 0; i < cnt; i++) {	    el = inb(pcm_s.iobase + 12) << 8;	    el |= inb(pcm_s.iobase + 12);	    er = inb(pcm_s.iobase + 12) << 8;	    er |= inb(pcm_s.iobase + 12);	    d = (el + er) >> 1;	    *buf++ = ((d >> 8) & 0xff) + zlev;	    *buf++ = d & 0xff;	}	if (count % 2) {	    el = inb(pcm_s.iobase + 12) << 8;	    el |= inb(pcm_s.iobase + 12);	    er = inb(pcm_s.iobase + 12) << 8;	    er |= inb(pcm_s.iobase + 12);	    d = (el + er) >> 1;	    *buf++ = ((d >> 8) & 0xff) + zlev;	    tmpbuf.buff[0] = d & 0xff;	    tmpbuf.size = 1;	}    } else {	/* Speed conversion with linear interpolation method. */	d0 = pcm_s.last_l;	el = inb(pcm_s.iobase + 12) << 8;	el |= inb(pcm_s.iobase + 12);	er = inb(pcm_s.iobase + 12) << 8;	er |= inb(pcm_s.iobase + 12);	d1 = (el + er) >> 1;	for (i = 0; i < cnt; i++) {	    while (pcm_s.acc >= pcm_s.speed) {		pcm_s.acc -= pcm_s.speed;		d0 = d1;		el = inb(pcm_s.iobase + 12) << 8;		el |= inb(pcm_s.iobase + 12);		er = inb(pcm_s.iobase + 12) << 8;		er |= inb(pcm_s.iobase + 12);		d1 = (el + er) >> 1;	    }	    d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))		/ pcm_s.speed;	    *buf++ = ((d >> 8) & 0xff) + zlev;	    *buf++ = d & 0xff;	    pcm_s.acc += pcm_s.chipspeed;	}	if (count % 2) {	    while (pcm_s.acc >= pcm_s.speed) {		pcm_s.acc -= pcm_s.speed;		d0 = d1;		el = inb(pcm_s.iobase + 12) << 8;		el |= inb(pcm_s.iobase + 12);		er = inb(pcm_s.iobase + 12) << 8;		er |= inb(pcm_s.iobase + 12);		d1 = (el + er) >> 1;	    }	    d = ((d0 * (pcm_s.speed - pcm_s.acc)) + (d1 * pcm_s.acc))		/ pcm_s.speed;	    *buf++ = ((d >> 8) & 0xff) + zlev;	    tmpbuf.buff[0] = d & 0xff;	    tmpbuf.size = 1;	}	pcm_s.last_l = d0;    }}static voidpcm_stop(void){    fifo_stop();		/* stop FIFO */    fifo_reset();		/* reset FIFO buffer */    /* Reset driver's status. */    pcm_s.intr_busy = NO;    pcm_s.intr_last = NO;    pcm_s.intr_trailer = NO;    pcm_s.acc = 0;    pcm_s.last_l = 0;    pcm_s.last_r = 0;    DEB(printk("pcm_stop\n"));}static voidpcm_init(void){    /* Initialize registers on the board. */    pcm_stop();    if (pcm_s.board_type == PC980173_FAMILY)	dsp73_init();    /* Set default volume. */    set_volume(DEFAULT_VOLUME);    /* Initialize driver's status. */    pcm_s.opened = NO;    pcm_initialized = YES;}/* * Codes for global use */intprobe_pcm86(struct address_info *hw_config){    return pcm86_detect(hw_config);}longattach_pcm86(long mem_start, struct address_info *hw_config){    if (pcm_s.board_type == NO_SUPPORTED_BOARD)	return mem_start;    /* Initialize the board. */    pcm_init();    printk("pcm0: <%s>", pcm86_operations.name);    if (num_audiodevs < MAX_AUDIO_DEV) {	my_dev = num_audiodevs++;	audio_devs[my_dev] = &pcm86_operations;	audio_devs[my_dev]->buffcount = DSP_BUFFCOUNT;	audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;#ifdef PCM86_DEBUG	printk("\nbuffsize = %d", DSP_BUFFSIZE);#endif    } else	printk("pcm0: Too many PCM devices available");    return mem_start;}static intpcm86_detect(struct address_info *hw_config){    int opna_iobase = 0x188, irq = 12, i;    unsigned char tmp;    if (hw_config->io_base == -1) {	printf("pcm0: iobase not specified. Assume default port(0x%x)\n",	       PCM86_IOBASE);	hw_config->io_base = PCM86_IOBASE;    }    pcm_s.iobase = hw_config->io_base;    /* auto configuration */    tmp = inb(pcm_s.iobase) & 0xfc;    switch ((tmp & 0xf0) >> 4) {    case 2:	opna_iobase = 0x188;	pcm_s.board_type = PC980173_FAMILY;	break;    case 3:	opna_iobase = 0x288;	pcm_s.board_type = PC980173_FAMILY;	break;    case 4:	opna_iobase = 0x188;	pcm_s.board_type = PC980186_FAMILY;	break;    case 5:	opna_iobase = 0x288;	pcm_s.board_type = PC980186_FAMILY;	break;    default:	pcm_s.board_type = NO_SUPPORTED_BOARD;	return NO;    }    /* Enable OPNA(YM2608) facilities. */    outb(pcm_s.iobase, tmp | 0x01);    /* Wait for OPNA to be ready. */    i = 100000;		/* Some large value */    while((inb(opna_iobase) & 0x80) && (i-- > 0));    /* Make IOA/IOB port ready (IOA:input, IOB:output) */    outb(opna_iobase, 0x07);    outb(0x5f, 0);	/* Because OPNA ports are comparatively slow(?), */    outb(0x5f, 0);	/* we'd better wait a moment. */    outb(0x5f, 0);    outb(0x5f, 0);    tmp = inb(opna_iobase + 2) & 0x3f;    outb(opna_iobase + 2, tmp | 0x80);    /* Wait for OPNA to be ready. */    i = 100000;		/* Some large value */    while((inb(opna_iobase) & 0x80) && (i-- > 0));    /* Get irq number from IOA port. */    outb(opna_iobase, 0x0e);    outb(0x5f, 0);    outb(0x5f, 0);    outb(0x5f, 0);    outb(0x5f, 0);    tmp = inb(opna_iobase + 2) & 0xc0;    switch (tmp >> 6) {    case 0:	/* INT0 (IRQ3)*/	irq = 3;	break;    case 1:	/* INT6 (IRQ13)*/	irq = 13;	break;    case 2:	/* INT4 (IRQ10)*/	irq = 10;	break;    case 3:	/* INT5 (IRQ12)*/	irq = 12;	break;    default:	/* error */	return NO;    }    /* Wait for OPNA to be ready. */    i = 100000;		/* Some large value */    while((inb(opna_iobase) & 0x80) && (i-- > 0));    /* Reset OPNA timer register. */    outb(opna_iobase, 0x27);    outb(0x5f, 0);    outb(0x5f, 0);    outb(0x5f, 0);    outb(0x5f, 0);    outb(opna_iobase + 2, 0x30);    /* Ok.  Detection finished. */    sprintf(pcm86_operations.name, board_name[pcm_s.board_type]);    pcm_initialized = NO;    pcm_s.irq = irq;    if ((hw_config->irq > 0) && (hw_config->irq != irq))	printf("pcm0: change irq %d -> %d\n", hw_config->irq, irq);    hw_config->irq = irq;    return YES;}static intpcm86_open(int dev, int mode){    int err;    if (!pcm_initialized)	return RET_ERROR(ENXIO);    if (pcm_s.intr_busy || pcm_s.opened)	return RET_ERROR(EBUSY);    if ((err = snd_set_irq_handler(pcm_s.irq, pcmintr, "PC-9801-73/86")) < 0)	return err;    pcm_stop();    tmpbuf.size = 0;    pcm_s.intr_mode = IMODE_NONE;    pcm_s.opened = YES;    return 0;}static voidpcm86_close(int dev){    snd_release_irq(pcm_s.irq);    pcm_s.opened = NO;}static voidpcm86_output_block(int dev, unsigned long buf, int count, int intrflag,		   int dma_restart){    unsigned long flags, cnt;    int maxchunksize;#ifdef PCM86_DEBUG    printk("pcm86_output_block():");    if (audio_devs[dev]->dmap->flags & DMA_BUSY)	printk(" DMA_BUSY");    if (audio_devs[dev]->dmap->flags & DMA_RESTART)	printk(" DMA_RESTART");    if (audio_devs[dev]->dmap->flags & DMA_ACTIVE)	printk(" DMA_ACTIVE");    if (audio_devs[dev]->dmap->flags & DMA_STARTED)	printk(" DMA_STARTED");    if (audio_devs[dev]->dmap->flags & DMA_ALLOC_DONE)	printk(" DMA_ALLOC_DONE");    printk("\n");#endif#if 0    DISABLE_INTR(flags);#endif#ifdef PCM86_DEBUG    printk("pcm86_output_block(): count = %d, intrsize= %d\n",	   count, pcm_s.intr_size);#endif    pcm_s.pdma_buf = (pcm_data *)buf;    pcm_s.pdma_count = count;    pcm_s.pdma_chunkcount = 1;    maxchunksize = (((PCM86_FIFOSIZE - pcm_s.intr_size * 2)		     / (pcm_s.bytes * 2)) * pcm_s.speed		    / pcm_s.chipspeed) * (pcm_s.bytes << pcm_s.stereo);    if (count > maxchunksize)	pcm_s.pdma_chunkcount = 2 * count / maxchunksize;    /*     * Let chunksize = (float)count / (float)pcm_s.pdma_chunkcount.     * Data of size chunksize is sent to the FIFO buffer on the 86-board     * on every occuring of interrupt.     * By assuming that pcm_s.intr_size < PCM86_FIFOSIZE / 2, we can conclude     * that the FIFO buffer never overflows from the following lemma.     *     * Lemma:     *	     maxchunksize / 2 <= chunksize <= maxchunksize.     *   (Though pcm_s.pdma_chunkcount is obtained through the flooring     *    function, this inequality holds.)     * Proof) Omitted.     */    fifo_output_block();    pcm_s.intr_last = NO;    pcm_s.intr_mode = IMODE_OUTPUT;    if (!pcm_s.intr_busy)	fifo_start(IMODE_OUTPUT);    pcm_s.intr_busy = YES;#if 0    RESTORE_INTR(flags);#endif}static voidpcm86_start_input(int dev, unsigned long buf, int count, int intrflag,		  int dma_restart){    unsigned long flags, cnt;    int maxchunksize;#ifdef PCM86_DEBUG    printk("pcm86_start_input():");    if (audio_devs[dev]->dmap->flags & DMA_BUSY)	printk(" DMA_BUSY");    if (audio_devs[dev]->dmap->flags & DMA_RESTART)	printk(" DMA_RESTART");    if (audio_devs[dev]->dmap->flags & DMA_ACTIVE)	printk(" DMA_ACTIVE");    if (audio_devs[dev]->dmap->flags & DMA_STARTED)	printk(" DMA_STARTED");    if (audio_devs[dev]->dmap->flags & DMA_ALLOC_DONE)	printk(" DMA_ALLOC_DONE");    printk("\n");#endif#if 0    DISABLE_INTR(flags);#endif    pcm_s.intr_size = PCM86_INTRSIZE_IN;#ifdef PCM86_DEBUG    printk("pcm86_start_input(): count = %d, intrsize= %d\n",	   count, pcm_s.intr_size);#endif    pcm_s.pdma_buf = (pcm_data *)buf;    pcm_s.pdma_count = count;    pcm_s.pdma_chunkcount = 1;    maxchunksize = ((pcm_s.intr_size / (pcm_s.bytes * 2)) * pcm_s.speed		    / pcm_s.chipspeed) * (pcm_s.bytes << pcm_s.stereo);    if (count > maxchunksize)	pcm_s.pdma_chunkcount = 2 * count / maxchunksize;    pcm_s.intr_mode = IMODE_INPUT;    if (!pcm_s.intr_busy)	fifo_start(IMODE_INPUT);    pcm_s.intr_busy = YES;#if 0    RESTORE_INTR(flags);#endif}static intpcm86_ioctl(int dev, unsigned int cmd, unsigned int arg, int local){    switch (cmd) {    case SOUND_PCM_WRITE_RATE:	if (local)	    return set_speed(arg);	return IOCTL_OUT(arg, set_speed(IOCTL_IN(arg)));    case SOUND_PCM_READ_RATE:	if (local)	    return pcm_s.speed;	return IOCTL_OUT(arg, pcm_s.speed);    case SNDCTL_DSP_STEREO:	if (local)	    return set_stereo(arg);	return IOCTL_OUT(arg, set_stereo(IOCTL_IN(arg)));    case SOUND_PCM_WRITE_CHANNELS:	if (local)	    return set_stereo(arg - 1) + 1;	return IOCTL_OUT(arg, set_stereo(IOCTL_IN(arg) - 1) + 1);    case SOUND_PCM_READ_CHANNELS:	if (local)	    return pcm_s.stereo + 1;	return IOCTL_OUT(arg, pcm_s.stereo + 1);    case SNDCTL_DSP_SETFMT:	if (local)	    return set_format(arg);	return IOCTL_OUT(arg, set_format(IOCTL_IN(arg)));    case SOUND_PCM_READ_BITS:	if (local)	    return pcm_s.bytes * 8;	return IOCTL_OUT(arg, pcm_s.bytes * 8);    }    /* Invalid ioctl request */    return RET_ERROR(EINVAL);}static intpcm86_prepare_for_input(int dev, int bufsize, int nbufs){    pcm_s.intr_size = PCM86_INTRSIZE_IN;    pcm_s.intr_mode = IMODE_NONE;    pcm_s.acc = 0;    pcm_s.last_l = 0;    pcm_s.last_r = 0;    DEB(printk("pcm86_prepare_for_input\n"));    return 0;}static intpcm86_prepare_for_output(int dev, int bufsize, int nbufs){    pcm_s.intr_size = PCM86_INTRSIZE_OUT;    pcm_s.intr_mode = IMODE_NONE;    pcm_s.acc = 0;    pcm_s.last_l = 0;    pcm_s.last_r = 0;    DEB(printk("pcm86_prepare_for_output\n"));    return 0;}static voidpcm86_reset(int dev){    pcm_stop();}static voidpcm86_halt_xfer(int dev){    pcm_stop();    DEB(printk("pcm86_halt_xfer\n"));}voidpcmintr(int unit){    unsigned char tmp;    if ((inb(pcm_s.iobase + 8) & 0x10) == 0)	return;		/* not FIFO intr. */    switch(pcm_s.intr_mode) {    case IMODE_OUTPUT:	if (pcm_s.intr_trailer) {	    DEB(printk("pcmintr(): fifo_reset\n"));	    fifo_reset();	    pcm_s.intr_trailer = NO;	    pcm_s.intr_busy = NO;	}	if (pcm_s.pdma_count > 0)	    fifo_output_block();	else	    DMAbuf_outputintr(my_dev, 1);	/* Reset intr. flag. */	tmp = inb(pcm_s.iobase + 8);	outb(pcm_s.iobase + 8, tmp & ~0x10);	outb(pcm_s.iobase + 8, tmp | 0x10);	break;    case IMODE_INPUT:	fifo_input_block();	if (pcm_s.pdma_count == 0)	    DMAbuf_inputintr(my_dev);	/* Reset intr. flag. */	tmp = inb(pcm_s.iobase + 8);	outb(pcm_s.iobase + 8, tmp & ~0x10);	outb(pcm_s.iobase + 8, tmp | 0x10);	break;    default:	pcm_stop();	printk("pcm0: unexpected interrupt\n");    }}#endif	/* EXCLUDE_PCM86, EXCLUDE_AUDIO */#endif	/* CONFIGURE_SOUNDCARD */

⌨️ 快捷键说明

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