static int powerup(void)
{
	int ret = 0;
	u8 cmd[8];
	u8 rsp[13];

	pSi47xxdata->power(1);

	cmd[0] = POWER_UP;
	cmd[1] = POWER_UP_IN_GPO2OEN | POWER_UP_IN_FUNC_FMRX;
#ifdef CONFIG_RADIO_USE_MI2S
	cmd[2] = POWER_UP_IN_OPMODE_RX_DIGITAL;
#else
	cmd[2] = POWER_UP_IN_OPMODE_RX_ANALOG;
#endif
	ret = si47xx_command(3, cmd, 8, rsp);

	if (ret < 0) {
		dev_err(Si47xx_dev->dev, "%s failed %d\n", __func__, ret);
	} else {
		/* Si4709/09 datasheet: Table 7 */
		msleep(110);
		Si47xx_dev->state.power_state = RADIO_ON;
	}
	return ret;
}
/*-----------------------------------------------------------------------------
 Helper function that sends the FM_RDS_STATUS command to the part

 Inputs:
  intack: If non-zero the interrupt for STCINT will be cleared.
  mtfifo: If non-zero the fifo will be cleared.

Outputs:
Status:      Contains bits about the status returned from the part.
RdsInts:     Contains bits about the interrupts that have fired
related to RDS.
RdsSync:     If non-zero the RDS is currently synced.
GrpLost:     If non-zero some RDS groups were lost.
RdsFifoUsed: The amount of groups currently remaining
in the RDS fifo.
BlockA:      Block A group data from the oldest FIFO entry.
BlockB:      Block B group data from the oldest FIFO entry.
BlockC:      Block C group data from the oldest FIFO entry.
BlockD:      Block D group data from the oldest FIFO entry.
BleA:        Block A corrected error information.
BleB:        Block B corrected error information.
BleC:        Block C corrected error information.
BleD:        Block D corrected error information.
-----------------------------------------------------------------------------*/
static void fmRdsStatus(u8 intack, u8 mtfifo, struct radio_data_t *rds_data,
				u8 *RdsFifoUsed)
{
	u8 cmd[8];
	u8 rsp[13];
	int ret = 0;

	cmd[0] = FM_RDS_STATUS;
	cmd[1] = 0;
	if (intack)
		cmd[1] |= FM_RDS_STATUS_IN_INTACK;
	if (mtfifo)
		cmd[1] |= FM_RDS_STATUS_IN_MTFIFO;

	ret = si47xx_command(2, cmd, 13, rsp);
	if (ret < 0) {
		dev_err(Si47xx_dev->dev, "%s fmRdsStatusfailed %d\n",
				__func__, ret);
		return;
	}

	*RdsFifoUsed = rsp[3];
	rds_data->rdsa      = ((u16)rsp[4] << 8) | (u16)rsp[5];
	rds_data->rdsb      = ((u16)rsp[6] << 8) | (u16)rsp[7];
	rds_data->rdsc      = ((u16)rsp[8] << 8) | (u16)rsp[9];
	rds_data->rdsd      = ((u16)rsp[10] << 8) | (u16)rsp[11];
	rds_data->blera = (rsp[12] & FM_RDS_STATUS_OUT_BLEA) >>
		FM_RDS_STATUS_OUT_BLEA_SHFT;
	rds_data->blerb        = (rsp[12] & FM_RDS_STATUS_OUT_BLEB) >>
		FM_RDS_STATUS_OUT_BLEB_SHFT;
	rds_data->blerc        = (rsp[12] & FM_RDS_STATUS_OUT_BLEC) >>
		FM_RDS_STATUS_OUT_BLEC_SHFT;
	rds_data->blerd        = (rsp[12] & FM_RDS_STATUS_OUT_BLED) >>
		FM_RDS_STATUS_OUT_BLED_SHFT;
}
static int fmTuneStatus(u8 cancel, u8 intack, struct tune_data_t *tune_data)
{
	u8 cmd[8];
	u8 rsp[13];
	int ret;

	cmd[0] = FM_TUNE_STATUS;
	cmd[1] = 0;
	if (cancel)
		cmd[1] |= FM_TUNE_STATUS_IN_CANCEL;
	if (intack)
		cmd[1] |= FM_TUNE_STATUS_IN_INTACK;

	ret = si47xx_command(2, cmd, 8, rsp);

	tune_data->stc    = !!(rsp[0] & STCINT);
	tune_data->bltf   = !!(rsp[1] & FM_TUNE_STATUS_OUT_BTLF);
	tune_data->afcrl  = !!(rsp[1] & FM_TUNE_STATUS_OUT_AFCRL);
	tune_data->valid  = !!(rsp[1] & FM_TUNE_STATUS_OUT_VALID);
	tune_data->freq   = ((u16)rsp[2] << 8) | (u16)rsp[3];
	tune_data->rssi   = rsp[4];
	tune_data->asnr   = rsp[5];
	tune_data->antcap = rsp[7];

	return ret;
}
/*-----------------------------------------------------------------------------
 Helper function that sends the FM_TUNE_FREQ command to the part

 Inputs:
 frequency in 10kHz steps
-----------------------------------------------------------------------------*/
static int fmTuneFreq(u16 frequency)
{
	u8 cmd[8];
	u8 rsp[13];
	int ret;

	cmd[0] = FM_TUNE_FREQ;
	cmd[1] = 0;
	cmd[2] = (u8)(frequency >> 8);
	cmd[3] = (u8)(frequency & 0x00FF);
	cmd[4] = (u8)0;
	ret  = si47xx_command(5, cmd, 1, rsp);

	return ret;
}
/*-----------------------------------------------------------------------------
 Helper function that sends the GET_INT_STATUS command to the part

 Returns:
   The status byte from the part.
-----------------------------------------------------------------------------*/
static s8 getIntStatus(void)
{
	u8 cmd[8];
	u8 rsp[13];
	int ret = 0;
	cmd[0] = GET_INT_STATUS;
	ret = si47xx_command(1, cmd, 1, rsp);

	if (ret < 0) {
		dev_err(Si47xx_dev->dev, "%s getIntStatus failed %d\n",
				__func__, ret);
		return ret;
	}
	return rsp[0];
}
/*-----------------------------------------------------------------------------
 Helper function that sends the FM_SEEK_START command to the part

Inputs:
seekUp: If non-zero seek will increment otherwise decrement
wrap:   If non-zero seek will wrap around band limits when hitting the end
of the band limit.
-----------------------------------------------------------------------------*/
static int fmSeekStart(u8 seekUp, u8 wrap)
{
	u8 cmd[8];
	u8 rsp[13];
	int ret;

	cmd[0] = FM_SEEK_START;
	cmd[1] = 0;
	if (seekUp)
		cmd[1] |= FM_SEEK_START_IN_SEEKUP;
	if (wrap)
		cmd[1] |= FM_SEEK_START_IN_WRAP;

	ret = si47xx_command(2, cmd, 1, rsp);
	return ret;

}
/*-----------------------------------------------------------------------------
 Set the passed property number to the passed value.

 Inputs:
      propNumber:  The number identifying the property to set
      propValue:   The value of the property.
-----------------------------------------------------------------------------*/
static void si47xx_set_property(u16 propNumber, u16 propValue)
{
	u8 cmd[8];
	int ret = 0;

	cmd[0] = SET_PROPERTY;
	cmd[1] = 0;
	cmd[2] = (u8)(propNumber >> 8);
	cmd[3] = (u8)(propNumber & 0x00FF);
	cmd[4] = (u8)(propValue >> 8);
	cmd[5] = (u8)(propValue & 0x00FF);

	ret = si47xx_command(6, cmd, 0, NULL);

	if (ret < 0)
		dev_err(Si47xx_dev->dev,
		"%s si47xx_set_property failed %d\n", __func__, ret);
}
/* -----------------------------------------------------------------------------
 Helper function that sends the FM_RSQ_STATUS command to the part

 Inputs:
  intack: If non-zero the interrupt for STCINT will be cleared.

  Outputs:
  Si47xx_status.Status:  Contains bits about the status returned from the part.
  Si47xx_status.RsqInts: Contains bits about the interrupts
  that have fired related to RSQ.
  SMUTE:   The soft mute function is currently enabled
  AFCRL:   The AFC is railed if this is non-zero
  Valid:   The station is valid if this is non-zero
  Pilot:   A pilot tone is currently present
  Blend:   Percentage of blend for stereo. (100 = full stereo)
  RSSI:    The RSSI level read at tune.
  ASNR:    The audio SNR level read at tune.
  FreqOff: The frequency offset in kHz of the current station
  from the tuned frequency.
-----------------------------------------------------------------------------*/
static void fmRsqStatus(u8 intack, struct rsq_data_t *rsq_data)
{
	u8 cmd[8];
	u8 rsp[13];

	cmd[0] = FM_RSQ_STATUS;
	cmd[1] = 0;

	if (intack)
		cmd[1] |= FM_RSQ_STATUS_IN_INTACK;

	si47xx_command(2, cmd, 8, rsp);

	rsq_data->rsqints = rsp[1];
	rsq_data->smute   = !!(rsp[2] & FM_RSQ_STATUS_OUT_SMUTE);
	rsq_data->afcrl   = !!(rsp[2] & FM_RSQ_STATUS_OUT_AFCRL);
	rsq_data->valid   = !!(rsp[2] & FM_RSQ_STATUS_OUT_VALID);
	rsq_data->pilot   = !!(rsp[3] & FM_RSQ_STATUS_OUT_PILOT);
	rsq_data->blend   = rsp[3] & FM_RSQ_STATUS_OUT_STBLEND;
	rsq_data->rssi    = rsp[4];
	rsq_data->snr    = rsp[5];
	rsq_data->freqoff = rsp[7];
}
static int powerdown(void)
{
	int ret = 0;
	u8 cmd[8];
	u8 rsp[13];

	if (!(RADIO_POWERDOWN == Si47xx_dev->state.power_state)) {
		cmd[0] = POWER_DOWN;
		ret = si47xx_command(1, cmd, 1, rsp);

		if (ret < 0)
			dev_err(Si47xx_dev->dev, "%s failed %d\n",
			__func__, ret);
		else
			Si47xx_dev->state.power_state = RADIO_POWERDOWN;

		msleep(110);
		pSi47xxdata->power(0);
	} else
		debug("Device already Powered-OFF\n");

	return ret;
}
Example #10
0
bit configSetStartupConfig()
{
	byte commands = 0;
	byte index;
	word addr;

	wait_ms(5);

	i2cFlag = I2C_READ | I2C_START | I2C_STOP | I2C_WORD_ADDR_TYPE;
	SET_I2C(EEPROM_I2C_ADDR, TX_CONFIG_OFFSET+CONF_NUM_CMDS_OFFSEET, &commands, 1, i2cFlag);
	if(!devRomFunction(ROM_I2C_ACCESS))
		return FALSE;
	if(!commands || commands > 62)
		return FALSE;

	wait_ms(5);

	for(index=1; index<=commands; index++) {
		addr = TX_CONFIG_OFFSET+(8*index);
		i2cFlag = I2C_READ | I2C_START | I2C_STOP | I2C_WORD_ADDR_TYPE;
		SET_I2C(EEPROM_I2C_ADDR, addr, &buff_request, 8, i2cFlag);
		if(!devRomFunction(ROM_I2C_ACCESS))
			return FALSE;

		wait_ms(5);

		si47xx_command(8, buff_request, 8, buff_response);
//		if(buff_ret != SI4711_OK)
//			return FALSE;
		/* wait for tSTC and tCOMP */
		switch(buff_request[0]) {
		case TX_TUNE_FREQ:
			wait_ms(100);
			break;
		case TX_TUNE_POWER:
			wait_ms(20);
			if(buff_request[3] >= 88) {
				TxPoweredUp = TRUE;
			} else {
				TXLed = LED_OFF;
				TxPoweredUp = FALSE;
				ASQLOWLed = LED_OFF;
				ASQHILed = LED_OFF;
				ASQOVRMLed = LED_OFF;
			}
			break;
		case SET_PROPERTY:
			wait_ms(10);
			if(buff_request[2] == 0x21 &&
			   buff_request[3] == 0x01) {
				DeviationValueThatSet = MAKE_WORD(buff_request[4], buff_request[5]);
				DeviationValueCounted = DeviationValueThatSet;
			}
			break;
		default:
			wait_ms(5);
			break;
		}
	}
	//set audio config after it!
	si47xxSetAudio(TRUE);
//	if(buff_ret != SI4711_OK)
//		return FALSE;
	return TRUE;
}
Example #11
0
void READ_ASQ_STATUS()
{
	byte status=0;
	//bit old_val;
	if(!FePoweredUp)
		return;

	asq_delayed++;
	if(asq_delayed < 10000)
		return;

	asq_delayed=0;
	FELed = !FELed;

	buff_request[0] = GET_INT_STATUS;

	si47xx_command(1, buff_request, 1, &status);
	if(!(status & CTS) || (status & ERR)) {
		FELed = !FELed;
		return;
	}

	if(status & STCINT) {
		buff_request[0] = TX_TUNE_STATUS;
		buff_request[1] = TX_TUNE_STATUS_IN_INTACK;
		si47xx_command(2, buff_request, 7, buff_response);
		if(!(buff_response[0] & CTS) || (buff_response[0] & ERR)) {
			FELed = !FELed;
			return;
		}

		TxFreq = MAKE_WORD(buff_response[2],buff_response[3]);
		TxPower = buff_response[5];
		TxAntCap = buff_response[6];
		TxRnl = buff_response[7];
		if(TxFreq && TxPower)
			TXLed = LED_ON;
		else
			TXLed = LED_OFF;
	}

	if(!TxPoweredUp)
		return;

	buff_request[0] = TX_ASQ_STATUS;
	/* if interrupt, then clean counters,
     * in other case, just read current level */
	if(status & ASQINT)
		buff_request[1] = TX_ASQ_STATUS_IN_INTACK;
	else
		buff_request[1] = 0x00;

	si47xx_command(2, buff_request, 5, buff_response);
	if(!(buff_response[0] & CTS) || (buff_response[0] & ERR)) {
		FELed = !FELed;
		return;
	}

	asq_level = buff_response[4];

	if(status & ASQINT) {
		asq_overmod = buff_response[1] & TX_ASQ_STATUS_OUT_OVERMOD;
		asq_iall = buff_response[1] & TX_ASQ_STATUS_OUT_IALL;
		asq_ialh = buff_response[1] & TX_ASQ_STATUS_OUT_IALH;

		ASQLOWLed = asq_iall ? LED_ON : LED_OFF;
		ASQHILed = asq_ialh ? LED_ON : LED_OFF;
		ASQOVRMLed = asq_overmod ? LED_ON : LED_OFF;
	}

	//old_val = ASQLOWLed;
	//ASQLOWLed = ASQHILed = ASQOVRMLed = !old_val;

}
Example #12
0
/*===================================================================
IEP3_HID(): Prepare Data to send from SI4711 to PC through IEP3 HID
===================================================================*/
void HID_ACCESS()
{
#ifdef _HID_
    if ( (PCCommand == PCTransfer) && !(PCRequest&RequestDone) ) {
        switch (PCRequest) {
			case(RequestSi4711Reset):
				//bReportOut:
				//  +-----------+-----------+
				//  | PCCommand | PCRequest |
				//  +-----------+-----------+
				si47xxReset();
				break;
			case(RequestCpuId):
				//  +-----------+-----------+--------------+----------+-------------+----------+---------------+
				//  | PCCommand | PCRequest | REV_MINOR[2] | STR_SIZE | REV_MAJOR[] | STR_SIZE | DEVICE_NAME[] |
				//  +-----------+-----------+--------------+----------+-------------+----------+---------------+
				Xdata.InEp3.HidReport.bReportItem[2] = (0xFF00 & REVISION_MAJOR) >> 8;
				Xdata.InEp3.HidReport.bReportItem[3] = 0x00FF & REVISION_MAJOR;
				Xdata.InEp3.HidReport.bReportItem[4] = sizeof(REVISION_MINOR);
				AppDevice.dummy.bData[0] = 0;
				for(AppDevice.dummy.bData[0] = 0;
					AppDevice.dummy.bData[0] < sizeof(REVISION_MINOR);
						AppDevice.dummy.bData[0]++)
					Xdata.InEp3.HidReport.bReportItem[5 + AppDevice.dummy.bData[0]] =
							 REVISION_MINOR[AppDevice.dummy.bData[0]];

 			    Xdata.InEp3.HidReport.bReportItem[5 + AppDevice.dummy.bData[0]] = sizeof(DEVICE_NAME);
				AppDevice.dummy.bData[1] = AppDevice.dummy.bData[0] + 5 + 1;

				for(AppDevice.dummy.bData[0] = 0;
					AppDevice.dummy.bData[0] < sizeof(DEVICE_NAME);
						AppDevice.dummy.bData[0]++)
					Xdata.InEp3.HidReport.bReportItem[AppDevice.dummy.bData[1] + AppDevice.dummy.bData[0]] =
							 DEVICE_NAME[AppDevice.dummy.bData[0]];
				break;
			case(RequestSi4711PowerStatus):
				//  +-----------+-----------+-------------+----------------+
				//  | PCCommand | PCRequest | IsPoweredUp | IsTransmitting |
				//  +-----------+-----------+-------------+----------------+
				Xdata.InEp3.HidReport.bReportItem[2] = FePoweredUp;
				Xdata.InEp3.HidReport.bReportItem[3] = TxPoweredUp;
				break;
			case(RequestSi4711PowerUp):
				if(FePoweredUp) {
					PCCommand |= PCRequestError;
					break;
				} else {
					FePoweredUp=TRUE;
				}
				//bReportOut:
				//  +-----------+-----------+---------+-----------+
				//  | PCCommand | PCRequest | IsError | ErrorCode |
				//  +-----------+-----------+---------+-----------+
				buff_ret = SI4711_COMM_ERR;
				Xdata.InEp3.HidReport.bReportItem[3] = 1;
				si47xxPowerUp();
				if(!(buff_response[0] & CTS)) {
					Xdata.InEp3.HidReport.bReportItem[2] = buff_ret;
					break;
				}

				buff_ret = SI4711_COMM_ERR;
				Xdata.InEp3.HidReport.bReportItem[3] = 2;
				si47xxFMTX_hardware_cfg();
				Xdata.InEp3.HidReport.bReportItem[2] = buff_ret;
				FELed = LED_ON;
				break;
			case(RequestSi4711PowerDown):
				if(!FePoweredUp) {
					PCCommand |= PCRequestError;
					break;
				}
				//bReportOut:
				//  +-----------+-----------+---------+-----------+
				//  | PCCommand | PCRequest | IsError | ErrorCode |
				//  +-----------+-----------+---------+-----------+
				buff_ret = SI4711_COMM_ERR;
				si47xxPowerDown();
				if(buff_ret != SI4711_OK || !(buff_response[0] & CTS)) {
					Xdata.InEp3.HidReport.bReportItem[2] = buff_ret;
					si47xxReset(); //force!
				}

				break;
			case(RequestSi4711AudioEnable):
				if(!FePoweredUp) {
					PCCommand |= PCRequestError;
					break;
				}
				buff_ret = SI4711_COMM_ERR;
				si47xxSetAudio(TRUE);
				Xdata.InEp3.HidReport.bReportItem[2] = buff_ret;
				break;
			case(RequestSi4711AudioDisable):
				if(!FePoweredUp) {
					PCCommand |= PCRequestError;
					break;
				}
				buff_ret = SI4711_COMM_ERR;
				si47xxSetAudio(FALSE);
				Xdata.InEp3.HidReport.bReportItem[2] = buff_ret;
				break;
			case(RequestEepromSectionRead):
				//bReportOut:
				//  +-----------+-----------+---------+-------+
				//  | PCCommand | PCRequest | Offset  | bytes |
				//  +-----------+-----------+---------+-------+
				if(Xdata.OutEp4.HidOReport.bReportOut[4] > 32) {
					PCCommand |= PCRequestError;
					break;
				}
				AppDevice.dummy.wData[0] =
					MAKE_WORD(Xdata.OutEp4.HidOReport.bReportOut[2], Xdata.OutEp4.HidOReport.bReportOut[3]);
				if(AppDevice.dummy.wData[0] + Xdata.OutEp4.HidOReport.bReportOut[4] > 0x2000) {
					PCCommand |= PCRequestError;
					break;
				}

				i2cFlag = I2C_READ | I2C_START | I2C_STOP | I2C_WORD_ADDR_TYPE;
				SET_I2C(EEPROM_I2C_ADDR, AppDevice.dummy.wData[0],
						&Xdata.InEp3.HidReport.bReportItem[3],
						 Xdata.OutEp4.HidOReport.bReportOut[4], i2cFlag);

				Xdata.InEp3.HidReport.bReportItem[2] = devRomFunction(ROM_I2C_ACCESS);
				//bReportItem:
				//  +-----------+-----------+--------+---------+- ... -+---------+
				//  | PCCommand | PCRequest | status | data[0] |  ...  | data[n] |
				//  +-----------+-----------+--------+---------+- ... -+---------+
				break;
			case(RequestEepromSectionWrite):
				//bReportOut:
				//  +-----------+-----------+---------+-------+---------+- ... -+---------+
				//  | PCCommand | PCRequest | Offset  | bytes | data[0] |  ...  | data[n] |
				//  +-----------+-----------+---------+-------+---------+- ... -+---------+
				if(Xdata.OutEp4.HidOReport.bReportOut[4] > 32) {
					PCCommand |= PCRequestError;
					break;
				}
				AppDevice.dummy.wData[0] =
					MAKE_WORD(Xdata.OutEp4.HidOReport.bReportOut[2], Xdata.OutEp4.HidOReport.bReportOut[3]);
			    if(AppDevice.dummy.wData[0] + Xdata.OutEp4.HidOReport.bReportOut[4] > 0x2000) {
					PCCommand |= PCRequestError;
					break;
				}

				i2cFlag = I2C_WRITE | I2C_START | I2C_STOP | I2C_WORD_ADDR_TYPE;
				SET_I2C(EEPROM_I2C_ADDR, AppDevice.dummy.wData[0],
						&Xdata.OutEp4.HidOReport.bReportOut[5],
						 Xdata.OutEp4.HidOReport.bReportOut[4], i2cFlag);

				Xdata.InEp3.HidReport.bReportItem[2] = devRomFunction(ROM_I2C_ACCESS);
				//bReportItem:
				//  +-----------+-----------+--------+
				//  | PCCommand | PCRequest | status |
				//  +-----------+-----------+--------+
				break;
			case(RequestSi4711SetProp):
				if(!FePoweredUp) {
					PCCommand |= PCRequestError;
					break;
				}
				//bReportOut:
				//  +-----------+-----------+---------+
				//  | PCCommand | PCRequest | IsError |
				//  +-----------+-----------+---------+
				//reversal order here
				AppDevice.dummy.wData[0] =
					MAKE_WORD(Xdata.OutEp4.HidOReport.bReportOut[2], Xdata.OutEp4.HidOReport.bReportOut[3]);

				//must set other way
				if(AppDevice.dummy.wData[0] == REFCLK_PRESCALE ||
					AppDevice.dummy.wData[0] == REFCLK_FREQ ||
					AppDevice.dummy.wData[0] == DIGITAL_INPUT_FORMAT ||
					AppDevice.dummy.wData[0] == DIGITAL_INPUT_SAMPLE_RATE ||
					AppDevice.dummy.wData[0] == GPO_IEN) {
					Xdata.InEp3.HidReport.bReportItem[2] = SI4711_BAD_ARG;
					PCCommand |= PCRequestError;
					break;
				}

				AppDevice.dummy.wData[1] =
					MAKE_WORD(Xdata.OutEp4.HidOReport.bReportOut[4], Xdata.OutEp4.HidOReport.bReportOut[5]);

				buff_ret = SI4711_COMM_ERR;
				Xdata.InEp3.HidReport.bReportItem[6] =
							si47xx_set_property(AppDevice.dummy.wData[0], AppDevice.dummy.wData[1]);
				Xdata.InEp3.HidReport.bReportItem[7] = buff_response[0];
				Xdata.InEp3.HidReport.bReportItem[8] = buff_ret;

				Xdata.InEp3.HidReport.bReportItem[2] = Xdata.OutEp4.HidOReport.bReportOut[2];
				Xdata.InEp3.HidReport.bReportItem[3] = Xdata.OutEp4.HidOReport.bReportOut[3];
				Xdata.InEp3.HidReport.bReportItem[4] = Xdata.OutEp4.HidOReport.bReportOut[4];
				Xdata.InEp3.HidReport.bReportItem[5] = Xdata.OutEp4.HidOReport.bReportOut[5];


				// hack for set volume
				if(AppDevice.dummy.wData[0] == TX_AUDIO_DEVIATION) {
						DeviationValueThatSet = AppDevice.dummy.wData[1];
						coSpkUpdate();
				}

				//bReportOut:
				//  +-----------+-----------+---------+------------+------+------+
				//  | PCCommand | PCRequest | IsError | IsErrorGet | ValH | ValL |
				//  +-----------+-----------+---------+------------+------+------+
#ifndef _PROP_RECHECK_ //re-check out property!
				AppDevice.dummy.wData[1] = 0;
				break;
#endif
			case(RequestSi4711GetProp):
				if(!FePoweredUp) {
					PCCommand |= PCRequestError;
					break;
				}

				//bReportOut:
				//  +-----------+-----------+---------+
				//  | PCCommand | PCRequest | IsError |
				//  +-----------+-----------+---------+
				AppDevice.dummy.wData[0] =
					MAKE_WORD(Xdata.OutEp4.HidOReport.bReportOut[2], Xdata.OutEp4.HidOReport.bReportOut[3]);
				AppDevice.dummy.wData[1] = 0;
				buff_ret = SI4711_COMM_ERR;
				Xdata.InEp3.HidReport.bReportItem[6] =
						si47xx_get_property(AppDevice.dummy.wData[0], &AppDevice.dummy.wData[1]);
				Xdata.InEp3.HidReport.bReportItem[7] = buff_response[0];
				Xdata.InEp3.HidReport.bReportItem[8] = buff_ret;

				Xdata.InEp3.HidReport.bReportItem[2] = Xdata.OutEp4.HidOReport.bReportOut[2];
				Xdata.InEp3.HidReport.bReportItem[3] = Xdata.OutEp4.HidOReport.bReportOut[3];
				Xdata.InEp3.HidReport.bReportItem[4] = MSB(AppDevice.dummy.wData[1]);
				Xdata.InEp3.HidReport.bReportItem[5] = LSB(AppDevice.dummy.wData[1]);
				break;

			case(RequestSi4711Access):
				if(!FePoweredUp) {
					PCCommand |= PCRequestError;
					break;
				}

				Xdata.InEp3.HidReport.bReportItem[2] = 0;
				Xdata.InEp3.HidReport.bReportItem[3] = 0;
				Xdata.InEp3.HidReport.bReportItem[4] = 0;
				
				if(Xdata.OutEp4.HidOReport.bReportOut[2] < 1) {
					PCCommand |= PCRequestError;
					Xdata.InEp3.HidReport.bReportItem[2] = FALSE;
					Xdata.InEp3.HidReport.bReportItem[3] = SI4711_BAD_ARG;
					break;
				}


				//bReportOut:
				//  +-----------+-----------+---------+---------+--------+- ... -+--------+
				//  | PCCommand | PCRequest | ArgsLen | Command | Arg[1] |  ...  | Arg[7] |
				//  +-----------+-----------+---------+---------+--------+- ... -+--------+
//bReportItem:
//  +-----------+-----------+-------------+------------+---------+---------+---------+ ... -+----------+
//  | PCCommand | PCRequest | WriteStatus | ReadStatus | RespLen |  Status | Resp[1] | ...  | Resp[15] |
//  +-----------+-----------+-------------+------------+---------+---------+---------+ ... -+----------+

				//do it other way!
				if(Xdata.OutEp4.HidOReport.bReportOut[3] == POWER_UP ||
				   Xdata.OutEp4.HidOReport.bReportOut[3] == POWER_DOWN ||
				   Xdata.OutEp4.HidOReport.bReportOut[3] == TX_ASQ_STATUS ||
				   Xdata.OutEp4.HidOReport.bReportOut[3] == TX_TUNE_STATUS ||
				   Xdata.OutEp4.HidOReport.bReportOut[3] == SET_PROPERTY ||
				   Xdata.OutEp4.HidOReport.bReportOut[3] == GET_PROPERTY ) {
					Xdata.InEp3.HidReport.bReportItem[2] = FALSE;
					Xdata.InEp3.HidReport.bReportItem[3] = SI4711_BAD_ARG;
					break;
				}

				/* Write command */
				Xdata.InEp3.HidReport.bReportItem[4] = 16; // RespLen
				buff_ret = SI4711_COMM_ERR;
				Xdata.InEp3.HidReport.bReportItem[2] = si47xx_command(Xdata.OutEp4.HidOReport.bReportOut[2], &Xdata.OutEp4.HidOReport.bReportOut[3],
								Xdata.InEp3.HidReport.bReportItem[4], &Xdata.InEp3.HidReport.bReportItem[5]);
				 
				Xdata.InEp3.HidReport.bReportItem[3] = buff_ret;
				
				/* Set specific delay, depends on what command sent. */
				if(Xdata.OutEp4.HidOReport.bReportOut[3] == TX_TUNE_POWER) {
					if(Xdata.OutEp4.HidOReport.bReportOut[6] >= 88) {
						TxPoweredUp = TRUE;
					} else {
//						TXLed = LED_OFF;
						TxPoweredUp = FALSE;
						ASQLOWLed = LED_OFF;
						ASQHILed = LED_OFF;
						ASQOVRMLed = LED_OFF;
					}
				}

				Xdata.InEp3.HidReport.bReportItem[21] = AppDevice.spk.preVol[DEV_SPK_LEFT_CN];
				Xdata.InEp3.HidReport.bReportItem[22] = AppDevice.spk.preVol[DEV_SPK_RIGHT_CN];
				Xdata.InEp3.HidReport.bReportItem[23] = MSB(DeviationValueCounted);
				Xdata.InEp3.HidReport.bReportItem[24] = LSB(DeviationValueCounted);
				break;
			case(RequestSi4711AsqStatus):
				if(!FePoweredUp || !TxPoweredUp) {
					PCCommand |= PCRequestError;
					break;
				}
				//bReportOut:
				//  +-----------+-----------+---------+---------+------+------+-------+
				//  | PCCommand | PCRequest | IsError | overmod | iall | ialh | level |
				//  +-----------+-----------+---------+---------+------+------+-------+
				Xdata.InEp3.HidReport.bReportItem[2] = 0x00;
				Xdata.InEp3.HidReport.bReportItem[3] = asq_overmod;
				Xdata.InEp3.HidReport.bReportItem[4] = asq_iall;
				Xdata.InEp3.HidReport.bReportItem[5] = asq_ialh;
				Xdata.InEp3.HidReport.bReportItem[6] = asq_level;
				break;
			case(RequestSi4711TuneStatus):
				if(!FePoweredUp) {
					PCCommand |= PCRequestError;
					break;
				}
				//bReportOut:
				//  +-----------+-----------+---------+---------+---------+-------+--------+-----+
				//  | PCCommand | PCRequest | IsError | FREQ[m] | FREQ[l] | power | antcap | rnl |
				//  +-----------+-----------+---------+---------+---------+-------+--------+-----+
				Xdata.InEp3.HidReport.bReportItem[2] = 0x00;
				Xdata.InEp3.HidReport.bReportItem[3] = MSB(TxFreq);
				Xdata.InEp3.HidReport.bReportItem[4] = LSB(TxFreq);
				Xdata.InEp3.HidReport.bReportItem[5] = TxPower;
				Xdata.InEp3.HidReport.bReportItem[6] = TxAntCap;
				Xdata.InEp3.HidReport.bReportItem[7] = TxRnl;
				break;
            default:
                PCCommand |= PCRequestError; 
                break;
        }
        // send data to PC through USP HID
        PCRequest |= RequestDone;
        Xdata.InEp3.HidReport.bReportItem[0] = PCCommand;
        Xdata.InEp3.HidReport.bReportItem[1] = PCRequest;
        while (!(IEPDCNTX3&0x80));
        IEPDCNTX3 = sizeof(Xdata.InEp3.HidReport);
    }
#endif
}