⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 amdtp.c

📁 IEE1394 火线接口驱动 for linux
💻 C
📖 第 1 页 / 共 3 页
字号:
		packet_list_free(s->current_packet_list, s);	list_for_each_safe(lh, next, &s->dma_packet_lists)		packet_list_free(list_entry(lh, struct packet_list, link), s);	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 - i, &length);		if (copy_from_user(p, buffer + i, length))			return -EFAULT;		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;	int i = ieee1394_file_to_instance(file);	host = hpsb_get_hostinfo_bykey(&amdtp_highlevel, i);	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;	int minor;	char name[16];	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME) != 0)		return;	ah = hpsb_create_hostinfo(&amdtp_highlevel, host, sizeof(*ah));	if (!ah) {		HPSB_ERR("amdtp: Unable able to alloc hostinfo");		return;	}	ah->host = host;	ah->ohci = host->hostdata;	hpsb_set_hostinfo_key(&amdtp_highlevel, host, ah->ohci->id);	minor = IEEE1394_MINOR_BLOCK_AMDTP * 16 + ah->ohci->id;	sprintf(name, "%d", ah->ohci->id);	INIT_LIST_HEAD(&ah->stream_list);	spin_lock_init(&ah->stream_list_lock);	ah->devfs = devfs_register(devfs_handle, name,				   DEVFS_FL_AUTO_OWNER,				   IEEE1394_MAJOR, minor,				   S_IFCHR | S_IRUSR | S_IWUSR,				   &amdtp_fops, NULL);}static void amdtp_remove_host(struct hpsb_host *host){	struct amdtp_host *ah = hpsb_get_hostinfo(&amdtp_highlevel, host);	if (ah)		devfs_unregister(ah->devfs);	return;}static struct hpsb_highlevel amdtp_highlevel = {	.name =		"amdtp",	.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; 	}	devfs_handle = devfs_mk_dir(NULL, "amdtp", NULL);	hpsb_register_highlevel(&amdtp_highlevel);	HPSB_INFO("Loaded AMDTP driver");	return 0;}static void __exit amdtp_exit_module (void){        hpsb_unregister_highlevel(&amdtp_highlevel);	devfs_unregister(devfs_handle);        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 + -