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

📄 video1394.c

📁 1394在linux下单独的驱动程序代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	}		/* reset the ctrl register */	reg_write(ohci, d->ctrlClear, 0xf0000000);		/* Set bufferFill */	reg_write(ohci, d->ctrlSet, 0x80000000);				//see pdf_doc,p138		/* Set isoch header */	if (flags & VIDEO1394_INCLUDE_ISO_HEADERS) 		reg_write(ohci, d->ctrlSet, 0x40000000);			/* Set the context match register to match on all tags, 	   sync for sync tag, and listen to d->channel */	reg_write(ohci, d->ctxMatch, 0xf0000000|((tag&0xf)<<8)|d->channel);		/* Set up isoRecvIntMask to generate interrupts */	reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1<<d->ctx);}/* find which context is listening to this channel */static struct dma_iso_ctx *find_ctx(struct list_head *list, int type, int channel){	struct list_head *lh;		list_for_each(lh, list) {		struct dma_iso_ctx *ctx;		ctx = list_entry(lh, struct dma_iso_ctx, link);		if (ctx->type == type && ctx->channel == channel)			return ctx;	}		return NULL;}void wakeup_dma_ir_ctx(unsigned long l){	struct dma_iso_ctx *d = (struct dma_iso_ctx *) l;	int i;		spin_lock(&d->lock);		for (i = 0; i < d->num_desc; i++) {		if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) {			reset_ir_status(d, i);			d->buffer_status[i] = VIDEO1394_BUFFER_READY;			do_gettimeofday(&d->buffer_time[i]);		}	}		spin_unlock(&d->lock);		if (waitqueue_active(&d->waitq))		wake_up_interruptible(&d->waitq);}static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d,								 int n){	unsigned char* buf = d->dma.kvirt + n * d->buf_size;	u32 cycleTimer;	u32 timeStamp;		if (n == -1) {		return;	}		cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);		timeStamp = ((cycleTimer & 0x0fff) + d->syt_offset); /* 11059 = 450 us */	timeStamp = (timeStamp % 3072 + ((timeStamp / 3072) << 12)		+ (cycleTimer & 0xf000)) & 0xffff;		buf[6] = timeStamp >> 8; 	buf[7] = timeStamp & 0xff; 	    /* if first packet is empty packet, then put timestamp into the next full one too */    if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) {   	    buf += d->packet_size;		buf[6] = timeStamp >> 8;		buf[7] = timeStamp & 0xff;	}	    /* do the next buffer frame too in case of irq latency */	n = d->next_buffer[n];	if (n == -1) {		return;	}	buf = d->dma.kvirt + n * d->buf_size;		timeStamp += (d->last_used_cmd[n] << 12) & 0xffff;		buf[6] = timeStamp >> 8;	buf[7] = timeStamp & 0xff;	    /* if first packet is empty packet, then put timestamp into the next full one too */    if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) {   	    buf += d->packet_size;		buf[6] = timeStamp >> 8;		buf[7] = timeStamp & 0xff;	}	#if 0	printk("curr: %d, next: %d, cycleTimer: %08x timeStamp: %08x\n",	       curr, n, cycleTimer, timeStamp);#endif	}void wakeup_dma_it_ctx(unsigned long l){	struct dma_iso_ctx *d = (struct dma_iso_ctx *) l;	struct ti_ohci *ohci = d->ohci;	int i;		spin_lock(&d->lock);		for (i = 0; i < d->num_desc; i++) {		if (d->it_prg[i][d->last_used_cmd[i]].end.status & 			cpu_to_le32(0xFFFF0000)) {			int next = d->next_buffer[i];			put_timestamp(ohci, d, next);			d->it_prg[i][d->last_used_cmd[i]].end.status = 0;			d->buffer_status[i] = VIDEO1394_BUFFER_READY;		}	}		spin_unlock(&d->lock);		if (waitqueue_active(&d->waitq))		wake_up_interruptible(&d->waitq);}static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag){	struct it_dma_prg *it_prg = d->it_prg[n];	struct dma_prog_region *it_reg = &d->prg_reg[n];	unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size;	int i;	d->last_used_cmd[n] = d->nb_cmd - 1;	for (i=0;i<d->nb_cmd;i++) {				it_prg[i].begin.control = cpu_to_le32(DMA_CTL_OUTPUT_MORE |			DMA_CTL_IMMEDIATE | 8) ;		it_prg[i].begin.address = 0;				it_prg[i].begin.status = 0;				it_prg[i].data[0] = cpu_to_le32(			(IEEE1394_SPEED_100 << 16) 			| (/* tag */ 1 << 14)			| (d->channel << 8) 			| (TCODE_ISO_DATA << 4));		if (i==0) it_prg[i].data[0] |= cpu_to_le32(sync_tag);		it_prg[i].data[1] = cpu_to_le32(d->packet_size << 16);		it_prg[i].data[2] = 0;		it_prg[i].data[3] = 0;				it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST |			DMA_CTL_BRANCH);		it_prg[i].end.address =			cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf+i*d->packet_size) -			(unsigned long)d->dma.kvirt));				if (i<d->nb_cmd-1) {			it_prg[i].end.control |= cpu_to_le32(d->packet_size);			it_prg[i].begin.branchAddress = 				cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *				sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);			it_prg[i].end.branchAddress = 				cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *				sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);		} else {			/* the last prg generates an interrupt */			it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE | 				DMA_CTL_IRQ | d->left_size);			/* the last prg doesn't branch */			it_prg[i].begin.branchAddress = 0;			it_prg[i].end.branchAddress = 0;		}		it_prg[i].end.status = 0;	}}static void initialize_dma_it_prg_var_packet_queue(												   struct dma_iso_ctx *d, int n, unsigned int * packet_sizes,												   struct ti_ohci *ohci){	struct it_dma_prg *it_prg = d->it_prg[n];	struct dma_prog_region *it_reg = &d->prg_reg[n];	int i;	#if 0	if (n != -1) {		put_timestamp(ohci, d, n);	}#endif	d->last_used_cmd[n] = d->nb_cmd - 1;		for (i = 0; i < d->nb_cmd; i++) {		unsigned int size;		if (packet_sizes[i] > d->packet_size) {			size = d->packet_size;		} else {			size = packet_sizes[i];		}		it_prg[i].data[1] = cpu_to_le32(size << 16); 		it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH);				if (i < d->nb_cmd-1 && packet_sizes[i+1] != 0) {			it_prg[i].end.control |= cpu_to_le32(size);			it_prg[i].begin.branchAddress =				cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *				sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);			it_prg[i].end.branchAddress =				cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *				sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);		} else {			/* the last prg generates an interrupt */			it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE | 				DMA_CTL_IRQ | size);			/* the last prg doesn't branch */			it_prg[i].begin.branchAddress = 0;			it_prg[i].end.branchAddress = 0;			d->last_used_cmd[n] = i;			break;		}	}}static void initialize_dma_it_ctx(struct dma_iso_ctx *d, int sync_tag,								  unsigned int syt_offset, int flags){	struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;	int i;		d->flags = flags;	d->syt_offset = (syt_offset == 0 ? 11000 : syt_offset);		ohci1394_stop_context(ohci, d->ctrlClear, NULL);		for (i=0;i<d->num_desc;i++)		initialize_dma_it_prg(d, i, sync_tag);		/* Set up isoRecvIntMask to generate interrupts */	reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx);}static int video1394_ioctl(struct inode *inode, struct file *file,						   unsigned int cmd, unsigned long arg){	struct file_ctx *ctx = (struct file_ctx *)file->private_data;	struct video_card *video = ctx->video;	struct ti_ohci *ohci = video->ohci;	unsigned long flags;		switch(cmd)	{	case VIDEO1394_LISTEN_CHANNEL:	case VIDEO1394_TALK_CHANNEL:	case VIDEO1394_IOC_LISTEN_CHANNEL:	case VIDEO1394_IOC_TALK_CHANNEL:		{			struct video1394_mmap v;			u64 mask;			struct dma_iso_ctx *d;			int i;						if (copy_from_user(&v, (void *)arg, sizeof(v)))				return -EFAULT;						/* if channel < 0, find lowest available one */			if (v.channel < 0) {				mask = (u64)0x1;				for (i=0; i<ISO_CHANNELS; i++) {					if (!(ohci->ISO_channel_usage & mask)) {						v.channel = i;						PRINT(KERN_INFO, ohci->id, "Found free channel %d", i);						break;					}					mask = mask << 1;				}			}						if (v.channel<0 || v.channel>(ISO_CHANNELS-1)) {				PRINT(KERN_ERR, ohci->id, 					"Iso channel %d out of bounds", v.channel);				return -EFAULT;			}			mask = (u64)0x1<<v.channel;			printk("mask: %08X%08X usage: %08X%08X\n",				(u32)(mask>>32),(u32)(mask&0xffffffff),				(u32)(ohci->ISO_channel_usage>>32),				(u32)(ohci->ISO_channel_usage&0xffffffff));			if (ohci->ISO_channel_usage & mask) {				PRINT(KERN_ERR, ohci->id, 					"Channel %d is already taken", v.channel);				return -EFAULT;			}			ohci->ISO_channel_usage |= mask;						if (v.buf_size == 0 || v.buf_size > VIDEO1394_MAX_SIZE) {				PRINT(KERN_ERR, ohci->id,					"Invalid %d length buffer requested",v.buf_size);				return -EFAULT;			}						if (v.nb_buffers == 0 || v.nb_buffers > VIDEO1394_MAX_SIZE) {				PRINT(KERN_ERR, ohci->id,					"Invalid %d buffers requested",v.nb_buffers);				return -EFAULT;			}						if (v.nb_buffers * v.buf_size > VIDEO1394_MAX_SIZE) {				PRINT(KERN_ERR, ohci->id, 					"%d buffers of size %d bytes is too big", 					v.nb_buffers, v.buf_size);				return -EFAULT;			}						if (cmd == VIDEO1394_IOC_LISTEN_CHANNEL || cmd == VIDEO1394_LISTEN_CHANNEL) {				d = alloc_dma_iso_ctx(ohci, OHCI_ISO_RECEIVE,					v.nb_buffers, v.buf_size, 					v.channel, 0);								if (d == NULL) {					PRINT(KERN_ERR, ohci->id, 						"Couldn't allocate ir context");					return -EFAULT;				}				initialize_dma_ir_ctx(d, v.sync_tag, v.flags);								ctx->current_ctx = d;								v.buf_size = d->buf_size;				list_add_tail(&d->link, &ctx->context_list);								PRINT(KERN_INFO, ohci->id, 					"iso context %d listen on channel %d",					d->ctx, v.channel);			}			else {				d = alloc_dma_iso_ctx(ohci, OHCI_ISO_TRANSMIT,					v.nb_buffers, v.buf_size, 					v.channel, v.packet_size);								if (d == NULL) {					PRINT(KERN_ERR, ohci->id, 						"Couldn't allocate it context");					return -EFAULT;				}				initialize_dma_it_ctx(d, v.sync_tag, 					v.syt_offset, v.flags);								ctx->current_ctx = d;								v.buf_size = d->buf_size;								list_add_tail(&d->link, &ctx->context_list);								PRINT(KERN_INFO, ohci->id, 					"Iso context %d talk on channel %d", d->ctx,					v.channel);			}						if (copy_to_user((void *)arg, &v, sizeof(v)))				return -EFAULT;						return 0;	}	case VIDEO1394_UNLISTEN_CHANNEL:	case VIDEO1394_UNTALK_CHANNEL:	case VIDEO1394_IOC_UNLISTEN_CHANNEL: 	case VIDEO1394_IOC_UNTALK_CHANNEL:		{			int channel;			u64 mask;			struct dma_iso_ctx *d;						if (copy_from_user(&channel, (void *)arg, sizeof(int)))				return -EFAULT;						if (channel<0 || channel>(ISO_CHANNELS-1)) {				PRINT(KERN_ERR, ohci->id, 					"Iso channel %d out of bound", channel);				return -EFAULT;			}			mask = (u64)0x1<<channel;			if (!(ohci->ISO_channel_usage & mask)) {				PRINT(KERN_ERR, ohci->id, 					"Channel %d is not being used", channel);				return -EFAULT;			}						/* Mark this channel as unused */			ohci->ISO_channel_usage &= ~mask;						if (cmd == VIDEO1394_IOC_UNLISTEN_CHANNEL || cmd == VIDEO1394_UNLISTEN_CHANNEL)				d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, channel);			else				d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, channel);						if (d == NULL) return -EFAULT;			PRINT(KERN_INFO, ohci->id, "Iso context %d "				"stop talking on channel %d", d->ctx, channel);			free_dma_iso_ctx(d);						return 0;		}	case VIDEO1394_LISTEN_QUEUE_BUFFER:	case VIDEO1394_IOC_LISTEN_QUEUE_BUFFER:		{			struct video1394_wait v;			struct dma_iso_ctx *d;						if (copy_from_user(&v, (void *)arg, sizeof(v)))				return -EFAULT;						d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);						if ((v.buffer<0) || (v.buffer>d->num_desc)) {				PRINT(KERN_ERR, ohci->id, 					"Buffer %d out of range",v.buffer);				return -EFAULT;			}						spin_lock_irqsave(&d->lock,flags);						if (d->buffer_status[v.buffer]==VIDEO1394_BUFFER_QUEUED) {				PRINT(KERN_ERR, ohci->id, 					"Buffer %d is already used",v.buffer);				spin_unlock_irqrestore(&d->lock,flags);				return -EFAULT;			}						d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;						if (d->last_buffer>=0)				d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress =				cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0)				& 0xfffffff0) | 0x1);						d->last_buffer = v.buffer;						d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = 0;						spin_unlock_irqrestore(&d->lock,flags);						if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) 			{				DBGMSG(ohci->id, "Starting iso DMA ctx=%d",d->ctx);								/* Tell the controller where the first program is */				reg_write(ohci, d->cmdPtr,					dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0) | 0x1);								/* Run IR context */				reg_write(ohci, d->ctrlSet, 0x8000);			}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -