static void audio_prime_dma(audio_stream_t *s) { int i; s->active = 1; for (i = 0; i < s->nbfrags; i++) { audio_buf_t *b = s->buf; down(&b->sem); sa1100_dma_queue_buffer(s->dma_ch, (void *) b, b->dma_addr, s->fragsize); NEXT_BUF(s, buf); } }
static void audio_dmaout_done_callback(void *buf_id, int size) { audio_buf_t *b = (audio_buf_t *) buf_id; audio_stream_t *s = b->stream; /* Accounting */ s->bytecount += size; s->fragcount++; /* Recycle buffer */ if (s->mapped) sa1100_dma_queue_buffer(s->dma_ch, buf_id, b->dma_addr, s->fragsize); else up(&b->sem); /* And any process polling on write. */ wake_up(&s->wq); }
/* * We want to get here as soon as possible, and get the receiver setup. * We use the existing buffer. */ static void sa1100_irda_rx_dma_start(struct sa1100_irda *si) { if (!si->rxskb) { printk(KERN_ERR "sa1100_ir: rx buffer went missing\n"); return; } /* * First empty receive FIFO */ Ser2HSCR0 = si->hscr0 | HSCR0_HSSP; /* * Enable the DMA, receiver and recieve interrupt. */ sa1100_dma_flush_all(si->rxdma); sa1100_dma_queue_buffer(si->rxdma, NULL, si->rxbuf_dma, HPSIR_MAX_RXLEN); Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_RXE; }
static int audio_sync(struct file *file) { audio_state_t *state = (audio_state_t *)file->private_data; audio_stream_t *s = state->output_stream; audio_buf_t *b; DPRINTK("audio_sync\n"); if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped) return 0; /* * Send current buffer if it contains data. Be sure to send * a full sample count. */ b = s->buf; if (b->size &= ~3) { down(&b->sem); sa1100_dma_queue_buffer(s->dma_ch, (void *) b, b->dma_addr, b->size); b->size = 0; NEXT_BUF(s, buf); } /* * Let's wait for the last buffer we sent i.e. the one before the * current buf_idx. When we acquire the semaphore, this means either: * - DMA on the buffer completed or * - the buffer was already free thus nothing else to sync. */ b = s->buffers + ((s->nbfrags + s->buf_idx - 1) % s->nbfrags); if (down_interruptible(&b->sem)) return -EINTR; up(&b->sem); return 0; }
static int audio_read(struct file *file, char *buffer, size_t count, loff_t * ppos) { char *buffer0 = buffer; audio_state_t *state = (audio_state_t *)file->private_data; audio_stream_t *s = state->input_stream; int chunksize, ret = 0; DPRINTK("audio_read: count=%d\n", count); if (ppos != &file->f_pos) return -ESPIPE; if (s->mapped) return -ENXIO; if (!s->active) { if (!s->buffers && audio_setup_buf(s)) return -ENOMEM; audio_check_tx_spin(state); audio_prime_dma(s); } while (count > 0) { audio_buf_t *b = s->buf; /* Wait for a buffer to become full */ if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; if (down_trylock(&b->sem)) break; } else { ret = -ERESTARTSYS; if (down_interruptible(&b->sem)) break; } /* Grab data from the current buffer */ chunksize = b->size; if (chunksize > count) chunksize = count; DPRINTK("read %d from %d\n", chunksize, s->buf_idx); if (copy_to_user(buffer, b->start + s->fragsize - b->size, chunksize)) { up(&b->sem); return -EFAULT; } b->size -= chunksize; buffer += chunksize; count -= chunksize; if (b->size > 0) { up(&b->sem); break; } /* Make current buffer available for DMA again */ sa1100_dma_queue_buffer(s->dma_ch, (void *) b, b->dma_addr, s->fragsize); NEXT_BUF(s, buf); } if ((buffer - buffer0)) ret = buffer - buffer0; DPRINTK("audio_read: return=%d\n", ret); return ret; }
static int audio_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) { const char *buffer0 = buffer; audio_state_t *state = (audio_state_t *)file->private_data; audio_stream_t *s = state->output_stream; int chunksize, ret = 0; DPRINTK("audio_write: count=%d\n", count); if (ppos != &file->f_pos) return -ESPIPE; if (s->mapped) return -ENXIO; if (!s->buffers && audio_setup_buf(s)) return -ENOMEM; while (count > 0) { audio_buf_t *b = s->buf; /* Wait for a buffer to become free */ if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; if (down_trylock(&b->sem)) break; } else { ret = -ERESTARTSYS; if (down_interruptible(&b->sem)) break; } /* Feed the current buffer */ chunksize = s->fragsize - b->size; if (chunksize > count) chunksize = count; DPRINTK("write %d to %d\n", chunksize, s->buf_idx); if (copy_from_user(b->start + b->size, buffer, chunksize)) { up(&b->sem); return -EFAULT; } b->size += chunksize; buffer += chunksize; count -= chunksize; if (b->size < s->fragsize) { up(&b->sem); break; } /* Send current buffer to dma */ s->active = 1; sa1100_dma_queue_buffer(s->dma_ch, (void *) b, b->dma_addr, b->size); b->size = 0; /* indicate that the buffer has been sent */ NEXT_BUF(s, buf); } if ((buffer - buffer0)) ret = buffer - buffer0; DPRINTK("audio_write: return=%d\n", ret); return ret; }
/* * Note that we will never build up a backlog of frames; the protocol is a * half duplex protocol which basically means we transmit a frame, we * receive a frame, we transmit the next frame etc. */ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) { struct sa1100_irda *si = dev->priv; int speed = irda_get_next_speed(skb); /* * Does this packet contain a request to change the interface * speed? If so, remember it until we complete the transmission * of this frame. */ if (speed != si->speed && speed != -1) si->newspeed = speed; /* * If this is an empty frame, we can bypass a lot. */ if (skb->len == 0) { if (si->newspeed) { si->newspeed = 0; sa1100_irda_set_speed(si, speed); } dev_kfree_skb(skb); return 0; } if (!IS_FIR(si)) { si->tx_buff.data = si->tx_buff.head; si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, si->tx_buff.truesize); /* * Set the transmit interrupt enable. This will fire * off an interrupt immediately. Note that we disable * the receiver so we won't get spurious characteres * received. */ Ser2UTCR3 = UTCR3_TIE | UTCR3_TXE; dev_kfree_skb(skb); } else { int mtt = irda_get_mtt(skb); /* * We must not be transmitting... */ if (si->txskb) BUG(); netif_stop_queue(dev); si->txskb = skb; si->txbuf_dma = pci_map_single(NULL, skb->data, skb->len, PCI_DMA_TODEVICE); sa1100_dma_queue_buffer(si->txdma, dev, si->txbuf_dma, skb->len); /* * If we have a mean turn-around time, impose the specified * specified delay. We could shorten this by timing from * the point we received the packet. */ if (mtt) udelay(mtt); Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_TXE; } dev->trans_start = jiffies; return 0; }