📄 amdtp.c
字号:
list_for_each_safe(lh, next, &s->free_packet_lists) packet_list_free(list_entry(lh, struct packet_list, link), s); if (s->packet_pool != NULL) pci_pool_destroy(s->packet_pool); s->current_packet_list = NULL; INIT_LIST_HEAD(&s->free_packet_lists); INIT_LIST_HEAD(&s->dma_packet_lists); s->packet_pool = NULL;}static void plug_update(struct cmp_pcr *plug, void *data){ struct stream *s = data; HPSB_INFO("plug update: p2p_count=%d, channel=%d", plug->p2p_count, plug->channel); s->iso_channel = plug->channel; if (plug->p2p_count > 0) { struct packet_list *pl; pl = list_entry(s->dma_packet_lists.next, struct packet_list, link); stream_start_dma(s, pl); } else { ohci1394_stop_it_ctx(s->host->ohci, s->iso_tasklet.context, 0); }}static int stream_configure(struct stream *s, int cmd, struct amdtp_ioctl *cfg){ const int transfer_delay = 9000; if (cfg->format <= AMDTP_FORMAT_IEC958_AC3) s->format = cfg->format; else return -EINVAL; switch (cfg->rate) { case 32000: s->syt_interval = 8; s->fdf = FDF_SFC_32KHZ; s->iec958_rate_code = 0x0c; break; case 44100: s->syt_interval = 8; s->fdf = FDF_SFC_44K1HZ; s->iec958_rate_code = 0x00; break; case 48000: s->syt_interval = 8; s->fdf = FDF_SFC_48KHZ; s->iec958_rate_code = 0x04; break; case 88200: s->syt_interval = 16; s->fdf = FDF_SFC_88K2HZ; s->iec958_rate_code = 0x00; break; case 96000: s->syt_interval = 16; s->fdf = FDF_SFC_96KHZ; s->iec958_rate_code = 0x00; break; case 176400: s->syt_interval = 32; s->fdf = FDF_SFC_176K4HZ; s->iec958_rate_code = 0x00; break; case 192000: s->syt_interval = 32; s->fdf = FDF_SFC_192KHZ; s->iec958_rate_code = 0x00; break; default: return -EINVAL; } s->rate = cfg->rate; fraction_init(&s->samples_per_cycle, s->rate, 8000); fraction_init(&s->ready_samples, 0, 8000); /* The ticks_per_syt_offset is initialized to the number of * ticks between syt_interval events. The number of ticks per * second is 24.576e6, so the number of ticks between * syt_interval events is 24.576e6 * syt_interval / rate. */ fraction_init(&s->ticks_per_syt_offset, 24576000 * s->syt_interval, s->rate); fraction_init(&s->cycle_offset, (transfer_delay % 3072) * s->rate, s->rate); atomic_set(&s->cycle_count, transfer_delay / 3072); atomic_set(&s->cycle_count2, 0); s->mode = cfg->mode; s->sample_format = AMDTP_INPUT_LE16; /* When using the AM824 raw subformat we can stream signals of * any dimension. The IEC958 subformat, however, only * supports 2 channels. */ if (s->format == AMDTP_FORMAT_RAW || cfg->dimension == 2) s->dimension = cfg->dimension; else return -EINVAL; if (s->opcr != NULL) { cmp_unregister_opcr(s->host->host, s->opcr); s->opcr = NULL; } switch(cmd) { case AMDTP_IOC_PLUG: s->opcr = cmp_register_opcr(s->host->host, cfg->u.plug, /*payload*/ 12, plug_update, s); if (s->opcr == NULL) return -EINVAL; s->iso_channel = s->opcr->channel; break; case AMDTP_IOC_CHANNEL: if (cfg->u.channel >= 0 && cfg->u.channel < 64) s->iso_channel = cfg->u.channel; else return -EINVAL; break; } /* The ioctl settings were all valid, so we realloc the packet * lists to make sure the packet size is big enough. */ if (s->packet_pool != NULL) stream_free_packet_lists(s); if (stream_alloc_packet_lists(s) < 0) { stream_free_packet_lists(s); return -ENOMEM; } return 0;}struct stream *stream_alloc(struct amdtp_host *host){ struct stream *s; unsigned long flags; s = kmalloc(sizeof(struct stream), SLAB_KERNEL); if (s == NULL) return NULL; memset(s, 0, sizeof(struct stream)); s->host = host; s->input = buffer_alloc(BUFFER_SIZE); if (s->input == NULL) { kfree(s); return NULL; } s->descriptor_pool = pci_pool_create("descriptor pool", host->ohci->dev, sizeof(struct descriptor_block), 16, 0, SLAB_KERNEL); if (s->descriptor_pool == NULL) { kfree(s->input); kfree(s); return NULL; } INIT_LIST_HEAD(&s->free_packet_lists); INIT_LIST_HEAD(&s->dma_packet_lists); init_waitqueue_head(&s->packet_list_wait); spin_lock_init(&s->packet_list_lock); ohci1394_init_iso_tasklet(&s->iso_tasklet, OHCI_ISO_TRANSMIT, stream_shift_packet_lists, (unsigned long) s); if (ohci1394_register_iso_tasklet(host->ohci, &s->iso_tasklet) < 0) { pci_pool_destroy(s->descriptor_pool); kfree(s->input); kfree(s); return NULL; } spin_lock_irqsave(&host->stream_list_lock, flags); list_add_tail(&s->link, &host->stream_list); spin_unlock_irqrestore(&host->stream_list_lock, flags); return s;}void stream_free(struct stream *s){ unsigned long flags; /* Stop the DMA. We wait for the dma packet list to become * empty and let the dma controller run out of programs. This * seems to be more reliable than stopping it directly, since * that sometimes generates an it transmit interrupt if we * later re-enable the context. */ wait_event_interruptible(s->packet_list_wait, list_empty(&s->dma_packet_lists)); ohci1394_stop_it_ctx(s->host->ohci, s->iso_tasklet.context, 1); ohci1394_unregister_iso_tasklet(s->host->ohci, &s->iso_tasklet); if (s->opcr != NULL) cmp_unregister_opcr(s->host->host, s->opcr); spin_lock_irqsave(&s->host->stream_list_lock, flags); list_del(&s->link); spin_unlock_irqrestore(&s->host->stream_list_lock, flags); kfree(s->input); stream_free_packet_lists(s); pci_pool_destroy(s->descriptor_pool); kfree(s);}/* File operations */static ssize_t amdtp_write(struct file *file, const char *buffer, size_t count, loff_t *offset_is_ignored){ struct stream *s = file->private_data; unsigned char *p; int i; size_t length; if (s->packet_pool == NULL) return -EBADFD; /* Fill the circular buffer from the input buffer and call the * iso packer when the buffer is full. The iso packer may * leave bytes in the buffer for two reasons: either the * remaining bytes wasn't enough to build a new packet, or * there were no free packet lists. In the first case we * re-fill the buffer and call the iso packer again or return * if we used all the data from userspace. In the second * case, the wait_event_interruptible will block until the irq * handler frees a packet list. */ for (i = 0; i < count; i += length) { p = buffer_put_bytes(s->input, count, &length); copy_from_user(p, buffer + i, length); if (s->input->length < s->input->size) continue; stream_flush(s); if (s->current_packet_list != NULL) continue; if (file->f_flags & O_NONBLOCK) return i + length > 0 ? i + length : -EAGAIN; if (wait_event_interruptible(s->packet_list_wait, !list_empty(&s->free_packet_lists))) return -EINTR; } return count;}static int amdtp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct stream *s = file->private_data; struct amdtp_ioctl cfg; switch(cmd) { case AMDTP_IOC_PLUG: case AMDTP_IOC_CHANNEL: if (copy_from_user(&cfg, (struct amdtp_ioctl *) arg, sizeof cfg)) return -EFAULT; else return stream_configure(s, cmd, &cfg); default: return -EINVAL; }}static unsigned int amdtp_poll(struct file *file, poll_table *pt){ struct stream *s = file->private_data; poll_wait(file, &s->packet_list_wait, pt); if (!list_empty(&s->free_packet_lists)) return POLLOUT | POLLWRNORM; else return 0;}static int amdtp_open(struct inode *inode, struct file *file){ struct amdtp_host *host; /* FIXME: We just grab the first registered host */ spin_lock(&host_list_lock); if (!list_empty(&host_list)) host = list_entry(host_list.next, struct amdtp_host, link); else host = NULL; spin_unlock(&host_list_lock); if (host == NULL) return -ENODEV; file->private_data = stream_alloc(host); if (file->private_data == NULL) return -ENOMEM; return 0;}static int amdtp_release(struct inode *inode, struct file *file){ struct stream *s = file->private_data; stream_free(s); return 0;}static struct file_operations amdtp_fops ={ .owner = THIS_MODULE, .write = amdtp_write, .poll = amdtp_poll, .ioctl = amdtp_ioctl, .open = amdtp_open, .release = amdtp_release};/* IEEE1394 Subsystem functions */static void amdtp_add_host(struct hpsb_host *host){ struct amdtp_host *ah; if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME) != 0) return; ah = kmalloc(sizeof *ah, SLAB_KERNEL); ah->host = host; ah->ohci = host->hostdata; INIT_LIST_HEAD(&ah->stream_list); spin_lock_init(&ah->stream_list_lock); spin_lock_irq(&host_list_lock); list_add_tail(&ah->link, &host_list); spin_unlock_irq(&host_list_lock);}static void amdtp_remove_host(struct hpsb_host *host){ struct list_head *lh; struct amdtp_host *ah; spin_lock_irq(&host_list_lock); list_for_each(lh, &host_list) { if (list_entry(lh, struct amdtp_host, link)->host == host) { list_del(lh); break; } } spin_unlock_irq(&host_list_lock); if (lh != &host_list) { ah = list_entry(lh, struct amdtp_host, link); kfree(ah); } else HPSB_ERR("remove_host: bogus ohci host: %p", host);}static struct hpsb_highlevel_ops amdtp_highlevel_ops = { .add_host = amdtp_add_host, .remove_host = amdtp_remove_host,};/* Module interface */MODULE_AUTHOR("Kristian Hogsberg <hogsberg@users.sf.net>");MODULE_DESCRIPTION("Driver for Audio & Music Data Transmission Protocol " "on OHCI boards.");MODULE_SUPPORTED_DEVICE("amdtp");MODULE_LICENSE("GPL");static int __init amdtp_init_module (void){ if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_AMDTP, THIS_MODULE, &amdtp_fops)) { HPSB_ERR("amdtp: unable to get minor device block"); return -EIO; } amdtp_highlevel = hpsb_register_highlevel ("amdtp", &amdtp_highlevel_ops); if (amdtp_highlevel == NULL) { HPSB_ERR("amdtp: unable to register highlevel ops"); ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP); return -EIO; } HPSB_INFO("Loaded AMDTP driver"); return 0;}static void __exit amdtp_exit_module (void){ hpsb_unregister_highlevel(amdtp_highlevel); ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP); HPSB_INFO("Unloaded AMDTP driver");}module_init(amdtp_init_module);module_exit(amdtp_exit_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -