📄 cs46xx.c
字号:
SGarray[4] = *(ptmp+2); SGarray[5] = 0x80000010; SGarray[6] = *ptmp; SGarray[7] = *(ptmp+2); SGarray[8] = (virt_to_bus(dmabuf->pbuf) & 0xffff000) | 0x10; if (dmabuf->SGok) { dmabuf->numfrag = nSGpages; dmabuf->fragsize = 4096; dmabuf->fragsamples = 4096 >> sample_shift[dmabuf->fmt]; dmabuf->fragshift = 12; dmabuf->dmasize = dmabuf->numfrag*4096; } else { SGarray[0] = 0xf2c0000f; SGarray[1] = 0x00000200; SGarray[2] = 0; SGarray[3] = 0x00010600; SGarray[4]=SGarray[5]=SGarray[6]=SGarray[7]=SGarray[8] = 0; dmabuf->numfrag = 2; dmabuf->fragsize = 2048; dmabuf->fragsamples = 2048 >> sample_shift[dmabuf->fmt]; dmabuf->dmasize = 4096; dmabuf->fragshift = 11; } for(tmp1 = 0; tmp1 < sizeof(SGarray)/4; tmp1++) cs461x_poke( state->card, BA1_PDTC+tmp1*4, SGarray[tmp1]); memset(dmabuf->rawbuf, (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80, dmabuf->dmasize); /* * Now set up the ring */ spin_lock_irqsave(&state->card->lock, flags); cs_play_setup(state); spin_unlock_irqrestore(&state->card->lock, flags); /* set the ready flag for the dma buffer */ dmabuf->ready = 1; CS_DBGOUT(CS_PARMS, 4, printk( "cs461x: prog_dmabuf(): PLAYBACK rate=%d fmt=0x%x numfrag=%d " "fragsize=%d dmasize=%d\n", dmabuf->rate, dmabuf->fmt, dmabuf->numfrag, dmabuf->fragsize, dmabuf->dmasize) ); CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- \n")); return 0; } else { CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- Invalid Type %d\n", dmabuf->type)); } return 1;}static void cs_clear_tail(struct cs_state *state){}static int drain_dac(struct cs_state *state, int nonblock){ DECLARE_WAITQUEUE(wait, current); struct dmabuf *dmabuf = &state->dmabuf; unsigned long flags; unsigned long tmo; int count; if (dmabuf->mapped || !dmabuf->ready) return 0; add_wait_queue(&dmabuf->wait, &wait); for (;;) { /* It seems that we have to set the current state to TASK_INTERRUPTIBLE every time to make the process really go to sleep */ current->state = TASK_INTERRUPTIBLE; spin_lock_irqsave(&state->card->lock, flags); count = dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); if (count <= 0) break; if (signal_pending(current)) break; if (nonblock) { remove_wait_queue(&dmabuf->wait, &wait); current->state = TASK_RUNNING; return -EBUSY; } tmo = (dmabuf->dmasize * HZ) / dmabuf->rate; tmo >>= sample_shift[dmabuf->fmt]; tmo += (2048*HZ)/dmabuf->rate; if (!schedule_timeout(tmo ? tmo : 1) && tmo){ printk(KERN_ERR "cs461x: drain_dac, dma timeout? %d\n", count); break; } } remove_wait_queue(&dmabuf->wait, &wait); current->state = TASK_RUNNING; if (signal_pending(current)) return -ERESTARTSYS; return 0;}/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */static void cs_update_ptr(void){ struct cs_card *card=devs; struct cs_state *state; struct dmabuf *dmabuf; unsigned hwptr; int diff; /* error handling and process wake up for ADC */ state = card->states[0]; if(state) { dmabuf = &state->dmabuf; if (dmabuf->enable & ADC_RUNNING) { /* update hardware pointer */ hwptr = cs_get_dma_addr(state); diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; CS_DBGOUT(CS_PARMS, 9, printk( "cs46xx: cs_update_ptr()+ ADC hwptr=%d diff=%d\n", hwptr,diff) ); dmabuf->hwptr = hwptr; dmabuf->total_bytes += diff; dmabuf->count += diff; if (dmabuf->count > dmabuf->dmasize) dmabuf->count = dmabuf->dmasize; if(dmabuf->mapped) { if (dmabuf->count >= (signed)dmabuf->fragsize) wake_up(&dmabuf->wait); } else { if (dmabuf->count > 0) wake_up(&dmabuf->wait); } } }/* * Now the DAC */ state = card->states[1]; if(state) { dmabuf = &state->dmabuf; /* error handling and process wake up for DAC */ if (dmabuf->enable & DAC_RUNNING) { /* update hardware pointer */ hwptr = cs_get_dma_addr(state); diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize; CS_DBGOUT(CS_PARMS, 9, printk( "cs46xx: cs_update_ptr()+ DAC hwptr=%d diff=%d\n", hwptr,diff) ); dmabuf->hwptr = hwptr; dmabuf->total_bytes += diff; if (dmabuf->mapped) { dmabuf->count += diff; if (dmabuf->count >= (signed)dmabuf->fragsize) wake_up(&dmabuf->wait); /* * other drivers use fragsize, but don't see any sense * in that, since dmasize is the buffer asked for * via mmap. */ if( dmabuf->count > dmabuf->dmasize) dmabuf->count &= dmabuf->dmasize-1; } else { dmabuf->count -= diff; /* * backfill with silence and clear out the last * "diff" number of bytes. */ if(hwptr >= diff) { memset(dmabuf->rawbuf + hwptr - diff, (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80, diff); } else { memset(dmabuf->rawbuf, (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80, (unsigned)hwptr); memset((void *)((unsigned)dmabuf->rawbuf + dmabuf->dmasize + hwptr - diff), (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80, diff - hwptr); } if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { CS_DBGOUT(CS_ERROR, 2, printk( "cs46xx: ERROR DAC count<0 or count > dmasize (%d)\n", dmabuf->count)); /* * buffer underrun or buffer overrun, reset the * count of bytes written back to 0. */ if(dmabuf->count < 0) dmabuf->underrun=1; dmabuf->count = 0; dmabuf->error++; } if (dmabuf->count < (signed)dmabuf->dmasize/2) wake_up(&dmabuf->wait); } } }}/* hold spinlock for the following! */static void cs_handle_midi(struct cs_card *card){ unsigned char ch; int wake; unsigned temp1; wake = 0; while (!(cs461x_peekBA0(card, BA0_MIDSR) & MIDSR_RBE)) { ch = cs461x_peekBA0(card, BA0_MIDRP); if (card->midi.icnt < CS_MIDIINBUF) { card->midi.ibuf[card->midi.iwr] = ch; card->midi.iwr = (card->midi.iwr + 1) % CS_MIDIINBUF; card->midi.icnt++; } wake = 1; } if (wake) wake_up(&card->midi.iwait); wake = 0; while (!(cs461x_peekBA0(card, BA0_MIDSR) & MIDSR_TBF) && card->midi.ocnt > 0) { temp1 = ( card->midi.obuf[card->midi.ord] ) & 0x000000ff; cs461x_pokeBA0(card, BA0_MIDWP,temp1); card->midi.ord = (card->midi.ord + 1) % CS_MIDIOUTBUF; card->midi.ocnt--; if (card->midi.ocnt < CS_MIDIOUTBUF-16) wake = 1; } if (wake) wake_up(&card->midi.owait);}static void cs_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct cs_card *card = (struct cs_card *)dev_id; /* Single channel card */ struct cs_state *recstate = card->channel[0].state; struct cs_state *playstate = card->channel[1].state; u32 status; CS_DBGOUT(CS_INTERRUPT, 4, printk("cs46xx: cs_interrupt()+ \n")); spin_lock(&card->lock); status = cs461x_peekBA0(card, BA0_HISR); if ((status & 0x7fffffff) == 0) { cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV); spin_unlock(&card->lock); return; } /* * check for playback or capture interrupt only */ if( ((status & HISR_VC0) && playstate && playstate->dmabuf.ready) || (((status & HISR_VC1) && recstate && recstate->dmabuf.ready)) ) { CS_DBGOUT(CS_INTERRUPT, 8, printk( "cs46xx: cs_interrupt() interrupt bit(s) set (0x%x)\n",status)); cs_update_ptr(); } if( status & HISR_MIDI ) cs_handle_midi(card); /* clear 'em */ cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV); spin_unlock(&card->lock); CS_DBGOUT(CS_INTERRUPT, 4, printk("cs46xx: cs_interrupt()- \n"));}/**********************************************************************/static ssize_t cs_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos){ struct cs_card *card = (struct cs_card *)file->private_data; ssize_t ret; unsigned long flags; unsigned ptr; int cnt; if (ppos != &file->f_pos) return -ESPIPE; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; ret = 0; while (count > 0) { spin_lock_irqsave(&card->lock, flags); ptr = card->midi.ird; cnt = CS_MIDIINBUF - ptr; if (card->midi.icnt < cnt) cnt = card->midi.icnt; spin_unlock_irqrestore(&card->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) return ret ? ret : -EAGAIN; interruptible_sleep_on(&card->midi.iwait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; continue; } if (copy_to_user(buffer, card->midi.ibuf + ptr, cnt)) return ret ? ret : -EFAULT; ptr = (ptr + cnt) % CS_MIDIINBUF; spin_lock_irqsave(&card->lock, flags); card->midi.ird = ptr; card->midi.icnt -= cnt; spin_unlock_irqrestore(&card->lock, flags); count -= cnt; buffer += cnt; ret += cnt; } return ret;}static ssize_t cs_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){ struct cs_card *card = (struct cs_card *)file->private_data; ssize_t ret; unsigned long flags; unsigned ptr; int cnt; if (ppos != &file->f_pos) return -ESPIPE; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; ret = 0; while (count > 0) { spin_lock_irqsave(&card->lock, flags); ptr = card->midi.owr; cnt = CS_MIDIOUTBUF - ptr; if (card->midi.ocnt + cnt > CS_MIDIOUTBUF) cnt = CS_MIDIOUTBUF - card->midi.ocnt; if (cnt <= 0) cs_handle_midi(card); spin_unlock_irqrestore(&card->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) return ret ? ret : -EAGAIN; interruptible_sleep_on(&card->midi.owait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; continue; } if (copy_from_user(card->midi.obuf + ptr, buffer, cnt)) return ret ? ret : -EFAULT; ptr = (ptr + cnt) % CS_MIDIOUTBUF; spin_lock_irqsave(&card->lock, flags); card->midi.owr = ptr; card->midi.ocnt += cnt; spin_unlock_irqrestore(&card->lock, flags); count -= cnt; buffer += cnt; ret += cnt; spin_lock_irqsave(&card->lock, flags); cs_handle_midi(card); spin_unlock_irqrestore(&card->lock, flags); } return ret;}static unsigned int cs_midi_poll(struct file *file, struct poll_table_struct *wait){ struct cs_card *card = (struct cs_card *)file->private_data; unsigned long flags; unsigned int mask = 0; if (file->f_flags & FMODE_WRITE) poll_wait(file, &card->midi.owait, wait); if (file->f_flags & FMODE_READ) poll_wait(file, &card->midi.iwait, wait); spin_lock_irqsave(&card->lock, flags); if (file->f_flags & FMODE_READ) { if (card->midi.icnt > 0) mask |= POLLIN | POLLRDNORM; } if (file->f_flags & FMODE_WRITE) { if (card->midi.ocnt < CS_MIDIOUTBUF) mask |= POLLOUT | POLLWRNORM; } spin_unlock_irqrestore(&card->lock, flags); return mask;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -