swarm_cs4297a.c
来自「linux 内核源代码」· C语言 代码 · 共 1,971 行 · 第 1/5 页
C
1,971 行
// Mixer file operations struct.// ******************************************************************************************static /*const */ struct file_operations cs4297a_mixer_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .ioctl = cs4297a_ioctl_mixdev, .open = cs4297a_open_mixdev, .release = cs4297a_release_mixdev,};// --------------------------------------------------------------------- static int drain_adc(struct cs4297a_state *s, int nonblock){ /* This routine serves no purpose currently - any samples sitting in the receive queue will just be processed by the background consumer. This would be different if DMA actually stopped when there were no clients. */ return 0;}static int drain_dac(struct cs4297a_state *s, int nonblock){ DECLARE_WAITQUEUE(wait, current); unsigned long flags; unsigned hwptr; unsigned tmo; int count; if (s->dma_dac.mapped) return 0; if (nonblock) return -EBUSY; add_wait_queue(&s->dma_dac.wait, &wait); while ((count = __raw_readq(SS_CSR(R_SER_DMA_DSCR_COUNT_TX))) || (s->dma_dac.count > 0)) { if (!signal_pending(current)) { set_current_state(TASK_INTERRUPTIBLE); /* XXXKW is this calculation working? */ tmo = ((count * FRAME_TX_US) * HZ) / 1000000; schedule_timeout(tmo + 1); } else { /* XXXKW do I care if there is a signal pending? */ } } spin_lock_irqsave(&s->lock, flags); /* Reset the bookkeeping */ hwptr = (int)(((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) - s->dma_dac.descrtab_phys) / sizeof(serdma_descr_t)); s->dma_dac.hwptr = s->dma_dac.swptr = hwptr; spin_unlock_irqrestore(&s->lock, flags); remove_wait_queue(&s->dma_dac.wait, &wait); current->state = TASK_RUNNING; return 0;}// --------------------------------------------------------------------- static ssize_t cs4297a_read(struct file *file, char *buffer, size_t count, loff_t * ppos){ struct cs4297a_state *s = (struct cs4297a_state *) file->private_data; ssize_t ret; unsigned long flags; int cnt, count_fr, cnt_by; unsigned copied = 0; CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2, printk(KERN_INFO "cs4297a: cs4297a_read()+ %d \n", count)); VALIDATE_STATE(s); if (s->dma_adc.mapped) return -ENXIO; if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) return ret; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; ret = 0;//// "count" is the amount of bytes to read (from app), is decremented each loop// by the amount of bytes that have been returned to the user buffer.// "cnt" is the running total of each read from the buffer (changes each loop)// "buffer" points to the app's buffer// "ret" keeps a running total of the amount of bytes that have been copied// to the user buffer.// "copied" is the total bytes copied into the user buffer for each loop.// while (count > 0) { CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO "_read() count>0 count=%d .count=%d .swptr=%d .hwptr=%d \n", count, s->dma_adc.count, s->dma_adc.swptr, s->dma_adc.hwptr)); spin_lock_irqsave(&s->lock, flags); /* cnt will be the number of available samples (16-bit stereo); it starts out as the maxmimum consequetive samples */ cnt = (s->dma_adc.sb_end - s->dma_adc.sb_swptr) / 2; count_fr = s->dma_adc.count / FRAME_SAMPLE_BYTES; // dma_adc.count is the current total bytes that have not been read. // if the amount of unread bytes from the current sw pointer to the // end of the buffer is greater than the current total bytes that // have not been read, then set the "cnt" (unread bytes) to the // amount of unread bytes. if (count_fr < cnt) cnt = count_fr; cnt_by = cnt * FRAME_SAMPLE_BYTES; spin_unlock_irqrestore(&s->lock, flags); // // if we are converting from 8/16 then we need to copy // twice the number of 16 bit bytes then 8 bit bytes. // if (s->conversion) { if (cnt_by > (count * 2)) { cnt = (count * 2) / FRAME_SAMPLE_BYTES; cnt_by = count * 2; } } else { if (cnt_by > count) { cnt = count / FRAME_SAMPLE_BYTES; cnt_by = count; } } // // "cnt" NOW is the smaller of the amount that will be read, // and the amount that is requested in this read (or partial). // if there are no bytes in the buffer to read, then start the // ADC and wait for the interrupt handler to wake us up. // if (cnt <= 0) { // start up the dma engine and then continue back to the top of // the loop when wake up occurs. start_adc(s); if (file->f_flags & O_NONBLOCK) return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->dma_adc.wait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; continue; } // there are bytes in the buffer to read. // copy from the hw buffer over to the user buffer. // user buffer is designated by "buffer" // virtual address to copy from is dma_buf+swptr // the "cnt" is the number of bytes to read. CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO "_read() copy_to cnt=%d count=%d ", cnt_by, count)); CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO " .sbufsz=%d .count=%d buffer=0x%.8x ret=%d\n", s->dma_adc.sbufsz, s->dma_adc.count, (unsigned) buffer, ret)); if (copy_to_user (buffer, ((void *)s->dma_adc.sb_swptr), cnt_by)) return ret ? ret : -EFAULT; copied = cnt_by; /* Return the descriptors */ spin_lock_irqsave(&s->lock, flags); CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4297a: upd_rcv sw->hw %x/%x\n", s->dma_adc.swptr, s->dma_adc.hwptr)); s->dma_adc.count -= cnt_by; s->dma_adc.sb_swptr += cnt * 2; if (s->dma_adc.sb_swptr == s->dma_adc.sb_end) s->dma_adc.sb_swptr = s->dma_adc.sample_buf; spin_unlock_irqrestore(&s->lock, flags); count -= copied; buffer += copied; ret += copied; start_adc(s); } CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2, printk(KERN_INFO "cs4297a: cs4297a_read()- %d\n", ret)); return ret;}static ssize_t cs4297a_write(struct file *file, const char *buffer, size_t count, loff_t * ppos){ struct cs4297a_state *s = (struct cs4297a_state *) file->private_data; ssize_t ret; unsigned long flags; unsigned swptr, hwptr; int cnt; CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2, printk(KERN_INFO "cs4297a: cs4297a_write()+ count=%d\n", count)); VALIDATE_STATE(s); if (s->dma_dac.mapped) return -ENXIO; if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; ret = 0; while (count > 0) { serdma_t *d = &s->dma_dac; int copy_cnt; u32 *s_tmpl; u32 *t_tmpl; u32 left, right; int swap = (s->prop_dac.fmt == AFMT_S16_LE) || (s->prop_dac.fmt == AFMT_U16_LE); /* XXXXXX this is broken for BLOAT_FACTOR */ spin_lock_irqsave(&s->lock, flags); if (d->count < 0) { d->count = 0; d->swptr = d->hwptr; } if (d->underrun) { d->underrun = 0; hwptr = (unsigned) (((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) - d->descrtab_phys) / sizeof(serdma_descr_t)); d->swptr = d->hwptr = hwptr; } swptr = d->swptr; cnt = d->sbufsz - (swptr * FRAME_SAMPLE_BYTES); /* Will this write fill up the buffer? */ if (d->count + cnt > d->sbufsz) cnt = d->sbufsz - d->count; spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { start_dac(s); if (file->f_flags & O_NONBLOCK) return ret ? ret : -EAGAIN; interruptible_sleep_on(&d->wait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; continue; } if (copy_from_user(d->sample_buf, buffer, cnt)) return ret ? ret : -EFAULT; copy_cnt = cnt; s_tmpl = (u32 *)d->sample_buf; t_tmpl = (u32 *)(d->dma_buf + (swptr * 4)); /* XXXKW assuming 16-bit stereo! */ do { u32 tmp; t_tmpl[0] = cpu_to_be32(0x98000000); tmp = be32_to_cpu(s_tmpl[0]); left = tmp & 0xffff; right = tmp >> 16; if (swap) { left = swab16(left); right = swab16(right); } t_tmpl[1] = cpu_to_be32(left >> 8); t_tmpl[2] = cpu_to_be32(((left & 0xff) << 24) | (right << 4)); s_tmpl++; t_tmpl += 8; copy_cnt -= 4; } while (copy_cnt); /* Mux in any pending read/write accesses */ if (s->reg_request) { *(u64 *)(d->dma_buf + (swptr * 4)) |= cpu_to_be64(s->reg_request); s->reg_request = 0; wake_up(&s->dma_dac.reg_wait); } CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO "cs4297a: copy in %d to swptr %x\n", cnt, swptr)); swptr = (swptr + (cnt/FRAME_SAMPLE_BYTES)) % d->ringsz; __raw_writeq(cnt/FRAME_SAMPLE_BYTES, SS_CSR(R_SER_DMA_DSCR_COUNT_TX)); spin_lock_irqsave(&s->lock, flags); d->swptr = swptr; d->count += cnt; d->endcleared = 0; spin_unlock_irqrestore(&s->lock, flags); count -= cnt; buffer += cnt; ret += cnt; start_dac(s); } CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2, printk(KERN_INFO "cs4297a: cs4297a_write()- %d\n", ret)); return ret;}static unsigned int cs4297a_poll(struct file *file, struct poll_table_struct *wait){ struct cs4297a_state *s = (struct cs4297a_state *) file->private_data; unsigned long flags; unsigned int mask = 0; CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, printk(KERN_INFO "cs4297a: cs4297a_poll()+\n")); VALIDATE_STATE(s); if (file->f_mode & FMODE_WRITE) { CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, printk(KERN_INFO "cs4297a: cs4297a_poll() wait on FMODE_WRITE\n")); if(!s->dma_dac.ready && prog_dmabuf_dac(s)) return 0; poll_wait(file, &s->dma_dac.wait, wait); } if (file->f_mode & FMODE_READ) { CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, printk(KERN_INFO "cs4297a: cs4297a_poll() wait on FMODE_READ\n")); if(!s->dma_dac.ready && prog_dmabuf_adc(s)) return 0; poll_wait(file, &s->dma_adc.wait, wait); } spin_lock_irqsave(&s->lock, flags); cs4297a_update_ptr(s,CS_FALSE); if (file->f_mode & FMODE_WRITE) { if (s->dma_dac.mapped) { if (s->dma_dac.count >= (signed) s->dma_dac.fragsize) { if (s->dma_dac.wakeup) mask |= POLLOUT | POLLWRNORM; else mask = 0; s->dma_dac.wakeup = 0; } } else { if ((signed) (s->dma_dac.sbufsz/2) >= s->dma_dac.count) mask |= POLLOUT | POLLWRNORM; } } else if (file->f_mode & FMODE_READ) { if (s->dma_adc.mapped) { if (s->dma_adc.count >= (signed) s->dma_adc.fragsize) mask |= POLLIN | POLLRDNORM; } else { if (s->dma_adc.count > 0) mask |= POLLIN | POLLRDNORM; } } spin_unlock_irqrestore(&s->lock, flags); CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, printk(KERN_INFO "cs4297a: cs4297a_poll()- 0x%.8x\n", mask)); return mask;}static int cs4297a_mmap(struct file *file, struct vm_area_struct *vma){ /* XXXKW currently no mmap support */ return -EINVAL; return 0;}static int cs4297a_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct cs4297a_state *s = (struct cs4297a_state *) file->private_data; unsigned long flags; audio_buf_info abinfo; count_info cinfo; int val, mapped, ret; CS_DBGOUT(CS_FUNCTION|CS_IOCTL, 4, printk(KERN_INFO "cs4297a: cs4297a_ioctl(): file=0x%.8x cmd=0x%.8x\n", (unsigned) file, cmd));#if CSDEBUG cs_printioctl(cmd);#endif VALIDATE_STATE(s); mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); switch (cmd) { case OSS_GETVERSION: CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?