core_i2c.c

来自「6440linuxDriver的源代码」· C语言 代码 · 共 723 行 · 第 1/2 页

C
723 行
字号
	else {			/* Shall return the specific page of Vital Production Data */		switch (pMvReq->Cdb[2]) {		case 0x00:	/* Supported VPD pages */			tmpLen = MV_MIN(pMvReq->Data_Transfer_Length, I2C_VPD_PAGE0_SIZE);/* supported VPD page */			MV_CopyMemory(pMvReq->Data_Buffer, I2C_INQUIRY_VPD_PAGE0_DATA, tmpLen);			break;		case 0x80:	/* Unit Serial Number VPD Page */			tmpLen = MV_MIN(pMvReq->Data_Transfer_Length, I2C_VPD_PAGE80_SIZE);			MV_CopyMemory(pMvReq->Data_Buffer, I2C_INQUIRY_VPD_PAGE80_DATA, tmpLen);			if (pMvReq->Data_Transfer_Length > I2C_VPD_PAGE80_SIZE) {				tmpLen = I2C_MakeSerialNumber(					(MV_PU8)(pMvReq->Data_Buffer)+I2C_VPD_PAGE80_SIZE,					pSepIdentify, 					pMvReq->Data_Transfer_Length - I2C_VPD_PAGE80_SIZE);				*(((MV_PU8)(pMvReq->Data_Buffer)) + 3) = I2C_VPD_PAGE80_SIZE + 24;/* serial number= 8 charactors of Vendor String + 16 charactors of 8 bytes-naa id */				tmpLen += I2C_VPD_PAGE80_SIZE;			}			break;		case 0x83:	/* Device Identification VPD Page */			tmpLen = MV_MIN(pMvReq->Data_Transfer_Length, I2C_VPD_PAGE83_SIZE);			MV_CopyMemory(pMvReq->Data_Buffer, I2C_INQUIRY_VPD_PAGE83_DATA, tmpLen);			if (pMvReq->Data_Transfer_Length > 8) {				MV_CopyMemory((MV_PU8)(pMvReq->Data_Buffer)+8,					pSepIdentify->logicalID, MV_MIN((pMvReq->Data_Transfer_Length - 8), 8));				if(pMvReq->Data_Transfer_Length > 23)					*((MV_PU8)(pMvReq->Data_Buffer)+ 23)=pSepIdentify->channelID;			}			break;		default:			statusCode = REQ_STATUS_HAS_SENSE;			senseKey = SCSI_SK_ILLEGAL_REQUEST;			adSenseCode = SCSI_ASC_INVALID_FEILD_IN_CDB;			break;		}	}	if (statusCode==REQ_STATUS_HAS_SENSE) {		if (pMvReq->Sense_Info_Buffer != NULL) {			((MV_PU8)pMvReq->Sense_Info_Buffer)[0] = 0x70;	/* Current */			((MV_PU8)pMvReq->Sense_Info_Buffer)[2] = senseKey;			((MV_PU8)pMvReq->Sense_Info_Buffer)[7] = 0;		/* additional sense length */			((MV_PU8)pMvReq->Sense_Info_Buffer)[12] = adSenseCode;	/* additional sense code */		}	}	pMvReq->Data_Transfer_Length = tmpLen;	pMvReq->Scsi_Status=statusCode;	return MV_QUEUE_COMMAND_RESULT_FINISHED;}MV_QUEUE_COMMAND_RESULTI2C_PrepareAndSendCommand(	IN PCore_Driver_Extension pCore,	IN PMV_Request pReq	){	MV_U32 reg;    int i = 0;	PDomain_I2cLink pI2cLink=&pCore->I2cLink;	if( (pI2cLink->I2C_State==I2C_STATE_CMD)||		(pI2cLink->I2C_State==I2C_STATE_RESPONSE) )		return MV_QUEUE_COMMAND_RESULT_FULL;	switch(pReq->Cdb[0])	{	case SCSI_CMD_INQUIRY:		return I2C_InquiryCmd(pI2cLink,pReq);	case I2C_CMD_IDENTIFY_SEP:	case SCSI_CMD_RCV_DIAG_RSLT:/* build the I2C SEP command frame */		pI2cLink->I2cCmdHeader[0] = (pReq->Req_Flag & REQ_FLAG_EXTERNAL) ? pReq->Cdb[1] : pI2cLink->I2cSEP_Address;		pI2cLink->I2cCmdHeader[1] = I2C_CT_D2H_SES;		pI2cLink->I2cCmdHeader[2] = I2C_SataChecksum(pI2cLink->I2cCmdHeader, 2, 0);		pI2cLink->I2cCmdHeader[3] = (pReq->Req_Flag & REQ_FLAG_EXTERNAL) ? pReq->Cdb[3] : I2C_SEMB_ADDR;		pI2cLink->I2cCmdHeader[4] = 0;   /*pI2cLink->I2cCmdHeader[4] = i2cCmdSeq++;*/		pI2cLink->I2cCmdHeader[5] = pReq->Cdb[0];		pI2cLink->I2cCmdHeader[6] = I2C_SataChecksum(&pI2cLink->I2cCmdHeader[3], 3, 0);		pI2cLink->I2cCmdFrameLen = 7;		pI2cLink->I2cRspFrameLen= 8 + (MV_U16)pReq->Data_Transfer_Length;		break;	case SCSI_CMD_SND_DIAG:/* build the I2C SEP command frame */		pI2cLink->I2cCmdHeader[0] = (pReq->Req_Flag & REQ_FLAG_EXTERNAL) ? pReq->Cdb[1] : pI2cLink->I2cSEP_Address;		pI2cLink->I2cCmdHeader[1] = I2C_CT_H2D_SES;		pI2cLink->I2cCmdHeader[2] = I2C_SataChecksum(pI2cLink->I2cCmdHeader, 2, 0);		pI2cLink->I2cCmdHeader[3] = (pReq->Req_Flag & REQ_FLAG_EXTERNAL) ? pReq->Cdb[3] : I2C_SEMB_ADDR;		pI2cLink->I2cCmdHeader[4] = 0;   /*pCore->I2cCmdHeader[4] = i2cCmdSeq++;*/		pI2cLink->I2cCmdHeader[5] = pReq->Cdb[0];		pI2cLink->I2cCmdHeader[6] = I2C_SataChecksum(pReq->Data_Buffer, pReq->Data_Transfer_Length, I2C_SataChecksum(&pI2cLink->I2cCmdHeader[3], 3, 0));		pI2cLink->I2cCmdFrameLen = 7 + (MV_U16)pReq->Data_Transfer_Length;		pI2cLink->I2cRspFrameLen= 8 + (MV_U16)pReq->Data_Transfer_Length;		break;	default:		pReq->Scsi_Status = REQ_STATUS_INVALID_REQUEST;		return MV_QUEUE_COMMAND_RESULT_FINISHED;	}	reg = MV_REG_READ_DWORD(pCore->Mmio_Base, COMMON_IRQ_MASK);	reg |= INT_SLAVE_I2C;	MV_REG_WRITE_DWORD(pCore->Mmio_Base, COMMON_IRQ_MASK, reg);	I2C_SendI2cFrame(pCore,pReq);	return MV_QUEUE_COMMAND_RESULT_SENT;}static MV_BOOLEAN I2C_DeviceStateMachine(	PCore_Driver_Extension pCore,	PDomain_Device pDevice	);void I2C_IdentifyCallback(	 IN	MV_PVOID This,	 IN	PMV_Request	pReq){    PCore_Driver_Extension pCore = (PCore_Driver_Extension)This;    PDomain_I2cLink pI2cLink=&pCore->I2cLink;    PDomain_Port pPort;     PDomain_Device pDevice = NULL;     pPort = &pCore->Ports[MapPortEntry(pCore,MapPortId(pCore, pReq->Device_Id))];    pDevice = &pCore->Devices[MapDeviceId(pCore, pReq->Device_Id)];    if( pReq->Scsi_Status==REQ_STATUS_ERROR )    {	    MV_PRINT("I2C callback error\n");	    pDevice->Status &=~DEVICE_STATUS_FUNCTIONAL;		pDevice->State = DEVICE_STATE_RESET_DONE;    }    else {		MV_PRINT("I2C Connected\n");	    MV_CopyMemory(pI2cLink->I2cIdentify,pReq->Data_Buffer,64);	   	pDevice->State = DEVICE_STATE_IDENTIFY_DONE;    }    if( pReq->Scratch_Buffer )	    FreeSATAScratchToPool(pCore, (PSATA_Scratch_Buffer *) &pReq->Scratch_Buffer);    FreeInternalReqToPool(pCore, pReq);    I2C_DeviceStateMachine(pCore, pDevice);}voidI2C_MakeIdentifyRequest(PDomain_Device pDevice){	PCore_Driver_Extension pCore = pDevice->pPort->Core_Extension;	PMV_Request pReq = GetInternalReqFromPool(pCore);	PSATA_Scratch_Buffer pSATASB;    PMV_SG_Table pSGTable;	if( pReq == NULL ) 	{		// no internal requests available - wait for now 		pDevice->Is_Waiting = MV_TRUE;		return;	}	pSATASB = GetSATAScratchFromPool(pCore);	if( pSATASB == NULL )	{		FreeInternalReqToPool(pCore, pReq);		MV_DPRINT(("ERROR: No more free SATA scratch buffer. Request aborted.\n"));		return;	}	pSGTable = &pReq->SG_Table;	/* Prepare identify  */	pReq->Cdb[0] = I2C_CMD_IDENTIFY_SEP;	pReq->Tag = 0xac;	pReq->Device_Id = pDevice->Id;	//pReq->Req_Flag;	pReq->Cmd_Initiator = pDevice->pPort->Core_Extension;	pReq->Data_Transfer_Length = 64;	pReq->Data_Buffer = pSATASB->Scratch_Vir;	pReq->Scratch_Buffer = pSATASB;	pReq->Completion = (void(*)(MV_PVOID,PMV_Request))I2C_IdentifyCallback;/* current I2c doesn't need DMA, but kept for future HW change. Make SG table */	SGTable_Init(pSGTable, 0);	SGTable_Append(pSGTable, 		pSATASB->Scratch_DMA.parts.low, 		pSATASB->Scratch_DMA.parts.high,				pReq->Data_Transfer_Length				); 	/* Send this internal request */	I2C_PrepareAndSendCommand(pCore, pReq);}/* Search through possible address - Starting with the default addresses of C0 and c2.   If the two fails then start trying from  00 till FF.   Return:        TRUE if there are valid addresses to try       FALSE if there are no valid addresses to try */MV_BOOLEAN I2C_CycleAddress( PDomain_I2cLink pI2cLink ){	static MV_U16 numSearches = 0;	if( numSearches == 0 ) {		//MV_PRINT("*  Try Address 0xC0 \n");		pI2cLink->I2cSEP_Address = I2C_SEP_ADDR0;		numSearches++;		return MV_TRUE;	} else if( numSearches == 1 ) {		//MV_PRINT("*  Try Address 0xC2 \n");		pI2cLink->I2cSEP_Address = I2C_SEP_ADDR1;		numSearches++;		return MV_TRUE;	// disable multi-I2C address search	/*} else if( numSearches > 1 && numSearches < 0x10 ) {		pI2cLink->I2cSEP_Address = I2C_SEP_ADDR0 + (numSearches*2);		MV_PRINT("*  Try Address 0x%x \n", pI2cLink->I2cSEP_Address );		numSearches++;		return MV_TRUE;*/	} else {		//MV_PRINT("*  Tried all addresses \n" );		return MV_FALSE;	}}static void I2C_StopModule(MV_PVOID This){	MV_U8 regI2c;	PCore_Driver_Extension pCore=(PCore_Driver_Extension)This;	Write_I2C_Register(pCore, MI2C_SOFT_RESET, 0);	Write_I2C_Register(pCore,MI2C_CONTROL,0);}static MV_BOOLEAN I2C_DeviceStateMachine(	PCore_Driver_Extension pCore,	PDomain_Device pDevice	){	PDomain_Port pPort = pDevice->pPort;	PDomain_I2cLink pI2cLink=&pCore->I2cLink;	switch ( pDevice->State )	{		case DEVICE_STATE_RESET_DONE:			//MV_DPRINT(("I2C Device %d DEVICE_STATE_RESET_DONE.\n", pDevice->Id));			pI2cLink->pI2cDevice=pDevice;			/* To do inquiry */			if( I2C_CycleAddress( pI2cLink ) ){				//MV_PRINT("pI2cLink->I2cSEP_Address = 0x%x \n", pI2cLink->I2cSEP_Address );				I2C_MakeIdentifyRequest( pDevice );				break;			}			pDevice->State = DEVICE_STATE_IDENTIFY_DONE;			I2C_StopModule(pCore);		case DEVICE_STATE_IDENTIFY_DONE:			//MV_DPRINT(("I2C Device %d DEVICE_STATE_IDENTIFY_DONE.\n", pDevice->Id));			pDevice->State=DEVICE_STATE_INIT_DONE;			if(!(pDevice->Status&DEVICE_STATUS_FUNCTIONAL))			{				List_Del( &pDevice->Queue_Pointer );				FreeDeviceToPool(pCore, pDevice);				pPort->Device_Number--;				pI2cLink->pI2cDevice=NULL;				FreePortToPool(pCore, pPort);			}		default:			/* The first time initialization */			core_start_cmpl_notify(pCore->desc);			break;	}	return MV_TRUE;}voidCheckI2CDevice(MV_PVOID This){	PCore_Driver_Extension pCore=(PCore_Driver_Extension)This;	PDomain_Port pPort;	PDomain_Device pDevice = NULL;/* first Create a virtual port and a virtual device. */	pPort = GetPortFromPool(pCore);	if(pPort==NULL)		return;/*  a virtual port is a port with no phy in its MemberPhyMap. */	pPort->MemberPhyMap=0; 	pPort->Type = PORT_TYPE_SAS|PORT_TYPE_I2C; /* it is emulated as a SSP SES device */	pPort->Port_State = PORT_STATE_INIT_DONE; /* don't block the channel state machine */	pPort->DiscoveryInstance = 0;	pPort->Core_Extension = pCore;	pPort->Expander_Number=0;	pDevice = GetDeviceFromPool( pCore );	if( pDevice == NULL )	{		FreePortToPool(pCore, pPort);		return;	}/*  create a virtual SES device. */	pDevice->Status = DEVICE_STATUS_EXISTING | DEVICE_STATUS_FUNCTIONAL;	pDevice->State = DEVICE_STATE_RESET_DONE;	pDevice->Connection = DC_SCSI | DC_SERIAL;	pDevice->Dev_Type = DT_ENCLOSURE;	U64_ZERO_VALUE(pDevice->Max_LBA);	if (pCore->State == CORE_STATE_STARTED)		pDevice->Need_Notify = MV_TRUE;	U64_ZERO_VALUE(pDevice->SASAddr);	pDevice->pPort = pPort;	pPort->Device_Number=1;	List_AddTail( &pDevice->Queue_Pointer, &pPort->Device_List );	I2C_DeviceStateMachine(pCore, pDevice );}void I2C_ModuleInitialize(MV_PVOID This){	PCore_Driver_Extension pCore=(PCore_Driver_Extension)This;	PDomain_I2cLink pI2cLink=&pCore->I2cLink;	MV_U32 reg;	MV_U8 regI2c;	Write_I2C_Register(pCore, MI2C_SOFT_RESET, 0);	regI2c=0;	((PREG_MI2C_CONTROL)&regI2c)->ENAB=1;	((PREG_MI2C_CONTROL)&regI2c)->IEN=1;	((PREG_MI2C_CONTROL)&regI2c)->AAK=1;	Write_I2C_Register(pCore,MI2C_CONTROL,regI2c);	Write_I2C_Register(pCore,MI2C_SLAVE_ADDRESS,I2C_SEMB_ADDR);	Write_I2C_Register(pCore,MI2C_X_SLAVE_ADDRESS,0);	/* set the baud rate register to */	regI2c=I2C_FindCCR(I2C_LINK_RATE);	Write_I2C_Register(pCore,MI2C_CLOCK_CONTROL,regI2c);	//MV_PRINT("Clk Frequency regI2c = 0x%x\n", regI2c );	pI2cLink->I2C_Clock=regI2c;	CheckI2CDevice(This);	return;}#endif

⌨️ 快捷键说明

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