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

📄 video1394.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* set the sync flag */	if (flags & VIDEO1394_SYNC_FRAMES)		ir_prg[0].control |= 0x00030000;	ir_prg[0].address = kvirt_to_bus(buf);	ir_prg[0].branchAddress =  (virt_to_bus(&(ir_prg[1].control)) 				    & 0xfffffff0) | 0x1;	/* the second descriptor will read PAGE_SIZE-4 bytes */	ir_prg[1].control = (0x280C << 16) | (PAGE_SIZE-4);	ir_prg[1].address = kvirt_to_bus(buf+4);	ir_prg[1].branchAddress =  (virt_to_bus(&(ir_prg[2].control)) 				    & 0xfffffff0) | 0x1;		for (i=2;i<d->nb_cmd-1;i++) {		ir_prg[i].control = (0x280C << 16) | PAGE_SIZE;		ir_prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE);		ir_prg[i].branchAddress =  			(virt_to_bus(&(ir_prg[i+1].control)) 			 & 0xfffffff0) | 0x1;	}	/* the last descriptor will generate an interrupt */	ir_prg[i].control = (0x283C << 16) | d->left_size;	ir_prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE);}	static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag, int flags){	struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;	int i;	ohci1394_stop_context(ohci, d->ctrlClear, NULL);	for (i=0;i<d->num_desc;i++) {		initialize_dma_ir_prg(d, i, flags);		reset_ir_status(d, i);	}	/* reset the ctrl register */	reg_write(ohci, d->ctrlClear, 0xf0000000);	/* Set bufferFill */	reg_write(ohci, d->ctrlSet, 0x80000000);	/* 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 */int ir_ctx_listening(struct video_card *video, int channel){	int i;	struct ti_ohci *ohci = video->ohci;	for (i=0;i<ohci->nb_iso_rcv_ctx-1;i++) 		if (video->ir_context[i]) {			if (video->ir_context[i]->channel==channel)				return i;		}			PRINT(KERN_ERR, ohci->id, 	      "no iso context is listening to channel %d",	      channel);	return -1;}int it_ctx_talking(struct video_card *video, int channel){	int i;	struct ti_ohci *ohci = video->ohci;	for (i=0;i<ohci->nb_iso_xmit_ctx;i++) 		if (video->it_context[i]) {			if (video->it_context[i]->channel==channel)				return i;		}			PRINT(KERN_ERR, ohci->id, 	      "no iso context is talking to channel %d",	      channel);	return -1;}int wakeup_dma_ir_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d) {	int i;	if (d==NULL) {		PRINT(KERN_ERR, ohci->id, "Iso receive event received but "		      "context not allocated");		return -EFAULT;	}	spin_lock(&d->lock);	for (i=0;i<d->num_desc;i++) {		if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) {			reset_ir_status(d, i);			d->buffer_status[i] = VIDEO1394_BUFFER_READY;		}	}	spin_unlock(&d->lock);	if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq);	return 0;}int wakeup_dma_it_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d) {	int i;	if (d==NULL) {		PRINT(KERN_ERR, ohci->id, "Iso transmit event received but "		      "context not allocated");		return -EFAULT;	}	spin_lock(&d->lock);	for (i=0;i<d->num_desc;i++) {		if (d->it_prg[i][d->nb_cmd-1].end.status & 0xFFFF0000) {			d->it_prg[i][d->nb_cmd-1].end.status = 0;			d->buffer_status[i] = VIDEO1394_BUFFER_READY;		}	}	spin_unlock(&d->lock);	if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq);	return 0;}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];	unsigned long buf = (unsigned long)d->buf+n*d->buf_size;	int i;		for (i=0;i<d->nb_cmd;i++) {				 		it_prg[i].begin.control = OUTPUT_MORE_IMMEDIATE | 8 ;		it_prg[i].begin.address = 0;				it_prg[i].begin.status = 0;				/* FIXME: what is the tag value + speed selection */		it_prg[i].data[0] = 			(DMA_SPEED_400<<16) | (d->channel<<8) | 0xa0;		if (i==0) it_prg[i].data[0] |= sync_tag;		it_prg[i].data[1] = d->packet_size << 16;		it_prg[i].data[2] = 0;		it_prg[i].data[3] = 0;				it_prg[i].end.control = 0x100c0000;		it_prg[i].end.address =			kvirt_to_bus(buf+i*d->packet_size);		if (i<d->nb_cmd-1) {			it_prg[i].end.control |= d->packet_size;			it_prg[i].begin.branchAddress = 				(virt_to_bus(&(it_prg[i+1].begin.control)) 				 & 0xfffffff0) | 0x3;			it_prg[i].end.branchAddress = 				(virt_to_bus(&(it_prg[i+1].begin.control)) 				 & 0xfffffff0) | 0x3;		}		else {			/* the last prg generates an interrupt */			it_prg[i].end.control |= 0x08300000 | 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;#if 0		printk("%d:%d: %08x-%08x ctrl %08x brch %08x d0 %08x d1 %08x\n",n,i,		       virt_to_bus(&(it_prg[i].begin.control)),		       virt_to_bus(&(it_prg[i].end.control)),		       it_prg[i].end.control,		       it_prg[i].end.branchAddress,		       it_prg[i].data[0], it_prg[i].data[1]);#endif	}}static void initialize_dma_it_ctx(struct dma_iso_ctx *d, int sync_tag){	struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;	int i;	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 do_iso_mmap(struct ti_ohci *ohci, struct dma_iso_ctx *d, 		       const char *adr, unsigned long size){        unsigned long start=(unsigned long) adr;        unsigned long page,pos;        if (size>d->num_desc * d->buf_size) {		PRINT(KERN_ERR, ohci->id, 		      "iso context %d buf size is different from mmap size", 		      d->ctx);                return -EINVAL;	}        if (!d->buf) {		PRINT(KERN_ERR, ohci->id, 		      "iso context %d is not allocated", d->ctx);		return -EINVAL;	}        pos=(unsigned long) d->buf;        while (size > 0) {                page = kvirt_to_pa(pos);                if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))                        return -EAGAIN;                start+=PAGE_SIZE;                pos+=PAGE_SIZE;                size-=PAGE_SIZE;        }        return 0;}static int video1394_ioctl(struct inode *inode, struct file *file,			   unsigned int cmd, unsigned long arg){	struct video_card *video = &video_cards[MINOR(inode->i_rdev)];	struct ti_ohci *ohci= video->ohci;	unsigned long flags;	switch(cmd)	{	case VIDEO1394_LISTEN_CHANNEL:	case VIDEO1394_TALK_CHANNEL:	{		struct video1394_mmap v;		u64 mask;		int i;		if(copy_from_user(&v, (void *)arg, sizeof(v)))			return -EFAULT;		if (v.channel<0 || v.channel>(ISO_CHANNELS-1)) {			PRINT(KERN_ERR, ohci->id, 			      "iso channel %d out of bound", 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) {			PRINT(KERN_ERR, ohci->id,			      "Invalid %d length buffer requested",v.buf_size);			return -EFAULT;		}		if (v.nb_buffers<=0) {			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_LISTEN_CHANNEL) {			/* find a free iso receive context */			for (i=0;i<ohci->nb_iso_rcv_ctx-1;i++) 				if (video->ir_context[i]==NULL) break;			    			if (i==(ohci->nb_iso_rcv_ctx-1)) {				PRINT(KERN_ERR, ohci->id, 				      "no iso context available");				return -EFAULT;			}			video->ir_context[i] = 				alloc_dma_iso_ctx(ohci, ISO_RECEIVE, i+1, 						  v.nb_buffers, v.buf_size, 						  v.channel, 0);			if (video->ir_context[i] == NULL) {				PRINT(KERN_ERR, ohci->id, 				      "Couldn't allocate ir context");				return -EFAULT;			}			initialize_dma_ir_ctx(video->ir_context[i], 					      v.sync_tag, v.flags);			video->current_ctx = video->ir_context[i];			v.buf_size = video->ir_context[i]->buf_size;			PRINT(KERN_INFO, ohci->id, 			      "iso context %d listen on channel %d", i+1, 			      v.channel);		}		else {			/* find a free iso transmit context */			for (i=0;i<ohci->nb_iso_xmit_ctx;i++) 				if (video->it_context[i]==NULL) break;			    			if (i==ohci->nb_iso_xmit_ctx) {				PRINT(KERN_ERR, ohci->id, 				      "no iso context available");				return -EFAULT;			}						video->it_context[i] = 				alloc_dma_iso_ctx(ohci, ISO_TRANSMIT, i, 						  v.nb_buffers, v.buf_size, 						  v.channel, v.packet_size);			if (video->it_context[i] == NULL) {				PRINT(KERN_ERR, ohci->id, 				      "Couldn't allocate it context");				return -EFAULT;			}			initialize_dma_it_ctx(video->it_context[i], 					      v.sync_tag);			video->current_ctx = video->it_context[i];			v.buf_size = video->it_context[i]->buf_size;			PRINT(KERN_INFO, ohci->id, 			      "iso context %d talk on channel %d", i, 			      v.channel);		}		if(copy_to_user((void *)arg, &v, sizeof(v)))			return -EFAULT;		return 0;	}	case VIDEO1394_UNLISTEN_CHANNEL: 	case VIDEO1394_UNTALK_CHANNEL:	{		int channel;		u64 mask;		int i;		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;		}		ohci->ISO_channel_usage &= ~mask;		if (cmd == VIDEO1394_UNLISTEN_CHANNEL) {			i = ir_ctx_listening(video, channel);			if (i<0) return -EFAULT;			free_dma_iso_ctx(&video->ir_context[i]);			PRINT(KERN_INFO, ohci->id, 			      "iso context %d stop listening on channel %d", 			      i+1, channel);		}		else {			i = it_ctx_talking(video, channel);			if (i<0) return -EFAULT;			free_dma_iso_ctx(&video->it_context[i]);			PRINT(KERN_INFO, ohci->id, 			      "iso context %d stop talking on channel %d", 			      i, channel);		}				return 0;	}	case VIDEO1394_LISTEN_QUEUE_BUFFER:	{		struct video1394_wait v;		struct dma_iso_ctx *d;		int i;		if(copy_from_user(&v, (void *)arg, sizeof(v)))			return -EFAULT;		i = ir_ctx_listening(video, v.channel);		if (i<0) return -EFAULT;		d = video->ir_context[i];		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 = 				(virt_to_bus(&(d->ir_prg[v.buffer][0].control)) 				 & 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 */

⌨️ 快捷键说明

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