📄 dmasound_awacs.c
字号:
case SOUND_MIXER_READ_RECSRC: data = 0; if (awacs_reg[0] & MASK_MUX_AUDIN) data |= SOUND_MASK_LINE; if (awacs_reg[0] & MASK_MUX_MIC) data |= SOUND_MASK_MIC; if (awacs_reg[0] & MASK_MUX_CD) data |= SOUND_MASK_CD; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_WRITE_RECSRC: IOCTL_IN(arg, data); data &= (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD); awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC | MASK_MUX_AUDIN); if (data & SOUND_MASK_LINE) awacs_reg[0] |= MASK_MUX_AUDIN; if (data & SOUND_MASK_MIC) awacs_reg[0] |= MASK_MUX_MIC; if (data & SOUND_MASK_CD) awacs_reg[0] |= MASK_MUX_CD; awacs_write(awacs_reg[0] | MASK_ADDR0); rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_STEREODEVS: data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER | SOUND_MASK_RECLEV | SOUND_MASK_CD | SOUND_MASK_LINE; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_CAPS: rc = IOCTL_OUT(arg, 0); break; case SOUND_MIXER_WRITE_VOLUME: IOCTL_IN(arg, data); awacs_burgundy_write_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME, data); /* Fall through */ case SOUND_MIXER_READ_VOLUME: rc = IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME)); break; case SOUND_MIXER_WRITE_SPEAKER: IOCTL_IN(arg, data); if (!(data & 0xff)) { /* Mute the left speaker */ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x2); } else { /* Unmute the left speaker */ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x2); } if (!(data & 0xff00)) { /* Mute the right speaker */ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x4); } else { /* Unmute the right speaker */ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x4); } data = (((data&0xff)*16)/100 > 0xf ? 0xf : (((data&0xff)*16)/100)) + ((((data>>8)*16)/100 > 0xf ? 0xf : ((((data>>8)*16)/100)))<<4); awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, ~data); /* Fall through */ case SOUND_MIXER_READ_SPEAKER: data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER); data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8); rc = IOCTL_OUT(arg, ~data); break; case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ IOCTL_IN(arg, data); beep_vol = data & 0xff; /* fall through */ case SOUND_MIXER_READ_ALTPCM: rc = IOCTL_OUT(arg, beep_vol); break; case SOUND_MIXER_WRITE_LINE: IOCTL_IN(arg, data); awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLLINE, data); /* fall through */ case SOUND_MIXER_READ_LINE: data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE); rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_WRITE_MIC: IOCTL_IN(arg, data); /* Mic is mono device */ data = (data << 8) + (data << 24); awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLMIC, data); /* fall through */ case SOUND_MIXER_READ_MIC: data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC); data <<= 24; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_WRITE_CD: IOCTL_IN(arg, data); awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLCD, data); /* fall through */ case SOUND_MIXER_READ_CD: data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLCD); rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_WRITE_RECLEV: IOCTL_IN(arg, data); data = awacs_volume_setter(data, 0, 0, 4); rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_RECLEV: data = awacs_get_volume(awacs_reg[0], 4); rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_OUTMASK: case SOUND_MIXER_OUTSRC: default: rc = -EINVAL; } return rc;}static int tumbler_mixer_ioctl(u_int cmd, u_long arg){ int data; int rc; /* We are, we are, we are... Tumbler (and very dumb) */ /* Ok, we're not THAT dumb anymore, but still pretty dumb :-) */ switch(cmd) { case SOUND_MIXER_READ_DEVMASK: data = SOUND_MASK_VOLUME | SOUND_MASK_ALTPCM | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_RECMASK: data = 0; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_RECSRC: data = 0; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_WRITE_RECSRC: IOCTL_IN(arg, data); data =0; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_STEREODEVS: data = SOUND_MASK_VOLUME | SOUND_MASK_PCM; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_CAPS: rc = IOCTL_OUT(arg, 0); break; case SOUND_MIXER_WRITE_BASS: IOCTL_IN(arg, data); tumbler_set_bass(data); /* Fall through */ case SOUND_MIXER_READ_BASS: tumbler_get_bass(&data); rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_WRITE_TREBLE: IOCTL_IN(arg, data); tumbler_set_treble(data); /* Fall through */ case SOUND_MIXER_READ_TREBLE: tumbler_get_treble(&data); rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_WRITE_PCM: IOCTL_IN(arg, data); tumbler_set_pcm_lvl(data); /* Fall through */ case SOUND_MIXER_READ_PCM: tumbler_get_pcm_lvl(&data); IOCTL_OUT(arg, data); break; case SOUND_MIXER_WRITE_VOLUME: IOCTL_IN(arg, data); tumbler_set_volume(data, data); /* Fall through */ case SOUND_MIXER_READ_VOLUME: tumbler_get_volume(& data, &data); rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ IOCTL_IN(arg, data); beep_vol = data & 0xff; /* fall through */ case SOUND_MIXER_READ_ALTPCM: rc = IOCTL_OUT(arg, beep_vol); break; case SOUND_MIXER_OUTMASK: case SOUND_MIXER_OUTSRC: default: rc = -EINVAL; } return rc;}static int daca_mixer_ioctl(u_int cmd, u_long arg){ int data; int rc; /* And the DACA's no genius either! */ switch(cmd) { case SOUND_MIXER_READ_DEVMASK: data = SOUND_MASK_VOLUME; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_RECMASK: data = 0; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_RECSRC: data = 0; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_WRITE_RECSRC: IOCTL_IN(arg, data); data =0; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_STEREODEVS: data = SOUND_MASK_VOLUME; rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_READ_CAPS: rc = IOCTL_OUT(arg, 0); break; case SOUND_MIXER_WRITE_VOLUME: IOCTL_IN(arg, data); daca_set_volume(data, data); /* Fall through */ case SOUND_MIXER_READ_VOLUME: daca_get_volume(& data, &data); rc = IOCTL_OUT(arg, data); break; case SOUND_MIXER_OUTMASK: case SOUND_MIXER_OUTSRC: default: rc = -EINVAL; } return rc;}static int PMacMixerIoctl(u_int cmd, u_long arg){ int rc; /* Different IOCTLS for burgundy and, eventually, DACA & Tumbler */ TRY_LOCK(); switch (awacs_revision){ case AWACS_BURGUNDY: rc = burgundy_mixer_ioctl(cmd, arg); break ; case AWACS_DACA: rc = daca_mixer_ioctl(cmd, arg); break; case AWACS_TUMBLER: rc = tumbler_mixer_ioctl(cmd, arg); break ; default: /* ;-)) */ rc = awacs_mixer_ioctl(cmd, arg); } UNLOCK(); return rc;}static void PMacMixerInit(void){ switch (awacs_revision) { case AWACS_TUMBLER: printk("AE-Init tumbler mixer\n"); break ; case AWACS_DACA: case AWACS_BURGUNDY: break ; /* don't know yet */ case AWACS_AWACS: case AWACS_SCREAMER: default: awacs_mixer_init() ; break ; }}/* Write/Read sq setup functions: Check to see if we have enough (or any) dbdma cmd buffers for the user's fragment settings. If not, allocate some. If this fails we will point at the beep buffer - as an emergency provision - to stop dma tromping on some random bit of memory (if someone lets it go anyway). The command buffers are then set up to point to the fragment buffers (allocated elsewhere). We need n+1 commands the last of which holds a NOP + loop to start.*/static int PMacWriteSqSetup(void){ int i, count = 600 ; volatile struct dbdma_cmd *cp; LOCK(); /* stop the controller from doing any output - if it isn't already. it _should_ be before this is called anyway */ out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); while ((in_le32(&awacs_txdma->status) & RUN) && count--) udelay(1);#ifdef DEBUG_DMASOUNDif (count <= 0) printk("dmasound_pmac: write sq setup: timeout waiting for dma to stop\n");#endif if ((write_sq.max_count + 1) > number_of_tx_cmd_buffers) { if (awacs_tx_cmd_space) kfree(awacs_tx_cmd_space); number_of_tx_cmd_buffers = 0; /* we need nbufs + 1 (for the loop) and we should request + 1 again because the DBDMA_ALIGN might pull the start up by up to sizeof(struct dbdma_cmd) - 4. */ awacs_tx_cmd_space = kmalloc ((write_sq.max_count + 1 + 1) * sizeof(struct dbdma_cmd), GFP_KERNEL); if (awacs_tx_cmd_space == NULL) { /* don't leave it dangling - nasty but better than a random address */ out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); printk(KERN_ERR "dmasound_pmac: can't allocate dbdma cmd buffers" ", driver disabled\n"); UNLOCK(); return -ENOMEM; } awacs_tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(awacs_tx_cmd_space); number_of_tx_cmd_buffers = write_sq.max_count + 1; } cp = awacs_tx_cmds; memset((void *)cp, 0, (write_sq.max_count+1) * sizeof(struct dbdma_cmd)); for (i = 0; i < write_sq.max_count; ++i, ++cp) { st_le32(&cp->phy_addr, virt_to_bus(write_sq.buffers[i])); } st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS); st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds)); /* point the controller at the command stack - ready to go */ out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds)); UNLOCK(); return 0;}static int PMacReadSqSetup(void){ int i, count = 600; volatile struct dbdma_cmd *cp; LOCK(); /* stop the controller from doing any input - if it isn't already. it _should_ be before this is called anyway */ out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); while ((in_le32(&awacs_rxdma->status) & RUN) && count--) udelay(1);#ifdef DEBUG_DMASOUNDif (count <= 0) printk("dmasound_pmac: read sq setup: timeout waiting for dma to stop\n");#endif if ((read_sq.max_count+1) > number_of_rx_cmd_buffers ) { if (awacs_rx_cmd_space) kfree(awacs_rx_cmd_space); number_of_rx_cmd_buffers = 0; /* we need nbufs + 1 (for the loop) and we should request + 1 again because the DBDMA_ALIGN might pull the start up by up to sizeof(struct dbdma_cmd) - 4 (assuming kmalloc aligns 32 bits). */ awacs_rx_cmd_space = kmalloc ((read_sq.max_count + 1 + 1) * sizeof(struct dbdma_cmd), GFP_KERNEL); if (awacs_rx_cmd_space == NULL) { /* don't leave it dangling - nasty but better than a random address */ out_le32(&awacs_rxdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); printk(KERN_ERR "dmasound_pmac: can't allocate dbdma cmd buffers" ", driver disabled\n"); UNLOCK(); return -ENOMEM; } awacs_rx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(awacs_rx_cmd_space); number_of_rx_cmd_buffers = read_sq.max_count + 1 ; } cp = awacs_rx_cmds; memset((void *)cp, 0, (read_sq.max_count+1) * sizeof(struct dbdma_cmd)); /* Set dma buffers up in a loop */ for (i = 0; i < read_sq.max_count; i++,cp++) { st_le32(&cp->phy_addr, virt_to_bus(read_sq.buffers[i])); st_le16(&cp->command, INPUT_MORE + INTR_ALWAYS); st_le16(&cp->req_count, read_sq.block_size); st_le16(&cp->xfer_status, 0); } /* The next two lines make the thing loop around. */ st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS); st_le32(&cp->cmd_dep, virt_to_bus(awacs_rx_cmds)); /* point the controller at the command stack - ready to go */ out_le32(&awacs_rxdma->cmdptr, virt_to_bus(awacs_rx_cmds)); UNLOCK(); return 0;}/* TODO: this needs work to guarantee that when it returns DMA has stopped but in a more elegant way than is done here....*/static void PMacAbortRead(void){ int i; volatile struct dbdma_cmd *cp; LOCK(); /* give it a chance to update the output and provide the IRQ that is expected. */ out_le32(&awacs_rxdma->control, ((FLUSH) << 16) + FLUSH ); cp = awacs_rx_cmds; for (i = 0; i < read_sq.max_count; i++,cp++) st_le16(&cp->command, DBDMA_STOP); /* * We should probably wait for the thing to stop before we * release the memory. */ wait_ms(100) ; /* give it a (small) chance to act */ /* apply the sl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -