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

📄 ohci1394.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Soft reset */	if ((retval=ohci_soft_reset(ohci))<0) return retval;	/* 	 * Delay after soft reset to make sure everything has settled	 * down (sanity)	 */	mdelay(100);      	/* Set Link Power Status (LPS) */	reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);	/*	 * Delay after setting LPS in order to make sure link/phy	 * communication is established	 */	mdelay(100);   	/* Set the bus number */	reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);	/* Enable posted writes */	reg_write(ohci, OHCI1394_HCControlSet, 0x00040000);	/* Clear link control register */	reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);  	/* Enable cycle timer and cycle master */	reg_write(ohci, OHCI1394_LinkControlSet, 0x00300000);	/* Clear interrupt registers */	reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);	reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);	/* Set up self-id dma buffer */	reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus);	/* enable self-id dma */	reg_write(ohci, OHCI1394_LinkControlSet, 0x00000200);	/* Set the configuration ROM mapping register */	reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);	/* Set bus options */	reg_write(ohci, OHCI1394_BusOptions, 		  cpu_to_be32(ohci->csr_config_rom_cpu[2]));#if 0		/* Write the GUID into the csr config rom */	ohci->csr_config_rom_cpu[3] = 		be32_to_cpu(reg_read(ohci, OHCI1394_GUIDHi));	ohci->csr_config_rom_cpu[4] = 		be32_to_cpu(reg_read(ohci, OHCI1394_GUIDLo));#endif	/* Write the config ROM header */	reg_write(ohci, OHCI1394_ConfigROMhdr, 		  cpu_to_be32(ohci->csr_config_rom_cpu[0]));	ohci->max_packet_size = 		1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);	PRINT(KERN_INFO, ohci->id, "max packet size = %d bytes",	      ohci->max_packet_size);	/* Don't accept phy packets into AR request context */ 	reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);	/* Initialize IR dma */	ohci->nb_iso_rcv_ctx = 		get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);	PRINT(KERN_INFO, ohci->id, "%d iso receive contexts available",	      ohci->nb_iso_rcv_ctx);	for (i=0;i<ohci->nb_iso_rcv_ctx;i++) {		reg_write(ohci, OHCI1394_IsoRcvContextControlClear+32*i,			  0xffffffff);		reg_write(ohci, OHCI1394_IsoRcvContextMatch+32*i, 0);		reg_write(ohci, OHCI1394_IsoRcvCommandPtr+32*i, 0);	}	/* Set bufferFill, isochHeader, multichannel for IR context */	reg_write(ohci, OHCI1394_IsoRcvContextControlSet, 0xd0000000);				/* Set the context match register to match on all tags */	reg_write(ohci, OHCI1394_IsoRcvContextMatch, 0xf0000000);	/* Clear the interrupt mask */	reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);	reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);	/* Initialize IT dma */	ohci->nb_iso_xmit_ctx = 		get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);	PRINT(KERN_INFO, ohci->id, "%d iso transmit contexts available",	      ohci->nb_iso_xmit_ctx);	for (i=0;i<ohci->nb_iso_xmit_ctx;i++) {		reg_write(ohci, OHCI1394_IsoXmitContextControlClear+32*i,			  0xffffffff);		reg_write(ohci, OHCI1394_IsoXmitCommandPtr+32*i, 0);	}		/* Clear the interrupt mask */	reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);	reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);	/* Clear the multi channel mask high and low registers */	reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);	reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);	/* Initialize AR dma */	initialize_dma_rcv_ctx(ohci->ar_req_context);	initialize_dma_rcv_ctx(ohci->ar_resp_context);	/* Initialize AT dma */	initialize_dma_trm_ctx(ohci->at_req_context);	initialize_dma_trm_ctx(ohci->at_resp_context);	/* Initialize IR dma */	initialize_dma_rcv_ctx(ohci->ir_context);	/* Set up isoRecvIntMask to generate interrupts for context 0	   (thanks to Michael Greger for seeing that I forgot this) */	reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001);	/* 	 * Accept AT requests from all nodes. This probably 	 * will have to be controlled from the subsystem	 * on a per node basis.	 */	reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000);	/* Specify AT retries */	reg_write(ohci, OHCI1394_ATRetries, 		  OHCI1394_MAX_AT_REQ_RETRIES |		  (OHCI1394_MAX_AT_RESP_RETRIES<<4) |		  (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));#ifndef __BIG_ENDIAN	reg_write(ohci, OHCI1394_HCControlClear, 0x40000000);#else	reg_write(ohci, OHCI1394_HCControlSet, 0x40000000);#endif	/* Enable interrupts */	reg_write(ohci, OHCI1394_IntMaskSet, 		  OHCI1394_masterIntEnable | 		  OHCI1394_phyRegRcvd | 		  OHCI1394_busReset | 		  OHCI1394_selfIDComplete |		  OHCI1394_RSPkt |		  OHCI1394_RQPkt |		  OHCI1394_ARRS |		  OHCI1394_ARRQ |		  OHCI1394_respTxComplete |		  OHCI1394_reqTxComplete |		  OHCI1394_isochRx |		  OHCI1394_isochTx		);	/* Enable link */	reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);	return 1;}static void ohci_remove(struct hpsb_host *host){	struct ti_ohci *ohci;        	if (host != NULL) {		ohci = host->hostdata;		remove_card(ohci);	}}/*  * Insert a packet in the AT DMA fifo and generate the DMA prg * FIXME: rewrite the program in order to accept packets crossing *        page boundaries. *        check also that a single dma descriptor doesn't cross a  *        page boundary. */static void insert_packet(struct ti_ohci *ohci,			  struct dma_trm_ctx *d, struct hpsb_packet *packet){	u32 cycleTimer;	int idx = d->prg_ind;	d->prg_cpu[idx]->begin.address = 0;	d->prg_cpu[idx]->begin.branchAddress = 0;	if (d->ctx==1) {		/* 		 * For response packets, we need to put a timeout value in		 * the 16 lower bits of the status... let's try 1 sec timeout 		 */ 		cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);		d->prg_cpu[idx]->begin.status = 			(((((cycleTimer>>25)&0x7)+1)&0x7)<<13) | 			((cycleTimer&0x01fff000)>>12);		DBGMSG(ohci->id, "cycleTimer: %08x timeStamp: %08x",		       cycleTimer, d->prg_cpu[idx]->begin.status);	}	else 		d->prg_cpu[idx]->begin.status = 0;        if (packet->type == raw) {		d->prg_cpu[idx]->data[0] = OHCI1394_TCODE_PHY<<4;		d->prg_cpu[idx]->data[1] = packet->header[0];		d->prg_cpu[idx]->data[2] = packet->header[1];        }        else {		d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |			(packet->header[0] & 0xFFFF);		d->prg_cpu[idx]->data[1] = (packet->header[1] & 0xFFFF) | 			(packet->header[0] & 0xFFFF0000);		d->prg_cpu[idx]->data[2] = packet->header[2];		d->prg_cpu[idx]->data[3] = packet->header[3];        }	if (packet->data_size) { /* block transmit */		d->prg_cpu[idx]->begin.control = OUTPUT_MORE_IMMEDIATE | 0x10;		d->prg_cpu[idx]->end.control = OUTPUT_LAST | packet->data_size;		/* 		 * FIXME: check that the packet data buffer		 * do not cross a page boundary 		 */		if (cross_bound((unsigned long)packet->data, 				packet->data_size)>0) {			/* FIXME: do something about it */			PRINT(KERN_ERR, ohci->id, __FUNCTION__			      ": packet data addr: %p size %d bytes "			      "cross page boundary", 			      packet->data, packet->data_size);		}		d->prg_cpu[idx]->end.address =			pci_map_single(ohci->dev, packet->data,				       packet->data_size, PCI_DMA_TODEVICE);		d->prg_cpu[idx]->end.branchAddress = 0;		d->prg_cpu[idx]->end.status = 0;		if (d->branchAddrPtr) 			*(d->branchAddrPtr) = d->prg_bus[idx] | 0x3;		d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress);	}	else { /* quadlet transmit */                if (packet->type == raw)                        d->prg_cpu[idx]->begin.control =				OUTPUT_LAST_IMMEDIATE|(packet->header_size+4);                else                        d->prg_cpu[idx]->begin.control =                                OUTPUT_LAST_IMMEDIATE|packet->header_size;		if (d->branchAddrPtr) 			*(d->branchAddrPtr) = d->prg_bus[idx] | 0x2;		d->branchAddrPtr = &(d->prg_cpu[idx]->begin.branchAddress);	}	d->free_prgs--;	/* queue the packet in the appropriate context queue */	if (d->fifo_last) {		d->fifo_last->xnext = packet;		d->fifo_last = packet;	}	else {		d->fifo_first = packet;		d->fifo_last = packet;	}	d->prg_ind = (d->prg_ind+1)%d->num_desc;}/* * This function fills the AT FIFO with the (eventual) pending packets * and runs or wake up the AT DMA prg if necessary. * The function MUST be called with the d->lock held. */ static int dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d){	int idx,z;	if (d->pending_first == NULL || d->free_prgs == 0) 		return 0;	idx = d->prg_ind;	z = (d->pending_first->data_size) ? 3 : 2;	/* insert the packets into the at dma fifo */	while (d->free_prgs>0 && d->pending_first) {		insert_packet(ohci, d, d->pending_first);		d->pending_first = d->pending_first->xnext;	}	if (d->pending_first == NULL) 		d->pending_last = NULL;	else		PRINT(KERN_INFO, ohci->id, 		      "AT DMA FIFO ctx=%d full... waiting",d->ctx);	/* Is the context running ? (should be unless it is 	   the first packet to be sent in this context) */	if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) {		DBGMSG(ohci->id,"Starting AT DMA ctx=%d",d->ctx);		reg_write(ohci, d->cmdPtr, d->prg_bus[idx]|z);		run_context(ohci, d->ctrlSet, NULL);	}	else {		DBGMSG(ohci->id,"Waking AT DMA ctx=%d",d->ctx);		/* wake up the dma context if necessary */		if (!(reg_read(ohci, d->ctrlSet) & 0x400))			reg_write(ohci, d->ctrlSet, 0x1000);	}	return 1;}/* * Transmission of an async packet */static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet){	struct ti_ohci *ohci = host->hostdata;	struct dma_trm_ctx *d;	unsigned char tcode;	unsigned long flags;	if (packet->data_size > ohci->max_packet_size) {		PRINT(KERN_ERR, ohci->id, 		      "transmit packet size = %d too big",		      packet->data_size);		return 0;	}	packet->xnext = NULL;	/* Decide wether we have a request or a response packet */	tcode = (packet->header[0]>>4)&0xf;	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 to 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:		/*		 * FIXME: this flag might be necessary in some case		 */		PRINT(KERN_INFO, ohci->id, "resetting bus on request%s",		      ((host->attempt_root || attempt_root) ? 		       " and attempting to become root" : ""));		reg_write(ohci, OHCI1394_PhyControl, 			  (host->attempt_root || attempt_root) ? 			  0x000041ff : 0x0000417f);		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 channel %d 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 channel %d 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 channel %d out of range", 			      arg);			return -EFAULT;		}		mask = (u64)0x1<<arg;		                spin_lock_irqsave(&ohci->IR_channel_lock, flags);

⌨️ 快捷键说明

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