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

📄 amdtp.c

📁 这个是uClinux下的ieee1394驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
	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 + -