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

📄 ohci1394.c

📁 Armlinux ieee1394接口驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Decide wether we have an iso, a request, or a response packet */	tcode = (packet->header[0]>>4)&0xf;	if (tcode == TCODE_ISO_DATA) d = ohci->it_context;	else if (tcode & 0x02) d = ohci->at_resp_context;	else d = ohci->at_req_context;	spin_lock_irqsave(&d->lock,flags);	/* queue the packet for later insertion into the dma fifo */	if (d->pending_last) {		d->pending_last->xnext = packet;		d->pending_last = packet;	}	else {		d->pending_first = packet;		d->pending_last = packet;	}		dma_trm_flush(ohci, d);	spin_unlock_irqrestore(&d->lock,flags);	return 1;}static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg){	struct ti_ohci *ohci = host->hostdata;	int retval = 0;	unsigned long flags;	switch (cmd) {	case RESET_BUS:		DBGMSG(ohci->id, "devctl: Bus reset requested%s",		       ((host->attempt_root || attempt_root) ? 		       " and attempting to become root" : ""));		set_phy_reg_mask (ohci, 1, 0x40 | ((host->attempt_root || attempt_root) ?				  0x80 : 0));		break;	case GET_CYCLE_COUNTER:		retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer);		break;		case SET_CYCLE_COUNTER:		reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg);		break;		case SET_BUS_ID:		PRINT(KERN_ERR, ohci->id, "devctl command SET_BUS_ID err");		break;	case ACT_CYCLE_MASTER:		if (arg) {			/* check if we are root and other nodes are present */			u32 nodeId = reg_read(ohci, OHCI1394_NodeID);			if ((nodeId & (1<<30)) && (nodeId & 0x3f)) {				/*				 * enable cycleTimer, cycleMaster				 */				DBGMSG(ohci->id, "Cycle master enabled");				reg_write(ohci, OHCI1394_LinkControlSet, 					  0x00300000);			}		} else {			/* disable cycleTimer, cycleMaster, cycleSource */			reg_write(ohci, OHCI1394_LinkControlClear, 0x00700000);		}		break;	case CANCEL_REQUESTS:		DBGMSG(ohci->id, "Cancel request received");		dma_trm_reset(ohci->at_req_context);		dma_trm_reset(ohci->at_resp_context);		break;	case MODIFY_USAGE:                if (arg) {                        MOD_INC_USE_COUNT;                } else {                        MOD_DEC_USE_COUNT;                }                break;	case ISO_LISTEN_CHANNEL:        {		u64 mask;		if (arg<0 || arg>63) {			PRINT(KERN_ERR, ohci->id, __FUNCTION__			      "IS0 listen channel %d is out of range", 			      arg);			return -EFAULT;		}		mask = (u64)0x1<<arg;		                spin_lock_irqsave(&ohci->IR_channel_lock, flags);		if (ohci->ISO_channel_usage & mask) {			PRINT(KERN_ERR, ohci->id, __FUNCTION__			      "IS0 listen channel %d is already used", 			      arg);			spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);			return -EFAULT;		}				ohci->ISO_channel_usage |= mask;		if (arg>31) 			reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, 				  1<<(arg-32));					else			reg_write(ohci, OHCI1394_IRMultiChanMaskLoSet, 				  1<<arg);			                spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);                DBGMSG(ohci->id, "Listening enabled on channel %d", arg);                break;        }	case ISO_UNLISTEN_CHANNEL:        {		u64 mask;		if (arg<0 || arg>63) {			PRINT(KERN_ERR, ohci->id, __FUNCTION__			      "IS0 unlisten channel %d is out of range", 			      arg);			return -EFAULT;		}		mask = (u64)0x1<<arg;		                spin_lock_irqsave(&ohci->IR_channel_lock, flags);		if (!(ohci->ISO_channel_usage & mask)) {			PRINT(KERN_ERR, ohci->id, __FUNCTION__			      "IS0 unlisten channel %d is 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;	unsigned long flags;	/* Read and clear the interrupt event register.  Don't clear	 * the busReset event, though, this is done when we get the	 * selfIDComplete interrupt. */	spin_lock_irqsave(&ohci->event_lock, flags);	event = reg_read(ohci, OHCI1394_IntEventClear);	reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset);	spin_unlock_irqrestore(&ohci->event_lock, flags);	if (!event) return;	DBGMSG(ohci->id, "IntEvent: %08x", event);	/* Die right here an now */	if (event & OHCI1394_unrecoverableError) {		PRINT(KERN_ERR, ohci->id, "Unrecoverable error, shutting down card!");		remove_card(ohci);		return;	}	if (event & OHCI1394_busReset) {		/* The busReset event bit can't be cleared during the		 * selfID phase, so we disable busReset interrupts, to		 * avoid burying the cpu in interrupt requests. */		spin_lock_irqsave(&ohci->event_lock, flags);  		reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset);		if (ohci->dev->vendor == PCI_VENDOR_ID_APPLE && 		    ohci->dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) {  			udelay(10);  			while(reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {  				reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);				spin_unlock_irqrestore(&ohci->event_lock, flags);	  			udelay(10);				spin_lock_irqsave(&ohci->event_lock, flags);  			}  		}		spin_unlock_irqrestore(&ohci->event_lock, flags);		if (!host->in_bus_reset) {			DBGMSG(ohci->id, "irq_handler: Bus reset requested%s",			      ((host->attempt_root || attempt_root) ?			      " and attempting to become root" : ""));			/* Subsystem call */			hpsb_bus_reset(ohci->host);		}		event &= ~OHCI1394_busReset;	}	/* XXX: We need a way to also queue the OHCI1394_reqTxComplete,	 * but for right now we simply run it upon reception, to make sure	 * we get sent acks before response packets. This sucks mainly	 * because it halts the interrupt 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_tasklet ((unsigned long)d);		event &= ~OHCI1394_reqTxComplete;	}	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			tasklet_schedule(&d->task);		event &= ~OHCI1394_respTxComplete;	}	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			tasklet_schedule(&d->task);		event &= ~OHCI1394_RQPkt;	}	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			tasklet_schedule(&d->task);		event &= ~OHCI1394_RSPkt;	}	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				tasklet_schedule(&d->task);		}		if (ohci->video_tmpl) 			ohci->video_tmpl->irq_handler(ohci->id, isoRecvIntEvent,						      0);		event &= ~OHCI1394_isochRx;	}	if (event & OHCI1394_isochTx) {		quadlet_t isoXmitIntEvent;		struct dma_trm_ctx *d = ohci->it_context;		isoXmitIntEvent = 			reg_read(ohci, OHCI1394_IsoXmitIntEventSet);		reg_write(ohci, OHCI1394_IsoXmitIntEventClear,			  isoXmitIntEvent);                       DBGMSG(ohci->id, "Got isochTx interrupt "                               "status=0x%08x isoXmitIntEvent=%08x",                              reg_read(ohci, d->ctrlSet), isoXmitIntEvent);		if (ohci->video_tmpl) 			ohci->video_tmpl->irq_handler(ohci->id, 0,						      isoXmitIntEvent);		if (isoXmitIntEvent & 0x1) {			if (reg_read(ohci, d->ctrlSet) & 0x800)				ohci1394_stop_context(ohci, d->ctrlClear, "isochTx");			else				tasklet_schedule(&d->task);		}		event &= ~OHCI1394_isochTx;	}	if (event & OHCI1394_selfIDComplete) {		if (host->in_bus_reset) {			node_id = reg_read(ohci, OHCI1394_NodeID); 			/* If our nodeid is not valid, give a msec delay			 * to let it settle in and try again.  */			if (!(node_id & 0x80000000)) {				mdelay(1);				node_id = reg_read(ohci, OHCI1394_NodeID);			}			if (node_id & 0x80000000) { /* NodeID valid */				phyid =  node_id & 0x0000003f;				isroot = (node_id & 0x40000000) != 0;				DBGMSG(ohci->id,				      "SelfID interrupt received "				      "(phyid %d, %s)", phyid, 				      (isroot ? "root" : "not root"));				handle_selfid(ohci, host, 					      phyid, isroot);			} else {				PRINT(KERN_ERR, ohci->id, 				      "SelfID interrupt received, but "				      "NodeID is not valid: %08X",				      node_id);			}			/* Accept Physical requests from all nodes. */			reg_write(ohci,OHCI1394_AsReqFilterHiSet, 				  0xffffffff);			reg_write(ohci,OHCI1394_AsReqFilterLoSet, 				  0xffffffff);			/* 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, 			      "SelfID received outside of bus reset sequence");		/* Finally, we clear the busReset event and reenable		 * the busReset interrupt. */		spin_lock_irqsave(&ohci->event_lock, flags);		reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); 		reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);		spin_unlock_irqrestore(&ohci->event_lock, flags);		event &= ~OHCI1394_selfIDComplete;		}	/* Make sure we handle everything, just in case we accidentally	 * enabled an interrupt that we didn't write a handler for.  */	if (event)		PRINT(KERN_ERR, ohci->id, "Unhandled interrupt(s) 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 = cpu_to_le32(d->buf_size);	d->prg_cpu[idx]->branchAddress &= le32_to_cpu(0xfffffff0);	idx = (idx + d->num_desc - 1 ) % d->num_desc;	d->prg_cpu[idx]->branchAddress |= le32_to_cpu(0x00000001);	/* wake up the dma context if necessary */	if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {		PRINT(KERN_INFO, ohci->id, 		      "Waking dma ctx=%d ... processing is probably too slow",		      d->ctx);		reg_write(ohci, d->ctrlSet, 0x1000);	}}#define cond_le32_to_cpu(data, noswap) \

⌨️ 快捷键说明

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