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

📄 ohci1394.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		if (!(ohci->ISO_channel_usage & mask)) {			PRINT(KERN_ERR, ohci->id, __FUNCTION__			      "IS0_UNLISTEN_CHANNEL channel %d not used", 			      arg);			spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);			return -EFAULT;		}				ohci->ISO_channel_usage &= ~mask;		if (arg>31) 			reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 				  1<<(arg-32));					else			reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 				  1<<arg);			                spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);                DBGMSG(ohci->id, "listening disabled on channel %d", arg);                break;        }	default:		PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet",			cmd);		break;	}	return retval;}/*************************************** * IEEE-1394 functionality section END * ***************************************//******************************************************** * Global stuff (interrupt handler, init/shutdown code) * ********************************************************/static void dma_trm_reset(struct dma_trm_ctx *d){	struct ti_ohci *ohci;	unsigned long flags;        struct hpsb_packet *nextpacket;	if (d==NULL) {		PRINT_G(KERN_ERR, "dma_trm_reset called with NULL arg");		return;	}	ohci = (struct ti_ohci *)(d->ohci);	ohci1394_stop_context(ohci, d->ctrlClear, NULL);	spin_lock_irqsave(&d->lock,flags);	/* is there still any packet pending in the fifo ? */	while(d->fifo_first) {		PRINT(KERN_INFO, ohci->id, 		      "AT dma reset ctx=%d, aborting transmission", 		      d->ctx);                nextpacket = d->fifo_first->xnext;		hpsb_packet_sent(ohci->host, d->fifo_first, ACKX_ABORTED);		d->fifo_first = nextpacket;	}	d->fifo_first = d->fifo_last = NULL;	/* is there still any packet pending ? */	while(d->pending_first) {		PRINT(KERN_INFO, ohci->id, 		      "AT dma reset ctx=%d, aborting transmission", 		      d->ctx);                nextpacket = d->pending_first->xnext;		hpsb_packet_sent(ohci->host, d->pending_first, 				 ACKX_ABORTED);		d->pending_first = nextpacket;	}	d->pending_first = d->pending_last = NULL;		d->branchAddrPtr=NULL;	d->sent_ind = d->prg_ind;	d->free_prgs = d->num_desc;	spin_unlock_irqrestore(&d->lock,flags);}static void ohci_irq_handler(int irq, void *dev_id,                             struct pt_regs *regs_are_unused){	quadlet_t event,node_id;	struct ti_ohci *ohci = (struct ti_ohci *)dev_id;	struct hpsb_host *host = ohci->host;	int phyid = -1, isroot = 0;	int timeout = 255;	do {		/* read the interrupt event register */		event=reg_read(ohci, OHCI1394_IntEventClear);		if (!event) return;		DBGMSG(ohci->id, "IntEvent: %08x",event);		/* clear the interrupt event register */		reg_write(ohci, OHCI1394_IntEventClear, event);		if (event & OHCI1394_busReset) {			if (!host->in_bus_reset) {				PRINT(KERN_INFO, ohci->id, "Bus reset");								/* Wait for the AT fifo to be flushed */				dma_trm_reset(ohci->at_req_context);				dma_trm_reset(ohci->at_resp_context);				/* Subsystem call */				hpsb_bus_reset(ohci->host);								ohci->NumBusResets++;			}		}		/*		 * Problem: How can I ensure that the AT bottom half will be		 * executed before the AR bottom half (both events may have		 * occured within a single irq event)		 * Quick hack: just launch it within the IRQ handler		 */		if (event & OHCI1394_reqTxComplete) { 			struct dma_trm_ctx *d = ohci->at_req_context;			DBGMSG(ohci->id, "Got reqTxComplete interrupt "			       "status=0x%08X", reg_read(ohci, d->ctrlSet));			if (reg_read(ohci, d->ctrlSet) & 0x800)				ohci1394_stop_context(ohci, d->ctrlClear, 					     "reqTxComplete");			else				dma_trm_bh((void *)d);		}		if (event & OHCI1394_respTxComplete) { 			struct dma_trm_ctx *d = ohci->at_resp_context;			DBGMSG(ohci->id, "Got respTxComplete interrupt "			       "status=0x%08X", reg_read(ohci, d->ctrlSet));			if (reg_read(ohci, d->ctrlSet) & 0x800)				ohci1394_stop_context(ohci, d->ctrlClear, 					     "respTxComplete");			else				dma_trm_bh((void *)d);		}		if (event & OHCI1394_RQPkt) {			struct dma_rcv_ctx *d = ohci->ar_req_context;			DBGMSG(ohci->id, "Got RQPkt interrupt status=0x%08X",			       reg_read(ohci, d->ctrlSet));			if (reg_read(ohci, d->ctrlSet) & 0x800)				ohci1394_stop_context(ohci, d->ctrlClear, "RQPkt");			else {#if IEEE1394_USE_BOTTOM_HALVES				queue_task(&d->task, &tq_immediate);				mark_bh(IMMEDIATE_BH);#else				dma_rcv_bh((void *)d);#endif			}		}		if (event & OHCI1394_RSPkt) {			struct dma_rcv_ctx *d = ohci->ar_resp_context;			DBGMSG(ohci->id, "Got RSPkt interrupt status=0x%08X",			       reg_read(ohci, d->ctrlSet));			if (reg_read(ohci, d->ctrlSet) & 0x800)				ohci1394_stop_context(ohci, d->ctrlClear, "RSPkt");			else {#if IEEE1394_USE_BOTTOM_HALVES				queue_task(&d->task, &tq_immediate);				mark_bh(IMMEDIATE_BH);#else				dma_rcv_bh((void *)d);#endif			}		}		if (event & OHCI1394_isochRx) {			quadlet_t isoRecvIntEvent;			struct dma_rcv_ctx *d = ohci->ir_context;			isoRecvIntEvent = 				reg_read(ohci, OHCI1394_IsoRecvIntEventSet);			reg_write(ohci, OHCI1394_IsoRecvIntEventClear,				  isoRecvIntEvent);			DBGMSG(ohci->id, "Got isochRx interrupt "			       "status=0x%08X isoRecvIntEvent=%08x", 			       reg_read(ohci, d->ctrlSet), isoRecvIntEvent);			if (isoRecvIntEvent & 0x1) {				if (reg_read(ohci, d->ctrlSet) & 0x800)					ohci1394_stop_context(ohci, d->ctrlClear, 						     "isochRx");				else {#if IEEE1394_USE_BOTTOM_HALVES					queue_task(&d->task, &tq_immediate);					mark_bh(IMMEDIATE_BH);#else					dma_rcv_bh((void *)d);#endif				}			}			if (ohci->video_tmpl) 				ohci->video_tmpl->irq_handler(ohci->id,							      isoRecvIntEvent,							      0);		}		if (event & OHCI1394_isochTx) {			quadlet_t isoXmitIntEvent;			isoXmitIntEvent = 				reg_read(ohci, OHCI1394_IsoXmitIntEventSet);			reg_write(ohci, OHCI1394_IsoXmitIntEventClear,				  isoXmitIntEvent);			DBGMSG(ohci->id, "Got isochTx interrupt");			if (ohci->video_tmpl) 				ohci->video_tmpl->irq_handler(ohci->id, 0,							      isoXmitIntEvent);		}		if (event & OHCI1394_selfIDComplete) {			if (host->in_bus_reset) {				/* 				 * Begin Fix (JSG): Check to make sure our 				 * node id is valid 				 */				node_id = reg_read(ohci, OHCI1394_NodeID); 				if (!(node_id & 0x80000000)) {					mdelay(1); /* phy is upset - 						    * this happens once in 						    * a while on hot-plugs...						    * give it a ms to recover 						    */				}				/* End Fix (JSG) */				node_id = reg_read(ohci, OHCI1394_NodeID);				if (node_id & 0x80000000) { /* NodeID valid */					phyid =  node_id & 0x0000003f;					isroot = (node_id & 0x40000000) != 0;					PRINT(KERN_INFO, ohci->id,					      "SelfID process finished "					      "(phyid %d, %s)", phyid, 					      (isroot ? "root" : "not root"));					handle_selfid(ohci, host, 						      phyid, isroot);				}				else 					PRINT(KERN_ERR, ohci->id, 					      "SelfID process finished but "					      "NodeID not valid: %08X",					      node_id);				/* Accept Physical requests from all nodes. */				reg_write(ohci,OHCI1394_AsReqFilterHiSet, 					  0xffffffff);				reg_write(ohci,OHCI1394_AsReqFilterLoSet, 					  0xffffffff);                       		/*				 * Tip by James Goodwin <jamesg@Filanet.com>				 * Turn on phys dma reception. We should				 * probably manage the filtering somehow, 				 * instead of blindly turning it on.				 */				reg_write(ohci,OHCI1394_PhyReqFilterHiSet,					  0xffffffff);				reg_write(ohci,OHCI1394_PhyReqFilterLoSet,					  0xffffffff);                        	reg_write(ohci,OHCI1394_PhyUpperBound,					  0xffff0000);			} 			else PRINT(KERN_ERR, ohci->id, 				   "self-id received outside of bus reset"				   "sequence");		}		if (event & OHCI1394_phyRegRcvd) {#if 1			if (host->in_bus_reset) {				PRINT(KERN_INFO, ohci->id, "PhyControl: %08X", 				      reg_read(ohci, OHCI1394_PhyControl));			}			else PRINT(KERN_ERR, ohci->id, 				   "phy reg received outside of bus reset"				   "sequence");#endif		}	} while (--timeout);	PRINT(KERN_ERR, ohci->id, "irq_handler timeout event=0x%08x", event);}/* Put the buffer back into the dma context */static void insert_dma_buffer(struct dma_rcv_ctx *d, int idx){	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);	DBGMSG(ohci->id, "Inserting dma buf ctx=%d idx=%d", d->ctx, idx);	d->prg_cpu[idx]->status = d->buf_size;	d->prg_cpu[idx]->branchAddress &= 0xfffffff0;	idx = (idx + d->num_desc - 1 ) % d->num_desc;	d->prg_cpu[idx]->branchAddress |= 0x1;	/* wake up the dma context if necessary */	if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {		PRINT(KERN_INFO, ohci->id, 		      "Waking dma cxt=%d ... processing is probably too slow",		      d->ctx);		reg_write(ohci, d->ctrlSet, 0x1000);	}}	static int block_length(struct dma_rcv_ctx *d, int idx, 			 quadlet_t *buf_ptr, int offset){	int length=0;	/* Where is the data length ? */	if (offset+12>=d->buf_size) 		length = (d->buf_cpu[(idx+1)%d->num_desc]			  [3-(d->buf_size-offset)/4]>>16);	else 		length = (buf_ptr[3]>>16);	if (length % 4) length += 4 - (length % 4);	return length;}const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0, 			    -1, 0, -1, 0, -1, -1, 16, -1};/*  * Determine the length of a packet in the buffer * Optimization suggested by Pascal Drolet <pascal.drolet@informission.ca> */static int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *buf_ptr,int offset){	unsigned char 	tcode;	int 		length 	= -1;	/* Let's see what kind of packet is in there */	tcode = (buf_ptr[0] >> 4) & 0xf;	if (d->ctx < 2) { /* Async Receive Response/Request */		length = TCODE_SIZE[tcode];		if (length == 0) 			length = block_length(d, idx, buf_ptr, offset) + 20;	}	else if (d->ctx==2) { /* Iso receive */		/* Assumption: buffer fill mode with header/trailer */		length = (buf_ptr[0]>>16);		if (length % 4) length += 4 - (length % 4);		length+=8;	}	return length;}/* Bottom half that processes dma receive buffers */static void dma_rcv_bh(void *data){	struct dma_rcv_ctx *d = (struct dma_rcv_ctx*)data;	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);	unsigned int split_left, idx, offset, rescount;	unsigned char tcode;	int length, bytes_left, ack;	quadlet_t *buf_ptr;	char *split_ptr;	char msg[256];	spin_lock(&d->lock);	idx = d->buf_ind;	offset = d->buf_offset;	buf_ptr = d->buf_cpu[idx] + offset/4;	rescount = d->prg_cpu[idx]->status&0xffff;	bytes_left = d->buf_size - rescount - offset;	while (bytes_left>0) {		tcode = (buf_ptr[0]>>4)&0xf;		length = packet_length(d, idx, buf_ptr, offset);		if (length<4) { /* something is wrong */			sprintf(msg,"unexpected tcode 0x%X in AR ctx=%d",				tcode, d->ctx);			ohci1394_stop_context(ohci, d->ctrlClear, msg);			spin_unlock(&d->lock);			return;		}		if ((offset+length)>d->buf_size) { /* Split packet */			if (length>d->split_buf_size) {				ohci1394_stop_context(ohci, d->ctrlClear,					     "split packet size exceeded");				d->buf_ind = idx;				d->buf_offset = offset;				spin_unlock(&d->lock);				return;			}			if (d->prg_cpu[(idx+1)%d->num_desc]->status			    ==d->buf_size) {				/* other part of packet not written yet */				/* this should never happen I think */				/* anyway we'll get it on the next call */				PRINT(KERN_INFO, ohci->id,				      "Got only half a packet !!!");				d->buf_ind = idx;				d->buf_offset = offset;				spin_unlock(&d->lock);				return;			}			split_left = length;			split_ptr = (char *)d->spb;			memcpy(split_ptr,buf_ptr,d->buf_size-offset);			split_left -= d->buf_size-offset;			split_ptr += d->buf_size-offset;			insert_dma_buffer(d, idx);			idx = (idx+1) % d->num_desc;			buf_ptr = d->buf_cpu[idx];			offset=0;			while (split_left >= d->buf_size) {				memcpy(split_ptr,buf_ptr,d->buf_size);				split_ptr += d->buf_size;				split_left -= d->buf_size;				insert_dma_buffer(d, idx);				idx = (idx+1) % d->num_desc;				buf_ptr = d->buf_cpu[idx];			}			if (split_left>0) {				memcpy(split_ptr, buf_ptr, split_left);				offset = split_left;				buf_ptr += offset/4;			}			/* 			 * We get one phy packet for each bus reset. 			 * we know that from now on the bus topology may			 * have changed. Just ignore it for the moment			 */			if (tcode != 0xE) {				DBGMSG(ohci->id, "Split packet received from"				       " node %d ack=0x%02X spd=%d tcode=0x%X"				       " length=%d data=0x%08x ctx=%d",				       (d->spb[1]>>16)&0x3f,				       (d->spb[length/4-1]>>16)&0x1f,				       (d->spb[length/4-1]>>21)&0x3,				       tcode, length, d->spb[3], d->ctx);								ack = (((d->spb[length/4-1]>>16)&0x1f) 				       == 0x11) ? 1 : 0;				hpsb_packet_received(ohci->host, d->spb, 						     length, ack);			}			else 				PRINT(KERN_INFO, ohci->id, 				      "Got phy packet ctx=%d ... discarded",				      d->ctx);		}		else {			/* 			 * We get one phy packet for each bus reset. 			 * we know that from now on the bus topology may			 * have changed. Just ignore it for the moment			 */			if (tcode != 0xE) {				DBGMSG(ohci->id, "Packet received from node"				       " %d ack=0x%02X spd=%d tcode=0x%X"				       " length=%d data=0x%08x ctx=%d",				       (buf_ptr[1]>>16)&0x3f,				       (buf_ptr[length/4-1]>>16)&0x1f,				       (buf_ptr[length/4-1]>>21)&0x3,				       tcode, length, buf_ptr[3], d->ctx);				ack = (((buf_ptr[length/4-1]>>16)&0x1f)

⌨️ 快捷键说明

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