diff --git a/src/add-ons/kernel/drivers/network/Jamfile b/src/add-ons/kernel/drivers/network/Jamfile index a7d3ef3129..b03a8e80a3 100644 --- a/src/add-ons/kernel/drivers/network/Jamfile +++ b/src/add-ons/kernel/drivers/network/Jamfile @@ -36,3 +36,5 @@ SubIncludeGPL HAIKU_TOP src add-ons kernel drivers network bcm570x ; SubInclude HAIKU_TOP src add-ons kernel drivers network atheros813x ; SubInclude HAIKU_TOP src add-ons kernel drivers network wlan ; + +SubInclude HAIKU_TOP src add-ons kernel drivers network wimax ; diff --git a/src/add-ons/kernel/drivers/network/wimax/Jamfile b/src/add-ons/kernel/drivers/network/wimax/Jamfile new file mode 100644 index 0000000000..bf1e599f49 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/Jamfile @@ -0,0 +1,3 @@ +SubDir HAIKU_TOP src add-ons kernel drivers network wimax ; + +SubInclude HAIKU_TOP src add-ons kernel drivers network wimax usb_beceem ; diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemCPU.cpp b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemCPU.cpp new file mode 100644 index 0000000000..b68ec3e444 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemCPU.cpp @@ -0,0 +1,156 @@ +/* + * Beceem WiMax USB Driver. + * Copyright (c) 2010 Alexander von Gluck + * Distributed under the terms of the MIT license. + * + * Based on GPL code developed by: Beceem Communications Pvt. Ltd + * + * Control the MIPS cpu within the Beceem chipset. + * + */ + +#include "Settings.h" +#include "BeceemCPU.h" + +#include "Driver.h" + +BeceemCPU::BeceemCPU() +{ + TRACE("Debug: Load CPU handler\n"); +} + + +status_t +BeceemCPU::CPUInit(WIMAX_DEVICE* swmxdevice) +{ + TRACE("Debug: Init CPU handler\n"); + pwmxdevice = swmxdevice; + return B_OK; +} + + +status_t +BeceemCPU::CPURun() +{ + unsigned int value = 0; + + if (BizarroReadRegister(CLOCK_RESET_CNTRL_REG_1, sizeof(value), &value) + != B_OK) { + + TRACE_ALWAYS("Error: Read of clock reset reg failure\n"); + return B_ERROR; + } + + if (pwmxdevice->CPUFlashBoot) { + value&=(~(1<<30)); + } else { + value |=(1<<30); + } + + if (BizarroWriteRegister(CLOCK_RESET_CNTRL_REG_1, sizeof(value), &value) + != B_OK) { + + TRACE_ALWAYS("Error: Write of clock reset reg failure\n"); + return B_ERROR; + } + + return B_OK; +} + + +status_t +BeceemCPU::CPUReset() +{ + status_t retval = B_OK; + unsigned int value = 0; + unsigned int uiResetValue = 0; + + if (pwmxdevice->deviceChipID >= T3LPB) + { + BizarroReadRegister(SYS_CFG, sizeof(value), &value); + BizarroReadRegister(SYS_CFG, sizeof(value), &value); + // SYS_CFG register is write protected hence for modifying + // this reg value, it should be read twice before writing. + + value = value | (pwmxdevice->syscfgBefFw & 0x00000060) ; + // making bit[6...5] same as was before f/w download. this + // setting forces the h/w to re-populated the SP RAM area + // with the string descriptor . + + BizarroWriteRegister(SYS_CFG, sizeof(value), &value); + } + + /* Reset the UMA-B Device */ + if (pwmxdevice->deviceChipID >= T3LPB) + { + // TRACE("Debug: Resetting UMA-B\n"); + // retval = usb_reset_device(psIntfAdapter->udev); + + if (retval != B_OK) + { + TRACE_ALWAYS("Error: Reset failed\n"); + goto err_exit; + } + if (pwmxdevice->deviceChipID == BCS220_2 || + pwmxdevice->deviceChipID == BCS220_2BC || + pwmxdevice->deviceChipID == BCS250_BC || + pwmxdevice->deviceChipID == BCS220_3) + { + retval = BizarroReadRegister(HPM_CONFIG_LDO145, + sizeof(value), &value); + + if ( retval < 0) + { + TRACE_ALWAYS("Error: read failed with status: %d\n", retval); + goto err_exit; + } + // setting 0th bit + value |= (1<<0); + retval = BizarroWriteRegister(HPM_CONFIG_LDO145, + sizeof(value), &value); + + if ( retval < 0) + { + TRACE_ALWAYS("Error: write failed with status: %d\n", retval); + goto err_exit; + } + } + + } + // TODO : ELSE OLDER CHIP ID's < T3LP see Misc.c:1048 + + if (pwmxdevice->CPUFlashBoot) + { + // In flash boot mode MIPS state register has reverse polarity. + // So just or with setting bit 30. + // Make the MIPS in Reset state. + BizarroReadRegister(CLOCK_RESET_CNTRL_REG_1, sizeof(uiResetValue), + &uiResetValue); + + uiResetValue |=(1<<30); + BizarroWriteRegister(CLOCK_RESET_CNTRL_REG_1, sizeof(uiResetValue), + &uiResetValue); + } + + if (pwmxdevice->deviceChipID >= T3LPB) + { + uiResetValue = 0; + // WA for SYSConfig Issue. + BizarroReadRegister(SYS_CFG, sizeof(uiResetValue), &uiResetValue); + if (uiResetValue & (1<<4)) + { + uiResetValue = 0; + BizarroReadRegister(SYS_CFG, sizeof(uiResetValue), &uiResetValue); + // Read SYSCFG Twice to make it writable. + uiResetValue &= (~(1<<4)); + BizarroWriteRegister(SYS_CFG, sizeof(uiResetValue), &uiResetValue); + } + + } + uiResetValue = 0; + BizarroWriteRegister(0x0f01186c, sizeof(uiResetValue), &uiResetValue); + + err_exit : + return retval; +} + diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemCPU.h b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemCPU.h new file mode 100644 index 0000000000..508e1d387b --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemCPU.h @@ -0,0 +1,39 @@ +/* + * Beceem WiMax USB Driver. + * Copyright (c) 2010 Alexander von Gluck + * Distributed under the terms of the MIT license. + * + * Based on GPL code developed by: Beceem Communications Pvt. Ltd + * + * Description: Wrangle Beceem CPU control calls + */ + +#define CLOCK_RESET_CNTRL_REG_1 0x0F00000C + +#ifndef _USB_BECEEM_CPU_H_ +#define _USB_BECEEM_CPU_H_ + +#include +#include "DeviceStruct.h" + +class BeceemCPU +{ + +public: + BeceemCPU(); + status_t CPUInit(WIMAX_DEVICE* swmxdevice); + status_t CPURun(); + status_t CPUReset(); + +// yuck. These are in a parent class +virtual status_t ReadRegister(unsigned int reg, size_t size, uint32_t* buffer){ return NULL; }; +virtual status_t WriteRegister(unsigned int reg, size_t size, uint32_t* buffer){ return NULL; }; +virtual status_t BizarroReadRegister(unsigned int reg, size_t size, uint32_t* buffer){ return NULL; }; +virtual status_t BizarroWriteRegister(unsigned int reg, size_t size, uint32_t* buffer){ return NULL; }; + +private: + WIMAX_DEVICE* pwmxdevice; + +}; +#endif // _USB_BECEEM_CPU_H_ + diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemDDR.cpp b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemDDR.cpp new file mode 100644 index 0000000000..6beffb74e6 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemDDR.cpp @@ -0,0 +1,411 @@ +/* + * Beceem WiMax USB Driver. + * Copyright (c) 2010 Alexander von Gluck + * Distributed under the terms of the MIT license. + * + * Based on GPL code developed by: Beceem Communications Pvt. Ltd + * + * Description: Wrangle Beceem volatile DDR memory. + */ + +#include "Settings.h" +#include "BeceemDDR.h" + +BeceemDDR::BeceemDDR() +{ + TRACE("Debug: Load DDR handler\n"); +} + +status_t +BeceemDDR::DDRInit(WIMAX_DEVICE* swmxdevice) +{ + pwmxdevice = swmxdevice; + PDDR_SETTING psDDRSetting=NULL; + + unsigned int HostDrvrConfig6 = pwmxdevice->vendorcfg.HostDrvrConfig6; + unsigned int uiHostDrvrCfg6 = 0; + unsigned int ChipID = pwmxdevice->deviceChipID; + + unsigned long RegCount=0; + unsigned long value = 0; + unsigned int uiResetValue = 0; + unsigned int uiClockSetting = 0; + int retval = B_OK; + + unsigned int DDRSetting = 0; + bool PmuMode = 0; + bool MipsConfig = 0; + bool PLLConfig = 0; + + HostDrvrConfig6 &= ~(htonl(1 << 15)); + uiHostDrvrCfg6 = ntohl(HostDrvrConfig6); + + DDRSetting = (ntohl(HostDrvrConfig6) >>8)&0x0F ; + PmuMode = (uiHostDrvrCfg6>>24)&0x03; + MipsConfig = (uiHostDrvrCfg6>>20)&0x01; + PLLConfig = (uiHostDrvrCfg6>>19)&0x01; + + switch (ChipID) + { + case 0xbece3200: + switch (DDRSetting) + { + case DDR_80_MHZ: + psDDRSetting=asT3LP_DDRSetting80MHz; + RegCount=(sizeof(asT3LP_DDRSetting80MHz)/ + sizeof(DDR_SETTING)); + break; + case DDR_100_MHZ: + psDDRSetting=asT3LP_DDRSetting100MHz; + RegCount=(sizeof(asT3LP_DDRSetting100MHz)/ + sizeof(DDR_SETTING)); + break; + case DDR_133_MHZ: + psDDRSetting=asT3LP_DDRSetting133MHz; + RegCount=(sizeof(asT3LP_DDRSetting133MHz)/ + sizeof(DDR_SETTING)); + if(MipsConfig == MIPS_200_MHZ) + { + uiClockSetting = 0x03F13652; + } + else + { + uiClockSetting = 0x03F1365B; + } + break; + default: + return -EINVAL; + } + + break; + case T3LPB: + case BCS220_2: + case BCS220_2BC: + case BCS250_BC: + case BCS220_3 : + // We need to check current value and additionally set bit 2 and + // bit 6 to 1 for BBIC 2mA drive + if( (ChipID != BCS220_2) && + (ChipID != BCS220_2BC) && + (ChipID != BCS220_3) ) + { + retval= BizarroReadRegister((unsigned int)0x0f000830, + sizeof(uiResetValue), &uiResetValue); + + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroReadRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + uiResetValue |= 0x44; + retval = BizarroWriteRegister((unsigned int)0x0f000830, + sizeof(uiResetValue), &uiResetValue); + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroWriteRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + } + switch(DDRSetting) + { + case DDR_80_MHZ: + TRACE("Debug: DDR 80MHz\n"); + psDDRSetting = asT3LPB_DDRSetting80MHz; + RegCount=(sizeof(asT3B_DDRSetting80MHz)/ + sizeof(DDR_SETTING)); + break; + case DDR_100_MHZ: + TRACE("Debug: DDR 100MHz\n"); + psDDRSetting=asT3LPB_DDRSetting100MHz; + RegCount=(sizeof(asT3B_DDRSetting100MHz)/ + sizeof(DDR_SETTING)); + break; + case DDR_133_MHZ: + TRACE("Debug: DDR 133MHz\n"); + psDDRSetting = asT3LPB_DDRSetting133MHz; + RegCount=(sizeof(asT3B_DDRSetting133MHz)/ + sizeof(DDR_SETTING)); + + if(MipsConfig == MIPS_200_MHZ) + { + uiClockSetting = 0x03F13652; + } + else + { + uiClockSetting = 0x03F1365B; + } + break; + + case DDR_160_MHZ: + TRACE("Debug: DDR 160MHz\n"); + psDDRSetting = asT3LPB_DDRSetting160MHz; + RegCount = sizeof(asT3LPB_DDRSetting160MHz)/sizeof(DDR_SETTING); + + if(MipsConfig == MIPS_200_MHZ) + { + TRACE("Debug: MIPS 200Mhz\n"); + uiClockSetting = 0x03F137D2; + } + else + { + uiClockSetting = 0x03F137DB; + } + } + break; + + case 0xbece0110: + case 0xbece0120: + case 0xbece0121: + case 0xbece0130: + case 0xbece0300: + switch (DDRSetting) + { + case DDR_80_MHZ: + psDDRSetting = asT3_DDRSetting80MHz; + RegCount = (sizeof(asT3_DDRSetting80MHz)/ + sizeof(DDR_SETTING)); + break; + case DDR_100_MHZ: + psDDRSetting = asT3_DDRSetting100MHz; + RegCount = (sizeof(asT3_DDRSetting100MHz)/ + sizeof(DDR_SETTING)); + break; + case DDR_133_MHZ: + psDDRSetting = asT3_DDRSetting133MHz; + RegCount = (sizeof(asT3_DDRSetting133MHz)/ + sizeof(DDR_SETTING)); + break; + default: + return -EINVAL; + } + case 0xbece0310: + { + switch (DDRSetting) + { + case DDR_80_MHZ: + psDDRSetting = asT3B_DDRSetting80MHz; + RegCount=(sizeof(asT3B_DDRSetting80MHz)/ + sizeof(DDR_SETTING)); + break; + case DDR_100_MHZ: + psDDRSetting=asT3B_DDRSetting100MHz; + RegCount=(sizeof(asT3B_DDRSetting100MHz)/ + sizeof(DDR_SETTING)); + break; + case DDR_133_MHZ: + + if(PLLConfig == PLL_266_MHZ)//266Mhz PLL selected. + { + memcpy(asT3B_DDRSetting133MHz, asDPLL_266MHZ, + sizeof(asDPLL_266MHZ)); + psDDRSetting = asT3B_DDRSetting133MHz; + RegCount=(sizeof(asT3B_DDRSetting133MHz)/ + sizeof(DDR_SETTING)); + } + else + { + psDDRSetting = asT3B_DDRSetting133MHz; + RegCount=(sizeof(asT3B_DDRSetting133MHz)/ + sizeof(DDR_SETTING)); + if(MipsConfig == MIPS_200_MHZ) + { + uiClockSetting = 0x07F13652; + } + else + { + uiClockSetting = 0x07F1365B; + } + } + break; + default: + return -EINVAL; + } + break; + + } + default: + return -EINVAL; + } + + value=0; + TRACE("Debug: Register count is %lu\n", RegCount); + while(RegCount && !retval) + { + if(uiClockSetting && psDDRSetting->ulRegAddress == MIPS_CLOCK_REG) + { + value = uiClockSetting; + } + else + { + value = psDDRSetting->ulRegValue; + } + retval = BizarroWriteRegister(psDDRSetting->ulRegAddress, + sizeof(value), (unsigned int*)&value); + + if(B_OK != retval) { + TRACE_ALWAYS( + "%s:%d BizarroWriteRegister failed at 0x%x on Register #%d.\n", + __FUNCTION__, __LINE__, psDDRSetting->ulRegAddress, RegCount); + break; + } + + RegCount--; + psDDRSetting++; + } + + if(ChipID >= 0xbece3300 ) + { + snooze(3); + if( (ChipID != BCS220_2)&& + (ChipID != BCS220_2BC)&& + (ChipID != BCS220_3)) + { + /* drive MDDR to half in case of UMA-B: */ + uiResetValue = 0x01010001; + retval = BizarroWriteRegister((unsigned int)0x0F007018, + sizeof(uiResetValue), &uiResetValue); + + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroWriteRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + uiResetValue = 0x00040020; + retval = BizarroWriteRegister((unsigned int)0x0F007094, + sizeof(uiResetValue), &uiResetValue); + + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroWriteRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + uiResetValue = 0x01020101; + retval = BizarroWriteRegister((unsigned int)0x0F00701c, + sizeof(uiResetValue), &uiResetValue); + + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroWriteRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + uiResetValue = 0x01010000; + retval = BizarroWriteRegister((unsigned int)0x0F007018, + sizeof(uiResetValue), &uiResetValue); + + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroWriteRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + } + snooze(3); + + /* DC/DC standby change... + * This is to be done only for Hybrid PMU mode. + * with the current h/w there is no way to detect this. + * and since we dont have internal PMU lets do it under + * UMA-B chip id. we will change this when we will have an + * internal PMU. + */ + if(PmuMode == HYBRID_MODE_7C) + { + TRACE("Debug: Hybrid Power Mode 7C\n"); + retval = BizarroReadRegister((unsigned int)0x0f000c00, + sizeof(uiResetValue), &uiResetValue); + + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroReadRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + retval = BizarroReadRegister((unsigned int)0x0f000c00, + sizeof(uiResetValue), &uiResetValue); + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroReadRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + uiResetValue = 0x1322a8; + retval = BizarroWriteRegister((unsigned int)0x0f000d1c, + sizeof(uiResetValue), &uiResetValue); + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroWriteRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + retval = BizarroReadRegister((unsigned int)0x0f000c00, + sizeof(uiResetValue), &uiResetValue); + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroReadRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + retval = BizarroReadRegister((unsigned int)0x0f000c00, + sizeof(uiResetValue), &uiResetValue); + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroReadRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + uiResetValue = 0x132296; + retval = BizarroWriteRegister((unsigned int)0x0f000d14, + sizeof(uiResetValue), &uiResetValue); + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroWriteRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + } + else if(PmuMode == HYBRID_MODE_6 ) + { + TRACE("Debug: Hybrid Power Mode 6\n"); + retval = BizarroReadRegister((unsigned int)0x0f000c00, + sizeof(uiResetValue), &uiResetValue); + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroReadRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + retval = BizarroReadRegister((unsigned int)0x0f000c00, + sizeof(uiResetValue), &uiResetValue); + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroReadRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + uiResetValue = 0x6003229a; + retval = BizarroWriteRegister((unsigned int)0x0f000d14, + sizeof(uiResetValue), &uiResetValue); + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroWriteRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + retval = BizarroReadRegister((unsigned int)0x0f000c00, + sizeof(uiResetValue), &uiResetValue); + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroReadRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + retval = BizarroReadRegister((unsigned int)0x0f000c00, + sizeof(uiResetValue), &uiResetValue); + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroReadRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + uiResetValue = 0x1322a8; + retval = BizarroWriteRegister((unsigned int)0x0f000d1c, + sizeof(uiResetValue), &uiResetValue); + if(retval < 0) { + TRACE_ALWAYS("%s:%d BizarroWriteRegister failed\n", + __FUNCTION__, __LINE__); + return retval; + } + } + + } + return retval; +} + diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemDDR.h b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemDDR.h new file mode 100644 index 0000000000..2f27ee844a --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemDDR.h @@ -0,0 +1,852 @@ +/* + * Beceem WiMax USB Driver. + * Copyright (c) 2010 Alexander von Gluck + * Distributed under the terms of the MIT license. + * + * Based on GPL code developed by: Beceem Communications Pvt. Ltd + * + * Description: Wrangle Beceem volatile DDR memory. + */ + +#ifndef _USB_BECEEM_DDR_H_ +#define _USB_BECEEM_DDR_H_ + +#include + +#include "DeviceStruct.h" + +#define DDR_DUMP_INTERNAL_DEVICE_MEMORY 0xBFC02B00 +#define MIPS_CLOCK_REG 0x0f000820 + +#define MIPS_200_MHZ 0 +#define MIPS_160_MHZ 1 +#define PLL_800_MHZ 0 +#define PLL_266_MHZ 1 + +#define DDR_80_MHZ 0 +#define DDR_100_MHZ 1 +#define DDR_120_MHZ 2 // Additional Frequency for T3LP +#define DDR_133_MHZ 3 +#define DDR_140_MHZ 4 // Not Used (Reserved for future) +#define DDR_160_MHZ 5 // Additional Frequency for T3LP +#define DDR_180_MHZ 6 // Not Used (Reserved for future) +#define DDR_200_MHZ 7 // Not Used (Reserved for future) + +class BeceemDDR +{ + +public: + WIMAX_DEVICE* pwmxdevice; + + BeceemDDR(); + status_t DDRInit(WIMAX_DEVICE* swmxdevice); + +// yuck. These are in a child class class +virtual status_t ReadRegister(unsigned int reg, size_t size, uint32_t* buffer){ return NULL; }; +virtual status_t WriteRegister(unsigned int reg, size_t size, uint32_t* buffer){ return NULL; }; +virtual status_t BizarroReadRegister(unsigned int reg, size_t size, uint32_t* buffer){ return NULL; }; +virtual status_t BizarroWriteRegister(unsigned int reg, size_t size, uint32_t* buffer){ return NULL; }; + +}; + + +/* + * DDR Power modes + */ +typedef enum ePMU_MODES +{ + HYBRID_MODE_7C = 0, + INTERNAL_MODE_6 = 1, + HYBRID_MODE_6 = 2 +}PMU_MODE; + +/* + * DDR Init maps, taken from Beceem GPL Linux Driver + */ + +typedef struct _DDR_SETTING +{ + unsigned long ulRegAddress; + unsigned long ulRegValue; +}DDR_SETTING, *PDDR_SETTING; +typedef DDR_SETTING DDR_SET_NODE, *PDDR_SET_NODE; + +//DDR INIT-133Mhz +#define T3_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 12 //index for 0x0F007000 +static DDR_SET_NODE asT3_DDRSetting133MHz[]= {// # DPLL Clock Setting + {0x0F000800,0x00007212}, + {0x0f000820,0x07F13FFF}, + {0x0f000810,0x00000F95}, + {0x0f000860,0x00000000}, + {0x0f000880,0x000003DD}, + // Changed source for X-bar and MIPS clock to APLL + {0x0f000840,0x0FFF1B00}, + {0x0f000870,0x00000002}, + {0x0F00a044,0x1fffffff}, + {0x0F00a040,0x1f000000}, + {0x0F00a084,0x1Cffffff}, + {0x0F00a080,0x1C000000}, + {0x0F00a04C,0x0000000C}, + //Memcontroller Default values + {0x0F007000,0x00010001}, + {0x0F007004,0x01010100}, + {0x0F007008,0x01000001}, + {0x0F00700c,0x00000000}, + {0x0F007010,0x01000000}, + {0x0F007014,0x01000100}, + {0x0F007018,0x01000000}, + {0x0F00701c,0x01020001},// POP - 0x00020001 Normal 0x01020001 + {0x0F007020,0x04030107}, //Normal - 0x04030107 POP - 0x05030107 + {0x0F007024,0x02000007}, + {0x0F007028,0x02020202}, + {0x0F00702c,0x0206060a},//ROB- 0x0205050a,//0x0206060a + {0x0F007030,0x05000000}, + {0x0F007034,0x00000003}, + {0x0F007038,0x110a0200},//ROB - 0x110a0200,//0x180a0200,// 0x1f0a0200 + {0x0F00703C,0x02101010},//ROB - 0x02101010,//0x02101018}, + {0x0F007040,0x45751200},//ROB - 0x45751200,//0x450f1200}, + {0x0F007044,0x110a0d00},//ROB - 0x110a0d00//0x111f0d00 + {0x0F007048,0x081b0306}, + {0x0F00704c,0x00000000}, + {0x0F007050,0x0000001c}, + {0x0F007054,0x00000000}, + {0x0F007058,0x00000000}, + {0x0F00705c,0x00000000}, + {0x0F007060,0x0010246c}, + {0x0F007064,0x00000010}, + {0x0F007068,0x00000000}, + {0x0F00706c,0x00000001}, + {0x0F007070,0x00007000}, + {0x0F007074,0x00000000}, + {0x0F007078,0x00000000}, + {0x0F00707C,0x00000000}, + {0x0F007080,0x00000000}, + {0x0F007084,0x00000000}, + //# Enable BW improvement within memory controller + {0x0F007094,0x00000104}, + //# Enable 2 ports within X-bar + {0x0F00A000,0x00000016}, + //# Enable start bit within memory controller + {0x0F007018,0x01010000} + }; +//80Mhz +#define T3_SKIP_CLOCK_PROGRAM_DUMP_80MHZ 10 //index for 0x0F007000 +static DDR_SET_NODE asT3_DDRSetting80MHz[]= {// # DPLL Clock Setting + {0x0f000810,0x00000F95}, + {0x0f000820,0x07f1ffff}, + {0x0f000860,0x00000000}, + {0x0f000880,0x000003DD}, + {0x0F00a044,0x1fffffff}, + {0x0F00a040,0x1f000000}, + {0x0F00a084,0x1Cffffff}, + {0x0F00a080,0x1C000000}, + {0x0F00a000,0x00000016}, + {0x0F00a04C,0x0000000C}, + //Memcontroller Default values + {0x0F007000,0x00010001}, + {0x0F007004,0x01000000}, + {0x0F007008,0x01000001}, + {0x0F00700c,0x00000000}, + {0x0F007010,0x01000000}, + {0x0F007014,0x01000100}, + {0x0F007018,0x01000000}, + {0x0F00701c,0x01020000}, + {0x0F007020,0x04020107}, + {0x0F007024,0x00000007}, + {0x0F007028,0x02020201}, + {0x0F00702c,0x0204040a}, + {0x0F007030,0x04000000}, + {0x0F007034,0x00000002}, + {0x0F007038,0x1F060200}, + {0x0F00703C,0x1C22221F}, + {0x0F007040,0x8A006600}, + {0x0F007044,0x221a0800}, + {0x0F007048,0x02690204}, + {0x0F00704c,0x00000000}, + {0x0F007050,0x0000001c}, + {0x0F007054,0x00000000}, + {0x0F007058,0x00000000}, + {0x0F00705c,0x00000000}, + {0x0F007060,0x000A15D6}, + {0x0F007064,0x0000000A}, + {0x0F007068,0x00000000}, + {0x0F00706c,0x00000001}, + {0x0F007070,0x00004000}, + {0x0F007074,0x00000000}, + {0x0F007078,0x00000000}, + {0x0F00707C,0x00000000}, + {0x0F007080,0x00000000}, + {0x0F007084,0x00000000}, + {0x0F007094,0x00000104}, + //# Enable start bit within memory controller + {0x0F007018,0x01010000} + }; +//100Mhz +#define T3_SKIP_CLOCK_PROGRAM_DUMP_100MHZ 13 //index for 0x0F007000 +static DDR_SET_NODE asT3_DDRSetting100MHz[]= {// # DPLL Clock Setting + {0x0F000800,0x00007008}, + {0x0f000810,0x00000F95}, + {0x0f000820,0x07F13E3F}, + {0x0f000860,0x00000000}, + {0x0f000880,0x000003DD}, + // Changed source for X-bar and MIPS clock to APLL + //0x0f000840,0x0FFF1800, + {0x0f000840,0x0FFF1B00}, + {0x0f000870,0x00000002}, + {0x0F00a044,0x1fffffff}, + {0x0F00a040,0x1f000000}, + {0x0F00a084,0x1Cffffff}, + {0x0F00a080,0x1C000000}, + {0x0F00a04C,0x0000000C}, + //# Enable 2 ports within X-bar + {0x0F00A000,0x00000016}, + //Memcontroller Default values + {0x0F007000,0x00010001}, + {0x0F007004,0x01010100}, + {0x0F007008,0x01000001}, + {0x0F00700c,0x00000000}, + {0x0F007010,0x01000000}, + {0x0F007014,0x01000100}, + {0x0F007018,0x01000000}, + {0x0F00701c,0x01020001}, // POP - 0x00020000 Normal 0x01020000 + {0x0F007020,0x04020107},//Normal - 0x04030107 POP - 0x05030107 + {0x0F007024,0x00000007}, + {0x0F007028,0x01020201}, + {0x0F00702c,0x0204040A}, + {0x0F007030,0x06000000}, + {0x0F007034,0x00000004}, + {0x0F007038,0x20080200}, + {0x0F00703C,0x02030320}, + {0x0F007040,0x6E7F1200}, + {0x0F007044,0x01190A00}, + {0x0F007048,0x06120305},//0x02690204 // 0x06120305 + {0x0F00704c,0x00000000}, + {0x0F007050,0x0000001C}, + {0x0F007054,0x00000000}, + {0x0F007058,0x00000000}, + {0x0F00705c,0x00000000}, + {0x0F007060,0x00082ED6}, + {0x0F007064,0x0000000A}, + {0x0F007068,0x00000000}, + {0x0F00706c,0x00000001}, + {0x0F007070,0x00005000}, + {0x0F007074,0x00000000}, + {0x0F007078,0x00000000}, + {0x0F00707C,0x00000000}, + {0x0F007080,0x00000000}, + {0x0F007084,0x00000000}, + //# Enable BW improvement within memory controller + {0x0F007094,0x00000104}, + //# Enable start bit within memory controller + {0x0F007018,0x01010000} + }; + +//Net T3B DDR Settings +//DDR INIT-133Mhz +static DDR_SET_NODE asDPLL_266MHZ[] = { + {0x0F000800,0x00007212}, + {0x0f000820,0x07F13FFF}, + {0x0f000810,0x00000F95}, + {0x0f000860,0x00000000}, + {0x0f000880,0x000003DD}, + // Changed source for X-bar and MIPS clock to APLL + {0x0f000840,0x0FFF1B00}, + {0x0f000870,0x00000002} + }; +#if 0 +static DDR_SET_NODE asDPLL_800MHZ[] = { + {0x0f000810,0x00000F95}, + {0x0f000810,0x00000F95}, + {0x0f000810,0x00000F95}, + {0x0f000820,0x03F1365B}, + {0x0f000840,0x0FFF0000}, + {0x0f000880,0x000003DD}, + {0x0f000860,0x00000000} + }; +#endif + +#define T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 11 //index for 0x0F007000 +static DDR_SET_NODE asT3B_DDRSetting133MHz[] = {// # DPLL Clock Setting + {0x0f000810,0x00000F95}, + {0x0f000810,0x00000F95}, + {0x0f000810,0x00000F95}, + {0x0f000820,0x07F13652}, + {0x0f000840,0x0FFF0800}, + // Changed source for X-bar and MIPS clock to APLL + {0x0f000880,0x000003DD}, + {0x0f000860,0x00000000}, + // Changed source for X-bar and MIPS clock to APLL + {0x0F00a044,0x1fffffff}, + {0x0F00a040,0x1f000000}, + {0x0F00a084,0x1Cffffff}, + {0x0F00a080,0x1C000000}, + //# Enable 2 ports within X-bar + {0x0F00A000,0x00000016}, + //Memcontroller Default values + {0x0F007000,0x00010001}, + {0x0F007004,0x01010100}, + {0x0F007008,0x01000001}, + {0x0F00700c,0x00000000}, + {0x0F007010,0x01000000}, + {0x0F007014,0x01000100}, + {0x0F007018,0x01000000}, + {0x0F00701c,0x01020001},// POP - 0x00020001 Normal 0x01020001 + {0x0F007020,0x04030107}, //Normal - 0x04030107 POP - 0x05030107 + {0x0F007024,0x02000007}, + {0x0F007028,0x02020202}, + {0x0F00702c,0x0206060a},//ROB- 0x0205050a,//0x0206060a + {0x0F007030,0x05000000}, + {0x0F007034,0x00000003}, + {0x0F007038,0x130a0200},//ROB - 0x110a0200,//0x180a0200,// 0x1f0a0200 + {0x0F00703C,0x02101012},//ROB - 0x02101010,//0x02101018}, + {0x0F007040,0x457D1200},//ROB - 0x45751200,//0x450f1200}, + {0x0F007044,0x11130d00},//ROB - 0x110a0d00//0x111f0d00 + {0x0F007048,0x040D0306}, + {0x0F00704c,0x00000000}, + {0x0F007050,0x0000001c}, + {0x0F007054,0x00000000}, + {0x0F007058,0x00000000}, + {0x0F00705c,0x00000000}, + {0x0F007060,0x0010246c}, + {0x0F007064,0x00000012}, + {0x0F007068,0x00000000}, + {0x0F00706c,0x00000001}, + {0x0F007070,0x00007000}, + {0x0F007074,0x00000000}, + {0x0F007078,0x00000000}, + {0x0F00707C,0x00000000}, + {0x0F007080,0x00000000}, + {0x0F007084,0x00000000}, + //# Enable BW improvement within memory controller + {0x0F007094,0x00000104}, + //# Enable start bit within memory controller + {0x0F007018,0x01010000}, + }; + +#define T3B_SKIP_CLOCK_PROGRAM_DUMP_80MHZ 9 //index for 0x0F007000 +static DDR_SET_NODE asT3B_DDRSetting80MHz[] = {// # DPLL Clock Setting + {0x0f000810,0x00000F95}, + {0x0f000820,0x07F13FFF}, + {0x0f000840,0x0FFF1F00}, + {0x0f000880,0x000003DD}, + {0x0f000860,0x00000000}, + + {0x0F00a044,0x1fffffff}, + {0x0F00a040,0x1f000000}, + {0x0F00a084,0x1Cffffff}, + {0x0F00a080,0x1C000000}, + {0x0F00a000,0x00000016}, + //Memcontroller Default values + {0x0F007000,0x00010001}, + {0x0F007004,0x01000000}, + {0x0F007008,0x01000001}, + {0x0F00700c,0x00000000}, + {0x0F007010,0x01000000}, + {0x0F007014,0x01000100}, + {0x0F007018,0x01000000}, + {0x0F00701c,0x01020000}, + {0x0F007020,0x04020107}, + {0x0F007024,0x00000007}, + {0x0F007028,0x02020201}, + {0x0F00702c,0x0204040a}, + {0x0F007030,0x04000000}, + {0x0F007034,0x02000002}, + {0x0F007038,0x1F060202}, + {0x0F00703C,0x1C22221F}, + {0x0F007040,0x8A006600}, + {0x0F007044,0x221a0800}, + {0x0F007048,0x02690204}, + {0x0F00704c,0x00000000}, + {0x0F007050,0x0100001c}, + {0x0F007054,0x00000000}, + {0x0F007058,0x00000000}, + {0x0F00705c,0x00000000}, + {0x0F007060,0x000A15D6}, + {0x0F007064,0x0000000A}, + {0x0F007068,0x00000000}, + {0x0F00706c,0x00000001}, + {0x0F007070,0x00004000}, + {0x0F007074,0x00000000}, + {0x0F007078,0x00000000}, + {0x0F00707C,0x00000000}, + {0x0F007080,0x00000000}, + {0x0F007084,0x00000000}, + {0x0F007094,0x00000104}, + //# Enable start bit within memory controller + {0x0F007018,0x01010000} + }; + +//100Mhz +#define T3B_SKIP_CLOCK_PROGRAM_DUMP_100MHZ 9 //index for 0x0F007000 +static DDR_SET_NODE asT3B_DDRSetting100MHz[] = {// # DPLL Clock Setting + {0x0f000810,0x00000F95}, + {0x0f000820,0x07F1369B}, + {0x0f000840,0x0FFF0800}, + {0x0f000880,0x000003DD}, + {0x0f000860,0x00000000}, + {0x0F00a044,0x1fffffff}, + {0x0F00a040,0x1f000000}, + {0x0F00a084,0x1Cffffff}, + {0x0F00a080,0x1C000000}, + //# Enable 2 ports within X-bar + {0x0F00A000,0x00000016}, + //Memcontroller Default values + {0x0F007000,0x00010001}, + {0x0F007004,0x01010100}, + {0x0F007008,0x01000001}, + {0x0F00700c,0x00000000}, + {0x0F007010,0x01000000}, + {0x0F007014,0x01000100}, + {0x0F007018,0x01000000}, + {0x0F00701c,0x01020000}, // POP - 0x00020000 Normal 0x01020000 + {0x0F007020,0x04020107},//Normal - 0x04030107 POP - 0x05030107 + {0x0F007024,0x00000007}, + {0x0F007028,0x01020201}, + {0x0F00702c,0x0204040A}, + {0x0F007030,0x06000000}, + {0x0F007034,0x02000004}, + {0x0F007038,0x20080200}, + {0x0F00703C,0x02030320}, + {0x0F007040,0x6E7F1200}, + {0x0F007044,0x01190A00}, + {0x0F007048,0x06120305},//0x02690204 // 0x06120305 + {0x0F00704c,0x00000000}, + {0x0F007050,0x0100001C}, + {0x0F007054,0x00000000}, + {0x0F007058,0x00000000}, + {0x0F00705c,0x00000000}, + {0x0F007060,0x00082ED6}, + {0x0F007064,0x0000000A}, + {0x0F007068,0x00000000}, + {0x0F00706c,0x00000001}, + {0x0F007070,0x00005000}, + {0x0F007074,0x00000000}, + {0x0F007078,0x00000000}, + {0x0F00707C,0x00000000}, + {0x0F007080,0x00000000}, + {0x0F007084,0x00000000}, + //# Enable BW improvement within memory controller + {0x0F007094,0x00000104}, + //# Enable start bit within memory controller + {0x0F007018,0x01010000} + }; + + +#define T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 9 //index for 0x0F007000 +static DDR_SET_NODE asT3LP_DDRSetting133MHz[]= {// # DPLL Clock Setting + {0x0f000820,0x03F1365B}, + {0x0f000810,0x00002F95}, + {0x0f000880,0x000003DD}, + // Changed source for X-bar and MIPS clock to APLL + {0x0f000840,0x0FFF0000}, + {0x0f000860,0x00000000}, + {0x0F00a044,0x1fffffff}, + {0x0F00a040,0x1f000000}, + {0x0F00a084,0x1Cffffff}, + {0x0F00a080,0x1C000000}, + {0x0F00A000,0x00000016}, + //Memcontroller Default values + {0x0F007000,0x00010001}, + {0x0F007004,0x01010100}, + {0x0F007008,0x01000001}, + {0x0F00700c,0x00000000}, + {0x0F007010,0x01000000}, + {0x0F007014,0x01000100}, + {0x0F007018,0x01000000}, + {0x0F00701c,0x01020001},// POP - 0x00020001 Normal 0x01020001 + {0x0F007020,0x04030107}, //Normal - 0x04030107 POP - 0x05030107 + {0x0F007024,0x02000007}, + {0x0F007028,0x02020200}, + {0x0F00702c,0x0206060a},//ROB- 0x0205050a,//0x0206060a + {0x0F007030,0x05000000}, + {0x0F007034,0x00000003}, + {0x0F007038,0x200a0200},//ROB - 0x110a0200,//0x180a0200,// 0x1f0a0200 + {0x0F00703C,0x02101020},//ROB - 0x02101010,//0x02101018, + {0x0F007040,0x45711200},//ROB - 0x45751200,//0x450f1200, + {0x0F007044,0x110D0D00},//ROB - 0x110a0d00//0x111f0d00 + {0x0F007048,0x04080306}, + {0x0F00704c,0x00000000}, + {0x0F007050,0x0100001c}, + {0x0F007054,0x00000000}, + {0x0F007058,0x00000000}, + {0x0F00705c,0x00000000}, + {0x0F007060,0x0010245F}, + {0x0F007064,0x00000010}, + {0x0F007068,0x00000000}, + {0x0F00706c,0x00000001}, + {0x0F007070,0x00007000}, + {0x0F007074,0x00000000}, + {0x0F007078,0x00000000}, + {0x0F00707C,0x00000000}, + {0x0F007080,0x00000000}, + {0x0F007084,0x00000000}, + {0x0F007088,0x01000001}, + {0x0F00708c,0x00000101}, + {0x0F007090,0x00000000}, + //# Enable BW improvement within memory controller + {0x0F007094,0x00040000}, + {0x0F007098,0x00000000}, + {0x0F0070c8,0x00000104}, + //# Enable 2 ports within X-bar + //# Enable start bit within memory controller + {0x0F007018,0x01010000} +}; + +#define T3LP_SKIP_CLOCK_PROGRAM_DUMP_100MHZ 11 //index for 0x0F007000 +static DDR_SET_NODE asT3LP_DDRSetting100MHz[]= {// # DPLL Clock Setting + {0x0f000810,0x00002F95}, + {0x0f000820,0x03F1369B}, + {0x0f000840,0x0fff0000}, + {0x0f000860,0x00000000}, + {0x0f000880,0x000003DD}, + // Changed source for X-bar and MIPS clock to APLL + {0x0f000840,0x0FFF0000}, + {0x0F00a044,0x1fffffff}, + {0x0F00a040,0x1f000000}, + {0x0F00a084,0x1Cffffff}, + {0x0F00a080,0x1C000000}, + //Memcontroller Default values + {0x0F007000,0x00010001}, + {0x0F007004,0x01010100}, + {0x0F007008,0x01000001}, + {0x0F00700c,0x00000000}, + {0x0F007010,0x01000000}, + {0x0F007014,0x01000100}, + {0x0F007018,0x01000000}, + {0x0F00701c,0x01020000},// POP - 0x00020001 Normal 0x01020001 + {0x0F007020,0x04020107}, //Normal - 0x04030107 POP - 0x05030107 + {0x0F007024,0x00000007}, + {0x0F007028,0x01020200}, + {0x0F00702c,0x0204040a},//ROB- 0x0205050a,//0x0206060a + {0x0F007030,0x06000000}, + {0x0F007034,0x00000004}, + {0x0F007038,0x1F080200},//ROB - 0x110a0200,//0x180a0200,// 0x1f0a0200 + {0x0F00703C,0x0203031F},//ROB - 0x02101010,//0x02101018, + {0x0F007040,0x6e001200},//ROB - 0x45751200,//0x450f1200, + {0x0F007044,0x011a0a00},//ROB - 0x110a0d00//0x111f0d00 + {0x0F007048,0x03000305}, + {0x0F00704c,0x00000000}, + {0x0F007050,0x0100001c}, + {0x0F007054,0x00000000}, + {0x0F007058,0x00000000}, + {0x0F00705c,0x00000000}, + {0x0F007060,0x00082ED6}, + {0x0F007064,0x0000000A}, + {0x0F007068,0x00000000}, + {0x0F00706c,0x00000001}, + {0x0F007070,0x00005000}, + {0x0F007074,0x00000000}, + {0x0F007078,0x00000000}, + {0x0F00707C,0x00000000}, + {0x0F007080,0x00000000}, + {0x0F007084,0x00000000}, + {0x0F007088,0x01000001}, + {0x0F00708c,0x00000101}, + {0x0F007090,0x00000000}, + {0x0F007094,0x00010000}, + {0x0F007098,0x00000000}, + {0x0F0070C8,0x00000104}, + //# Enable 2 ports within X-bar + {0x0F00A000,0x00000016}, + //# Enable start bit within memory controller + {0x0F007018,0x01010000} +}; + +#define T3LP_SKIP_CLOCK_PROGRAM_DUMP_80MHZ 9 //index for 0x0F007000 +static DDR_SET_NODE asT3LP_DDRSetting80MHz[]= {// # DPLL Clock Setting + {0x0f000820,0x07F13FFF}, + {0x0f000810,0x00002F95}, + {0x0f000860,0x00000000}, + {0x0f000880,0x000003DD}, + {0x0f000840,0x0FFF1F00}, + {0x0F00a044,0x1fffffff}, + {0x0F00a040,0x1f000000}, + {0x0F00a084,0x1Cffffff}, + {0x0F00a080,0x1C000000}, + {0x0F00A000,0x00000016}, + {0x0f007000,0x00010001}, + {0x0f007004,0x01000000}, + {0x0f007008,0x01000001}, + {0x0f00700c,0x00000000}, + {0x0f007010,0x01000000}, + {0x0f007014,0x01000100}, + {0x0f007018,0x01000000}, + {0x0f00701c,0x01020000}, + {0x0f007020,0x04020107}, + {0x0f007024,0x00000007}, + {0x0f007028,0x02020200}, + {0x0f00702c,0x0204040a}, + {0x0f007030,0x04000000}, + {0x0f007034,0x00000002}, + {0x0f007038,0x1d060200}, + {0x0f00703c,0x1c22221d}, + {0x0f007040,0x8A116600}, + {0x0f007044,0x222d0800}, + {0x0f007048,0x02690204}, + {0x0f00704c,0x00000000}, + {0x0f007050,0x0100001c}, + {0x0f007054,0x00000000}, + {0x0f007058,0x00000000}, + {0x0f00705c,0x00000000}, + {0x0f007060,0x000A15D6}, + {0x0f007064,0x0000000A}, + {0x0f007068,0x00000000}, + {0x0f00706c,0x00000001}, + {0x0f007070,0x00004000}, + {0x0f007074,0x00000000}, + {0x0f007078,0x00000000}, + {0x0f00707c,0x00000000}, + {0x0f007080,0x00000000}, + {0x0f007084,0x00000000}, + {0x0f007088,0x01000001}, + {0x0f00708c,0x00000101}, + {0x0f007090,0x00000000}, + {0x0f007094,0x00010000}, + {0x0f007098,0x00000000}, + {0x0F0070C8,0x00000104}, + {0x0F007018,0x01010000} +}; + + + + +///T3 LP-B (UMA-B) + +#define T3LPB_SKIP_CLOCK_PROGRAM_DUMP_160MHZ 7 //index for 0x0F007000 +static DDR_SET_NODE asT3LPB_DDRSetting160MHz[]= {// # DPLL Clock Setting + + {0x0f000820,0x03F137DB}, + {0x0f000810,0x01842795}, + {0x0f000860,0x00000000}, + {0x0f000880,0x000003DD}, + {0x0f000840,0x0FFF0400}, + {0x0F00a044,0x1fffffff}, + {0x0F00a040,0x1f000000}, + {0x0f003050,0x00000021},//this is flash/eeprom clock divisor which set the flash clock to 20 MHz + {0x0F00a084,0x1Cffffff},//Now dump from her in internal memory + {0x0F00a080,0x1C000000}, + {0x0F00A000,0x00000016}, + {0x0f007000,0x00010001}, + {0x0f007004,0x01000001}, + {0x0f007008,0x01000101}, + {0x0f00700c,0x00000000}, + {0x0f007010,0x01000100}, + {0x0f007014,0x01000100}, + {0x0f007018,0x01000000}, + {0x0f00701c,0x01020000}, + {0x0f007020,0x04030107}, + {0x0f007024,0x02000007}, + {0x0f007028,0x02020200}, + {0x0f00702c,0x0206060a}, + {0x0f007030,0x050d0d00}, + {0x0f007034,0x00000003}, + {0x0f007038,0x170a0200}, + {0x0f00703c,0x02101012}, + {0x0f007040,0x45161200}, + {0x0f007044,0x11250c00}, + {0x0f007048,0x04da0307}, + {0x0f00704c,0x00000000}, + {0x0f007050,0x0000001c}, + {0x0f007054,0x00000000}, + {0x0f007058,0x00000000}, + {0x0f00705c,0x00000000}, + {0x0f007060,0x00142bb6}, + {0x0f007064,0x20430014}, + {0x0f007068,0x00000000}, + {0x0f00706c,0x00000001}, + {0x0f007070,0x00009000}, + {0x0f007074,0x00000000}, + {0x0f007078,0x00000000}, + {0x0f00707c,0x00000000}, + {0x0f007080,0x00000000}, + {0x0f007084,0x00000000}, + {0x0f007088,0x01000001}, + {0x0f00708c,0x00000101}, + {0x0f007090,0x00000000}, + {0x0f007094,0x00040000}, + {0x0f007098,0x00000000}, + {0x0F0070C8,0x00000104}, + {0x0F007018,0x01010000} +}; + + +#define T3LPB_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 7 //index for 0x0F007000 +static DDR_SET_NODE asT3LPB_DDRSetting133MHz[]= {// # DPLL Clock Setting + {0x0f000820,0x03F1365B}, + {0x0f000810,0x00002F95}, + {0x0f000880,0x000003DD}, + // Changed source for X-bar and MIPS clock to APLL + {0x0f000840,0x0FFF0000}, + {0x0f000860,0x00000000}, + {0x0F00a044,0x1fffffff}, + {0x0F00a040,0x1f000000}, + {0x0f003050,0x00000021},//flash/eeprom clock divisor which set the flash clock to 20 MHz + {0x0F00a084,0x1Cffffff},//dump from here in internal memory + {0x0F00a080,0x1C000000}, + {0x0F00A000,0x00000016}, + //Memcontroller Default values + {0x0F007000,0x00010001}, + {0x0F007004,0x01010100}, + {0x0F007008,0x01000001}, + {0x0F00700c,0x00000000}, + {0x0F007010,0x01000000}, + {0x0F007014,0x01000100}, + {0x0F007018,0x01000000}, + {0x0F00701c,0x01020001},// POP - 0x00020001 Normal 0x01020001 + {0x0F007020,0x04030107}, //Normal - 0x04030107 POP - 0x05030107 + {0x0F007024,0x02000007}, + {0x0F007028,0x02020200}, + {0x0F00702c,0x0206060a},//ROB- 0x0205050a,//0x0206060a + {0x0F007030,0x05000000}, + {0x0F007034,0x00000003}, + {0x0F007038,0x190a0200},//ROB - 0x110a0200,//0x180a0200,// 0x1f0a0200 + {0x0F00703C,0x02101017},//ROB - 0x02101010,//0x02101018, + {0x0F007040,0x45171200},//ROB - 0x45751200,//0x450f1200, + {0x0F007044,0x11290D00},//ROB - 0x110a0d00//0x111f0d00 + {0x0F007048,0x04080306}, + {0x0F00704c,0x00000000}, + {0x0F007050,0x0100001c}, + {0x0F007054,0x00000000}, + {0x0F007058,0x00000000}, + {0x0F00705c,0x00000000}, + {0x0F007060,0x0010245F}, + {0x0F007064,0x00000010}, + {0x0F007068,0x00000000}, + {0x0F00706c,0x00000001}, + {0x0F007070,0x00007000}, + {0x0F007074,0x00000000}, + {0x0F007078,0x00000000}, + {0x0F00707C,0x00000000}, + {0x0F007080,0x00000000}, + {0x0F007084,0x00000000}, + {0x0F007088,0x01000001}, + {0x0F00708c,0x00000101}, + {0x0F007090,0x00000000}, + //# Enable BW improvement within memory controller + {0x0F007094,0x00040000}, + {0x0F007098,0x00000000}, + {0x0F0070c8,0x00000104}, + //# Enable 2 ports within X-bar + //# Enable start bit within memory controller + {0x0F007018,0x01010000} +}; + +#define T3LPB_SKIP_CLOCK_PROGRAM_DUMP_100MHZ 8 //index for 0x0F007000 +static DDR_SET_NODE asT3LPB_DDRSetting100MHz[]= {// # DPLL Clock Setting + {0x0f000810,0x00002F95}, + {0x0f000820,0x03F1369B}, + {0x0f000840,0x0fff0000}, + {0x0f000860,0x00000000}, + {0x0f000880,0x000003DD}, + // Changed source for X-bar and MIPS clock to APLL + {0x0f000840,0x0FFF0000}, + {0x0F00a044,0x1fffffff}, + {0x0F00a040,0x1f000000}, + {0x0f003050,0x00000021},//flash/eeprom clock divisor which set the flash clock to 20 MHz + {0x0F00a084,0x1Cffffff}, //dump from here in internal memory + {0x0F00a080,0x1C000000}, + //Memcontroller Default values + {0x0F007000,0x00010001}, + {0x0F007004,0x01010100}, + {0x0F007008,0x01000001}, + {0x0F00700c,0x00000000}, + {0x0F007010,0x01000000}, + {0x0F007014,0x01000100}, + {0x0F007018,0x01000000}, + {0x0F00701c,0x01020000},// POP - 0x00020001 Normal 0x01020001 + {0x0F007020,0x04020107}, //Normal - 0x04030107 POP - 0x05030107 + {0x0F007024,0x00000007}, + {0x0F007028,0x01020200}, + {0x0F00702c,0x0204040a},//ROB- 0x0205050a,//0x0206060a + {0x0F007030,0x06000000}, + {0x0F007034,0x00000004}, + {0x0F007038,0x1F080200},//ROB - 0x110a0200,//0x180a0200,// 0x1f0a0200 + {0x0F00703C,0x0203031F},//ROB - 0x02101010,//0x02101018, + {0x0F007040,0x6e001200},//ROB - 0x45751200,//0x450f1200, + {0x0F007044,0x011a0a00},//ROB - 0x110a0d00//0x111f0d00 + {0x0F007048,0x03000305}, + {0x0F00704c,0x00000000}, + {0x0F007050,0x0100001c}, + {0x0F007054,0x00000000}, + {0x0F007058,0x00000000}, + {0x0F00705c,0x00000000}, + {0x0F007060,0x00082ED6}, + {0x0F007064,0x0000000A}, + {0x0F007068,0x00000000}, + {0x0F00706c,0x00000001}, + {0x0F007070,0x00005000}, + {0x0F007074,0x00000000}, + {0x0F007078,0x00000000}, + {0x0F00707C,0x00000000}, + {0x0F007080,0x00000000}, + {0x0F007084,0x00000000}, + {0x0F007088,0x01000001}, + {0x0F00708c,0x00000101}, + {0x0F007090,0x00000000}, + {0x0F007094,0x00010000}, + {0x0F007098,0x00000000}, + {0x0F0070C8,0x00000104}, + //# Enable 2 ports within X-bar + {0x0F00A000,0x00000016}, + //# Enable start bit within memory controller + {0x0F007018,0x01010000} +}; + +#define T3LPB_SKIP_CLOCK_PROGRAM_DUMP_80MHZ 7 //index for 0x0F007000 +static DDR_SET_NODE asT3LPB_DDRSetting80MHz[]= {// # DPLL Clock Setting + {0x0f000820,0x07F13FFF}, + {0x0f000810,0x00002F95}, + {0x0f000860,0x00000000}, + {0x0f000880,0x000003DD}, + {0x0f000840,0x0FFF1F00}, + {0x0F00a044,0x1fffffff}, + {0x0F00a040,0x1f000000}, + {0x0f003050,0x00000021},//flash/eeprom clock divisor which set the flash clock to 20 MHz + {0x0F00a084,0x1Cffffff},// dump from here in internal memory + {0x0F00a080,0x1C000000}, + {0x0F00A000,0x00000016}, + {0x0f007000,0x00010001}, + {0x0f007004,0x01000000}, + {0x0f007008,0x01000001}, + {0x0f00700c,0x00000000}, + {0x0f007010,0x01000000}, + {0x0f007014,0x01000100}, + {0x0f007018,0x01000000}, + {0x0f00701c,0x01020000}, + {0x0f007020,0x04020107}, + {0x0f007024,0x00000007}, + {0x0f007028,0x02020200}, + {0x0f00702c,0x0204040a}, + {0x0f007030,0x04000000}, + {0x0f007034,0x00000002}, + {0x0f007038,0x1d060200}, + {0x0f00703c,0x1c22221d}, + {0x0f007040,0x8A116600}, + {0x0f007044,0x222d0800}, + {0x0f007048,0x02690204}, + {0x0f00704c,0x00000000}, + {0x0f007050,0x0100001c}, + {0x0f007054,0x00000000}, + {0x0f007058,0x00000000}, + {0x0f00705c,0x00000000}, + {0x0f007060,0x000A15D6}, + {0x0f007064,0x0000000A}, + {0x0f007068,0x00000000}, + {0x0f00706c,0x00000001}, + {0x0f007070,0x00004000}, + {0x0f007074,0x00000000}, + {0x0f007078,0x00000000}, + {0x0f00707c,0x00000000}, + {0x0f007080,0x00000000}, + {0x0f007084,0x00000000}, + {0x0f007088,0x01000001}, + {0x0f00708c,0x00000101}, + {0x0f007090,0x00000000}, + {0x0f007094,0x00010000}, + {0x0f007098,0x00000000}, + {0x0F0070C8,0x00000104}, + {0x0F007018,0x01010000} +}; + +#endif // _USB_BECEEM_DDR_H_ + diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemDevice.cpp b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemDevice.cpp new file mode 100644 index 0000000000..04c9a5a9a2 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemDevice.cpp @@ -0,0 +1,1286 @@ +/* + * Beceem WiMax USB Driver. + * Copyright (c) 2010 Alexander von Gluck + * Distributed under the terms of the MIT license. + * + * Based on GPL code developed by: Beceem Communications Pvt. Ltd + * + * Driver for USB Ethernet Control Model devices + * Copyright (C) 2008 Michael Lotz + * Distributed under the terms of the MIT license. + * + * This code is the entry point for the operating system to + * Beceem device communications. + */ + +#include +#include + +#include "util.h" + +#ifdef HAIKU_TARGET_PLATFORM_HAIKU +#include // for mutex +#else +#include "BeOSCompatibility.h" // for pseudo mutex +#endif + +#include "Driver.h" +#include "Settings.h" + +#include "BeceemDevice.h" + +mutex gUSBLock; + +// auto-release helper class +class USBSmartLock { + public: + USBSmartLock() { mutex_lock(&gUSBLock); } + ~USBSmartLock() { mutex_unlock(&gUSBLock); } +}; + + +status_t +BeceemDevice::ReadRegister(unsigned int reg, size_t size, uint32_t* buffer) +{ + USBSmartLock USBSubsystemLock; // released on exit + + if (size > 255) { + TRACE_ALWAYS("Read too big! size = %d\n", size); + return B_BAD_VALUE; + } + + size_t actualLength = 0; + int retries = 0; + status_t result = B_ERROR; + + do { + result = gUSBModule->send_request(fDevice, + 0xC0 | USB_REQTYPE_ENDPOINT_OUT, 0x02, + (reg & 0xFFFF), + ((reg >> 16) & 0xFFFF), + size, buffer, + &actualLength); + retries++ ; + if (-ENODEV == result) + { + TRACE_ALWAYS("Error: Device was removed during USB read\n"); + break; + } + + } while ((result < 0) && (retries < MAX_USB_IO_RETRIES ) ); + + if (result < 0) { + TRACE_ALWAYS("Error: USB read request failure." + " Result: %d; Attempt: %d.\n", + result, retries); + return result; + } + + + if (size != actualLength) { + TRACE_ALWAYS("Error: Size mismatch on USB read request." + " Asked: %d; Got: %d; Attempt: %d.\n", + size, actualLength, retries); + } + + return result; +} + + +status_t +BeceemDevice::WriteRegister(unsigned int reg, size_t size, uint32_t* buffer) +{ + USBSmartLock USBSubsystemLock; // released on exit + + if (size > 255) { + TRACE_ALWAYS("Write too big! size = %d\n", size); + return B_BAD_VALUE; + } + + size_t actualLength = 0; + int retries = 0; + status_t result; + + do { + result = gUSBModule->send_request(fDevice, + 0x40 | USB_REQTYPE_ENDPOINT_OUT, 0x01, + (reg & 0xFFFF), + ((reg >> 16) & 0xFFFF), + size, buffer, + &actualLength); + retries++ ; + if (-ENODEV == result) + { + TRACE_ALWAYS("Error: Device was removed during USB write\n"); + break; + } + + } while ((result < 0) && (retries < MAX_USB_IO_RETRIES ) ); + + if (result < 0) { + TRACE_ALWAYS("Error: USB write request failure." + " Result: %d; Attempt: %d.\n", + result, retries); + + return result; + } + + if (size != actualLength) { + TRACE_ALWAYS("Error: Size mismatch on USB write request." + " Provided: %d; Took: %d; Attempt: %d.\n", + size, actualLength, retries); + } + + return result; +} + + +status_t +BeceemDevice::BizarroReadRegister(unsigned int reg, size_t size, uint32_t* buffer) +{ + // NET_TO_HOST long + + // Read then flip + status_t Status = ReadRegister(reg, size, buffer); + + convertEndian(false, size, buffer); + + return Status; +} + + +status_t +BeceemDevice::BizarroWriteRegister(unsigned int reg, size_t size, uint32_t* buffer) +{ + // HOST_TO_NET long + + volatile uint32_t reload = *buffer; + + convertEndian(true, size, buffer); + + status_t Status = WriteRegister(reg, size, buffer); + // Flip then write + + // as we modified the input data, and other things + // outside this function may need it, restore the original val. + *buffer = reload; + + return Status; +} + + +BeceemDevice::BeceemDevice(usb_device device, const char *description) + : + fStatus(B_ERROR), + fOpen(false), + fInsideNotify(0), + fDevice(device), + fDescription(description), + fNonBlocking(false), + fNotifyEndpoint(0), + fReadEndpoint(0), + fWriteEndpoint(0), + fNotifyReadSem(-1), + fNotifyWriteSem(-1), + fNotifyBuffer(NULL), + fNotifyBufferLength(0), + fLinkStateChangeSem(-1), + fHasConnection(false) +{ + const usb_device_descriptor + *deviceDescriptor = gUSBModule->get_device_descriptor(device); + + if (deviceDescriptor == NULL) { + TRACE_ALWAYS("Error of getting USB device descriptor.\n"); + return; + } + + fVendorID = deviceDescriptor->vendor_id; + fProductID = deviceDescriptor->product_id; + + fNotifyReadSem = create_sem(0, DRIVER_NAME"_notify_read"); + if (fNotifyReadSem < B_OK) { + TRACE_ALWAYS("Error of creating read notify semaphore:%#010x\n", + fNotifyReadSem); + return; + } + + fNotifyWriteSem = create_sem(0, DRIVER_NAME"_notify_write"); + if (fNotifyWriteSem < B_OK) { + TRACE_ALWAYS("Error of creating write notify semaphore:%#010x\n", + fNotifyWriteSem); + return; + } + + mutex_init(&gUSBLock, DRIVER_NAME"_usbsubsys"); + + // TODO : Investigate possible Notify Buffer sizes + fNotifyBufferLength = 8; + fNotifyBuffer = (uint8*)malloc(fNotifyBufferLength); + if (fNotifyBuffer == NULL) { + TRACE_ALWAYS("Error allocating notify buffer\n"); + return; + } + + if ((pwmxdevice = (WIMAX_DEVICE*)malloc(sizeof(WIMAX_DEVICE))) == NULL) + TRACE_ALWAYS("Error allocating Wimax device configuration buffer\n"); + + if ((pwmxdevice->nvmFlashCSInfo + = (PFLASH_CS_INFO)malloc(sizeof(FLASH_CS_INFO))) == NULL) + TRACE_ALWAYS("Error allocating Flash CS info structure.\n"); + + // set initial states + pwmxdevice->LEDThreadID = 0; + pwmxdevice->driverDDRinit = false; + pwmxdevice->driverHalt = false; + pwmxdevice->driverFwPushed = false; + + if (_SetupEndpoints() != B_OK) { + return; + } + + fStatus = B_OK; +} + + +BeceemDevice::~BeceemDevice() +{ + pwmxdevice->driverHalt = true; + + snooze(500); + + // Terminate LED thread cleanly + if (pwmxdevice->LEDThreadID > 0) { + LEDThreadTerminate(); + // Turn lights out + LightsOut(); + } + + gUSBModule->cancel_queued_transfers(fNotifyEndpoint); + gUSBModule->cancel_queued_transfers(fReadEndpoint); + gUSBModule->cancel_queued_transfers(fWriteEndpoint); + + if (fNotifyReadSem >= B_OK) + delete_sem(fNotifyReadSem); + if (fNotifyWriteSem >= B_OK) + delete_sem(fNotifyWriteSem); + + if (fNotifyBuffer) + free(fNotifyBuffer); + // Free notification buffer + + if (pwmxdevice->nvmFlashCSInfo) + free(pwmxdevice->nvmFlashCSInfo); + // Free flash configuration structure + + if (pwmxdevice) + free(pwmxdevice); + // Free malloc of wimax device struct + + mutex_destroy(&gUSBLock); + + TRACE("Debug: BeceemDevice deconstruction complete\n"); +} + + +status_t +BeceemDevice::Open(uint32 flags) +{ + if (fOpen) + return B_BUSY; + if (pwmxdevice->driverHalt) + return B_ERROR; + + status_t result = StartDevice(); + if (result != B_OK) { + return result; + } + + // setup state notifications + result = gUSBModule->queue_interrupt(fNotifyEndpoint, fNotifyBuffer, + fNotifyBufferLength, _NotifyCallback, this); + if (result != B_OK) { + TRACE_ALWAYS("Error of requesting notify interrupt:%#010x\n", result); + return result; + } + + fNonBlocking = (flags & O_NONBLOCK) == O_NONBLOCK; + fOpen = true; + return result; +} + + +status_t +BeceemDevice::Close() +{ + if (pwmxdevice->driverHalt) { + fOpen = false; + return B_OK; + } + + // wait until possible notification handling finished... + while (atomic_add(&fInsideNotify, 0) != 0) + snooze(100); + + gUSBModule->cancel_queued_transfers(fNotifyEndpoint); + gUSBModule->cancel_queued_transfers(fReadEndpoint); + gUSBModule->cancel_queued_transfers(fWriteEndpoint); + + fOpen = false; + + return StopDevice(); +} + + +status_t +BeceemDevice::Free() +{ + return B_OK; +} + + +// Network device Rx +status_t +BeceemDevice::Read(uint8 *buffer, size_t *numBytes) +{ + size_t numBytesToRead = *numBytes; + *numBytes = 0; + + TRACE_FLOW("Request %d bytes.\n", numBytesToRead); + + if (pwmxdevice->driverHalt) { + TRACE_ALWAYS("Error receiving %d bytes from removed device.\n", + numBytesToRead); + return B_DEVICE_NOT_FOUND; + } + + uint8 header[kRXHeaderSize]; + iovec rxData[] = { + { &header, kRXHeaderSize }, + { buffer, numBytesToRead } + }; + + status_t result = gUSBModule->queue_bulk_v(fReadEndpoint, + rxData, 1, _ReadCallback, this); + if (result != B_OK) { + TRACE_ALWAYS("Error of queue_bulk_v request:%#010x\n", result); + return result; + } + + uint32 flags = B_CAN_INTERRUPT | (fNonBlocking ? B_TIMEOUT : 0); + result = acquire_sem_etc(fNotifyReadSem, 1, flags, 0); + if (result < B_OK) { + TRACE_ALWAYS("Error of acquiring notify semaphore:%#010x.\n", result); + return result; + } + + // Safely tidy up after a major device hiccup + if (fStatusRead != B_OK && fStatusRead != B_CANCELED && !pwmxdevice->driverHalt) { + TRACE_ALWAYS("Error: Device status error:%#010x\n", fStatusRead); + result = gUSBModule->clear_feature(fReadEndpoint, + USB_FEATURE_ENDPOINT_HALT); + if (result != B_OK) { + TRACE_ALWAYS("Error: Problem during clearing of HALT state: " + "%#010x.\n", result); + return result; + } + } + + if (fActualLengthRead < kRXHeaderSize) { + TRACE_ALWAYS("Error: no place for TRXHeader:only %d of %d bytes.\n", + fActualLengthRead, kRXHeaderSize); + return B_ERROR; // TODO: ??? + } + + /* + * TODO :see what the first byte holds ? + if (!header.IsValid()) { + TRACE_ALWAYS("Error:TRX Header is invalid: len:%#04x; ilen:%#04x\n", + header.fLength, header.fInvertedLength); + return B_ERROR; // TODO: ??? + } + */ + + *numBytes = header[1] | ( header[2] << 8 ); + + if (header[0] & 0xBF ) { + TRACE_ALWAYS("RX error %d occured !\n", header[0]); + } + + if (fActualLengthRead - kRXHeaderSize > *numBytes) { + TRACE_ALWAYS("MISMATCH of the frame length: hdr %d; received:%d\n", + *numBytes, fActualLengthRead - kRXHeaderSize); + } + + TRACE_FLOW("Read %d bytes.\n", *numBytes); + return B_OK; +} + + +// Network device Tx +status_t +BeceemDevice::Write(const uint8 *buffer, size_t *numBytes) +{ + size_t numBytesToWrite = *numBytes; + *numBytes = 0; + + if (pwmxdevice->driverHalt) { + TRACE_ALWAYS("Error writing %d bytes to removed device.\n", + numBytesToWrite); + return B_DEVICE_NOT_FOUND; + } + + if (!fHasConnection) { + TRACE_ALWAYS("Error writing %d bytes to device while WiMAX connection down.\n", + numBytesToWrite); + return B_ERROR; + } + + if (fTXBufferFull) { + TRACE_ALWAYS("Error writing %d bytes to device while TX buffer full.\n", + numBytesToWrite); + return B_ERROR; + } + + TRACE_FLOW("Write %d bytes.\n", numBytesToWrite); + + uint8 header[kTXHeaderSize]; + header[0] = *numBytes & 0xFF; + header[1] = *numBytes >> 8; + + iovec txData[] = { + { &header, kTXHeaderSize }, + { (uint8*)buffer, numBytesToWrite } + }; + + status_t result = gUSBModule->queue_bulk_v(fWriteEndpoint, + txData, 2, _WriteCallback, this); + if (result != B_OK) { + TRACE_ALWAYS("Error of queue_bulk_v request:%#010x\n", result); + return result; + } + + result = acquire_sem_etc(fNotifyWriteSem, 1, B_CAN_INTERRUPT, 0); + + if (result < B_OK) { + TRACE_ALWAYS("Error of acquiring notify semaphore:%#010x.\n", result); + return result; + } + + // Safely tidy up after a major device hiccup + if (fStatusWrite != B_OK && fStatusWrite != B_CANCELED + && !pwmxdevice->driverHalt) { + + TRACE_ALWAYS("Device status error:%#010x\n", fStatusWrite); + result = gUSBModule->clear_feature(fWriteEndpoint, + USB_FEATURE_ENDPOINT_HALT); + + if (result != B_OK) { + TRACE_ALWAYS("Error during clearing of HALT state:%#010x\n", result); + return result; + } + } + + *numBytes = fActualLengthWrite - kTXHeaderSize;; + + TRACE_FLOW("Written %d bytes.\n", *numBytes); + return B_OK; +} + + +status_t +BeceemDevice::Control(uint32 op, void *buffer, size_t length) +{ + switch (op) { + case ETHER_INIT: + return B_OK; + + case ETHER_GETADDR: + memcpy(buffer, &fMACAddress, sizeof(fMACAddress)); + return B_OK; + + case ETHER_GETFRAMESIZE: + *(uint32 *)buffer = 1518 /* fFrameSize */; + return B_OK; + + case ETHER_NONBLOCK: + TRACE("ETHER_NONBLOCK\n"); + fNonBlocking = *((uint8*)buffer); + return B_OK; + + case ETHER_SETPROMISC: + TRACE("ETHER_SETPROMISC\n"); + return SetPromiscuousMode(*((uint8*)buffer)); + + case ETHER_ADDMULTI: + TRACE("ETHER_ADDMULTI\n"); + return ModifyMulticastTable(true, *((uint8*)buffer)); + + case ETHER_REMMULTI: + TRACE("ETHER_REMMULTI\n"); + return ModifyMulticastTable(false, *((uint8*)buffer)); + +#if HAIKU_TARGET_PLATFORM_HAIKU + case ETHER_SET_LINK_STATE_SEM: + fLinkStateChangeSem = *(sem_id *)buffer; + return B_OK; + + case ETHER_GET_LINK_STATE: + return GetLinkState((ether_link_state *)buffer); +#endif + + default: + TRACE_ALWAYS("Error: Unhandled IOCTL catched: %#010x\n", op); + } + + return B_DEV_INVALID_IOCTL; +} + + +void +BeceemDevice::Removed() +{ + fHasConnection = false; + + pwmxdevice->driverHalt = true; + + TRACE("Debug: Pre InsideNotify\n"); + + // the notify hook is different from the read and write hooks as it does + // itself schedule traffic (while the other hooks only release a semaphore + // to notify another thread which in turn safly checks for the removed + // case) - so we must ensure that we are not inside the notify hook anymore + // before returning, as we would otherwise violate the promise not to use + // any of the pipes after returning from the removed hook + while (atomic_add(&fInsideNotify, 0) != 0) + snooze(100); + + TRACE("Debug: Post InsideNotify\n"); + + TRACE("Debug: Canceling queued USB transfers... [NotifyEndpoint]\n"); + gUSBModule->cancel_queued_transfers(fNotifyEndpoint); + TRACE("Debug: Canceling queued USB transfers... [ReadEndpoint]\n"); + gUSBModule->cancel_queued_transfers(fReadEndpoint); + TRACE("Debug: Canceling queued USB transfers... [WriteEndpoint]\n"); + gUSBModule->cancel_queued_transfers(fWriteEndpoint); + + if (fLinkStateChangeSem >= B_OK) + release_sem_etc(fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE); +} + + +/*! Identify Beceem Baseband chip and populate deviceChipID with it + */ +status_t +BeceemDevice::IdentifyChipset() +{ + + if (BizarroReadRegister(CHIP_ID_REG, sizeof(unsigned int), + &pwmxdevice->deviceChipID) != B_OK) + { + TRACE_ALWAYS("Error: Beceem device identification read failure\n"); + return B_ERROR; + } + + switch(pwmxdevice->deviceChipID) { + case T3: + TRACE_ALWAYS( + "Info: Identified Beceem T3 baseband chipset (0x%x)\n", + pwmxdevice->deviceChipID); + break; + case T3B: + TRACE_ALWAYS( + "Info: Identified Beceem T3B baseband chipset (0x%x)\n", + pwmxdevice->deviceChipID); + break; + case T3LPB: + TRACE_ALWAYS( + "Info: Identified Beceem T3LPB baseband chipset (0x%x)\n", + pwmxdevice->deviceChipID); + break; + case BCS250_BC: + TRACE_ALWAYS( + "Info: Identified Beceem BC250_BC baseband chipset (0x%x)\n", + pwmxdevice->deviceChipID); + break; + case BCS220_2: + TRACE_ALWAYS( + "Info: Identified Beceem BCS220_2 baseband chipset (0x%x)\n", + pwmxdevice->deviceChipID); + break; + case BCS220_2BC: + TRACE_ALWAYS( + "Info: Identified Beceem BCS220_2BC baseband chipset (0x%x)\n", + pwmxdevice->deviceChipID); + break; + case BCS220_3: + TRACE_ALWAYS( + "Info: Identified Beceem BCS220_3 baseband chipset (0x%x)\n", + pwmxdevice->deviceChipID); + break; + default: + TRACE_ALWAYS( + "Warning: Unknown Beceem chipset detected (0x%x)\n", + pwmxdevice->deviceChipID); + break; + } + + return B_OK; +} + + +status_t +BeceemDevice::SetupDevice(bool deviceReplugged) +{ + unsigned int value = 0; + unsigned long dwReadValue = 0; + + pwmxdevice->gpioInfo[32] = {0}; + pwmxdevice->driverState = STATE_INIT; + + // ID the Beceem chipset + IdentifyChipset(); + + // init the CPU subsystem + CPUInit(pwmxdevice); + + // Parse vendor config and put into struct + if (LoadConfig() != B_OK) + return B_ERROR; + + if (pwmxdevice->deviceChipID >= T3LPB) + { + BizarroReadRegister(SYS_CFG, sizeof(value), &value); + pwmxdevice->syscfgBefFw = value; + if((value & 0x60)== 0) + { + TRACE("Debug: CPU is FlashBoot\n"); + pwmxdevice->CPUFlashBoot = true; + } + } + + // take a quick break to let things settle + snooze(100); + + CPUReset(); + + // Initilize non-volatile memory + if (NVMInit(pwmxdevice) != B_OK) { + TRACE_ALWAYS("Error: Non-volatile memory initialization failure.\n"); + return B_ERROR; + } + + // Initilize device DDR memory + if (DDRInit(pwmxdevice) != B_OK) { + TRACE_ALWAYS("Error: DDR Initialization failed\n"); + return B_ERROR; + } else { + TRACE("Debug: DDR Initialization successful.\n"); + pwmxdevice->driverDDRinit = true; + } + + // Push vendor configuration to device + // Each bcm chip has a custom binary config + // telling the device about itself (how it was designed) + if (PushConfig(CONF_BEGIN_ADDR) != B_OK) { + TRACE_ALWAYS("Vendor configuration push failed, aborting device setup.\n"); + return B_ERROR; + } + + // Set up GPIO (nvmVer 5+ is double sized) + if (pwmxdevice->nvmVerMajor < 5) { + TRACE("Debug: VerMajor < 5 PARAM pointer\n"); + NVMRead(GPIO_PARAM_POINTER, 2, (unsigned int*)&pwmxdevice->hwParamPtr); + pwmxdevice->hwParamPtr = ntohs(pwmxdevice->hwParamPtr); + } else { + TRACE("Debug: VerMajor 5+ PARAM pointer\n"); + NVMRead(GPIO_PARAM_POINTER_MAP5, 4, (unsigned int*)&pwmxdevice->hwParamPtr); + // TODO : NVM : validate v5+ nvm params a-la ValidateDSDParamsChecksum + pwmxdevice->hwParamPtr = ntohl(pwmxdevice->hwParamPtr); + } + + TRACE("Debug: Raw PARAM pointer: 0x%x\n", pwmxdevice->hwParamPtr); + + if (pwmxdevice->hwParamPtr < DSD_START_OFFSET || + pwmxdevice->hwParamPtr > pwmxdevice->nvmDSDSize - DSD_START_OFFSET) + { + TRACE_ALWAYS("Error: DSD Status checksum mismatch\n"); + return B_ERROR; + } + + dwReadValue = pwmxdevice->hwParamPtr; + // hw paramater pointer + dwReadValue = dwReadValue + DSD_START_OFFSET; + // add DSD start offset + dwReadValue = dwReadValue + GPIO_START_OFFSET; + // add GPIO start offset + + NVMRead(dwReadValue, 32, (uint32_t*)&pwmxdevice->gpioInfo); + // populate for LED information + + ValidateDSD(pwmxdevice->hwParamPtr); + // validate the hardware DSD0 we calculated + + LEDInit(pwmxdevice); + // Initilize LED on GPIO subsystem and spawn thread + + pwmxdevice->driverState = STATE_FWPUSH; + + status_t firm_push_result = PushFirmware(FIRM_BEGIN_ADDR); + // Push firmware to device + + if (firm_push_result != B_OK) { + TRACE_ALWAYS("Firmware push failed, aborting device setup.\n"); + pwmxdevice->driverFwPushed = false; + return B_ERROR; + } else { + pwmxdevice->driverFwPushed = true; + pwmxdevice->driverState = STATE_FWPUSH_OK; + CPURun(); + } + + ether_address address; + + if (ReadMACFromNVM(&address) != B_OK) + return B_ERROR; + + TRACE("MAC address is: %02x:%02x:%02x:%02x:%02x:%02x\n", + address.ebyte[0], address.ebyte[1], address.ebyte[2], + address.ebyte[3], address.ebyte[4], address.ebyte[5]); + + if (deviceReplugged) { + // this might be the same device that was replugged - read the MAC address + // (which should be at the same index) to make sure + if (memcmp(&address, &fMACAddress, sizeof(address)) != 0) { + TRACE_ALWAYS("Cannot replace device with MAC address:" + "%02x:%02x:%02x:%02x:%02x:%02x\n", + fMACAddress.ebyte[0], fMACAddress.ebyte[1], fMACAddress.ebyte[2], + fMACAddress.ebyte[3], fMACAddress.ebyte[4], fMACAddress.ebyte[5]); + return B_BAD_VALUE; // is not the same + } + } else + fMACAddress = address; + + pwmxdevice->driverState = STATE_NONET; + + // TODO : init Urb a-la StartInterruptUrb + // TODO : wait for StartInterruptUrb + // TODO : register_control_device_interface + + + // TODO : Preserve stability + // Things will break past this point until things are more complete + // Prevent completion of device initilization to preseve system stability. + + #if 1 + TRACE_ALWAYS("A Beceem WiMax device was attached, " + "however the Beceem driver is incomplete.\n"); + return B_ERROR; + #endif + + return B_OK; +} + + +status_t +BeceemDevice::CompareAndReattach(usb_device device) +{ + const usb_device_descriptor *deviceDescriptor + = gUSBModule->get_device_descriptor(device); + + if (deviceDescriptor == NULL) { + TRACE_ALWAYS("Error getting USB device descriptor.\n"); + return B_ERROR; + } + + if (deviceDescriptor->vendor_id != fVendorID + && deviceDescriptor->product_id != fProductID) { + // this certainly isn't the same device + return B_BAD_VALUE; + } + + // this is the same device that was replugged - clear the removed state, + // resetup the endpoints and transfers and open the device if it was + // previously opened + fDevice = device; + pwmxdevice->driverHalt = false; + + status_t result = _SetupEndpoints(); + if (result != B_OK) { + pwmxdevice->driverHalt = true; + return result; + } + + // we need to setup hardware on device replug + result = SetupDevice(true); + if (result != B_OK) { + return result; + } + + if (fOpen) { + fOpen = false; + result = Open(fNonBlocking ? O_NONBLOCK : 0); + } + + return result; +} + + +status_t +BeceemDevice::_SetupEndpoints() +{ + const usb_configuration_info *config + = gUSBModule->get_nth_configuration(fDevice, 0); + + if (config == NULL) { + TRACE_ALWAYS("Error: Failed to get USB device configuration.\n"); + return B_ERROR; + } + + if (config->interface_count <= 0) { + TRACE_ALWAYS("Error: No interfaces found in USB device configuration\n"); + return B_ERROR; + } + + usb_interface_info *interface = config->interface[0].active; + if (interface == 0) { + TRACE_ALWAYS("Error:invalid active interface in " + "USB device configuration\n"); + return B_ERROR; + } + + int notifyEndpoint = -1; + int readEndpoint = -1; + int writeEndpoint = -1; + + for (size_t ep = 0; ep < interface->endpoint_count; ep++) { + usb_endpoint_descriptor *epd = interface->endpoint[ep].descr; + + if ((epd->attributes & USB_ENDPOINT_ATTR_MASK) + == USB_ENDPOINT_ATTR_INTERRUPT) { + // Interrupt endpoint + notifyEndpoint = ep; + } else if ((epd->attributes & USB_ENDPOINT_ATTR_MASK) + == USB_ENDPOINT_ATTR_BULK) { + + // Bulk data endpoint + if ((epd->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) + == USB_ENDPOINT_ADDR_DIR_IN) + readEndpoint = ep; + else if ((epd->endpoint_address & USB_ENDPOINT_ADDR_DIR_OUT) + == USB_ENDPOINT_ADDR_DIR_OUT) + writeEndpoint = ep; + else + TRACE_ALWAYS("Warning: BULK USB Endpoint %d (%#04x) is unknown.\n", + ep, epd->attributes); + } else if ((epd->attributes & USB_ENDPOINT_ATTR_MASK) + == USB_ENDPOINT_ATTR_ISOCHRONOUS) { + // Isochronous endpoint + // TODO : do we need the Isochronous USB endpoints this device provides? + // http://www.beyondlogic.org/usbnutshell/usb4.shtml#Isochronous + } else { + // Strange... + TRACE_ALWAYS("Warning: USB Endpoint %d (%#04x) doesn't match known " + "attribute mask.\n", ep, epd->attributes); + } + + } + + if (notifyEndpoint == -1 || readEndpoint == -1 || writeEndpoint == -1) { + TRACE_ALWAYS("Error: not all USB endpoints were found: " + "notify:%d; read:%d; write:%d\n", + notifyEndpoint, readEndpoint, writeEndpoint); + return B_ERROR; + } + + TRACE("Debug: USB Endpoints configured: notify %d; read %d; write %d\n", + notifyEndpoint, readEndpoint, writeEndpoint); + + gUSBModule->set_configuration(fDevice, config); + + fNotifyEndpoint = interface->endpoint[notifyEndpoint].handle; + fReadEndpoint = interface->endpoint[readEndpoint ].handle; + fWriteEndpoint = interface->endpoint[writeEndpoint ].handle; + + return B_OK; +} + + +status_t +BeceemDevice::StopDevice() +{ + TRACE_ALWAYS("Stop device not implemented\n"); + return B_ERROR; +} + + +status_t +BeceemDevice::SetPromiscuousMode(bool on) +{ + // TODO : SetPromiscuousMode + + return B_OK; +} + + +status_t +BeceemDevice::ModifyMulticastTable(bool add, uint8 address) +{ + // TODO : ModifyMulticastTable + TRACE_ALWAYS("Call for (%d, %#02x) is not implemented\n", add, address); + return B_OK; +} + + +void +BeceemDevice::_ReadCallback(void *cookie, int32 status, void *data, + uint32 actualLength) +{ + TRACE_FLOW("ReadCB: %d bytes; status:%#010x\n", actualLength, status); + BeceemDevice *device = (BeceemDevice *)cookie; + device->fActualLengthRead = actualLength; + device->fStatusRead = status; + release_sem_etc(device->fNotifyReadSem, 1, B_DO_NOT_RESCHEDULE); +} + + +void +BeceemDevice::_WriteCallback(void *cookie, int32 status, void *data, + uint32 actualLength) +{ + TRACE_FLOW("WriteCB: %d bytes; status:%#010x\n", actualLength, status); + BeceemDevice *device = (BeceemDevice *)cookie; + device->fActualLengthWrite = actualLength; + device->fStatusWrite = status; + release_sem_etc(device->fNotifyWriteSem, 1, B_DO_NOT_RESCHEDULE); +} + + +void +BeceemDevice::_NotifyCallback(void *cookie, int32 status, void *data, + uint32 actualLength) +{ + BeceemDevice *device = (BeceemDevice *)cookie; + atomic_add(&device->fInsideNotify, 1); + if (status == B_CANCELED || device->pwmxdevice->driverHalt) { + atomic_add(&device->fInsideNotify, -1); + return; + } + + if (status != B_OK) { + TRACE_ALWAYS("Device status error:%#010x\n", status); + status_t result = gUSBModule->clear_feature(device->fNotifyEndpoint, + USB_FEATURE_ENDPOINT_HALT); + if (result != B_OK) + TRACE_ALWAYS("Error during clearing of HALT state:%#010x.\n", result); + } + + // parse data in overriden class + device->OnNotify(actualLength); + + // schedule next notification buffer + gUSBModule->queue_interrupt(device->fNotifyEndpoint, device->fNotifyBuffer, + device->fNotifyBufferLength, _NotifyCallback, device); + atomic_add(&device->fInsideNotify, -1); +} + + +status_t +BeceemDevice::StartDevice() +{ + // TODO : StartDevice on open (might not be needed) + return B_OK; +} + + +status_t +BeceemDevice::LoadConfig() +{ + size_t file_size = 0; + unsigned int* buffer = 0; + struct stat cfgStat; + int dtaread = 0; + + int fh = open( FIRM_CFG, O_RDONLY ); + + if (fh == B_ERROR || fstat(fh, &cfgStat) < 0 ) { + TRACE_ALWAYS("Error: Unable to open the configuration at %s\n", FIRM_CFG); + return fh; + } + + file_size = cfgStat.st_size; + + buffer=(unsigned int*)malloc(MAX_USB_TRANSFER); + + if ( !buffer ) { + TRACE_ALWAYS("Error: Memory allocation error.\n"); + return B_ERROR; + } + + dtaread = read(fh , buffer, MAX_USB_TRANSFER); + + if (dtaread < 0) + { + TRACE_ALWAYS("Error: Error reading from vendor configuration.\n"); + close(fh); + free(buffer); + return B_ERROR; + } + + if (file_size != sizeof(VENDORCFG)) + { + TRACE_ALWAYS("Error: Size mismatch in vendor configuration structure!\n"); + close(fh); + free(buffer); + return B_ERROR; + } else { + TRACE_ALWAYS("Info: Found valid vendor configuration %ld bytes long.\n", file_size); + } + + // we copy the configuration into our fancy struct to know what the device knows + memcpy(&pwmxdevice->vendorcfg, buffer, sizeof(VENDORCFG)); + + TRACE("Debug: Vendor Config: Config File Version is 0x%x\n", pwmxdevice->vendorcfg.m_u32CfgVersion); + TRACE("Debug: Vendor Config: Center Frequency is 0x%x\n", pwmxdevice->vendorcfg.m_u32CenterFrequency); + TRACE("Debug: Vendor Config: Band A Scan = 0x%x\n", pwmxdevice->vendorcfg.m_u32BandAScan); + TRACE("Debug: Vendor Config: Band B Scan = 0x%x\n", pwmxdevice->vendorcfg.m_u32BandBScan); + TRACE("Debug: Vendor Config: Band C Scan = 0x%x\n", pwmxdevice->vendorcfg.m_u32BandCScan); + TRACE("Debug: Vendor Config: PHS Enable = 0x%x\n", pwmxdevice->vendorcfg.m_u32PHSEnable); + TRACE("Debug: Vendor Config: Handoff Enable = 0x%x\n", pwmxdevice->vendorcfg.m_u32HoEnable); + TRACE("Debug: Vendor Config: HO Reserved1 = 0x%x\n", pwmxdevice->vendorcfg.m_u32HoReserved1); + TRACE("Debug: Vendor Config: HO Reserved2 = 0x%x\n", pwmxdevice->vendorcfg.m_u32HoReserved2); + TRACE("Debug: Vendor Config: MIMO Enable = 0x%x\n", pwmxdevice->vendorcfg.m_u32MimoEnable); + TRACE("Debug: Vendor Config: PKMv2 Enable = 0x%x\n", pwmxdevice->vendorcfg.m_u32SecurityEnable); + TRACE("Debug: Vendor Config: Power Saving Modes Enable = 0x%x\n", pwmxdevice->vendorcfg.m_u32PowerSavingModesEnable); + TRACE("Debug: Vendor Config: Power Saving Mode Options = 0x%x\n", pwmxdevice->vendorcfg.m_u32PowerSavingModeOptions); + TRACE("Debug: Vendor Config: ARQ Enable = 0x%x\n", pwmxdevice->vendorcfg.m_u32ArqEnable); + TRACE("Debug: Vendor Config: Harq Enable = 0x%x\n", pwmxdevice->vendorcfg.m_u32HarqEnable); + TRACE("Debug: Vendor Config: EEPROM Flag = 0x%x\n", pwmxdevice->vendorcfg.m_u32EEPROMFlag); + TRACE("Debug: Vendor Config: Customize = 0x%x\n", pwmxdevice->vendorcfg.m_u32Customize); + TRACE("Debug: Vendor Config: Bandwidth = 0x%x\n", pwmxdevice->vendorcfg.m_u32ConfigBW); + TRACE("Debug: Vendor Config: RadioParameter = 0x%x\n", pwmxdevice->vendorcfg.m_u32RadioParameter); + TRACE("Debug: Vendor Config: HostDrvrConfig1 is 0x%x\n", pwmxdevice->vendorcfg.HostDrvrConfig1); + TRACE("Debug: Vendor Config: HostDrvrConfig2 is 0x%x\n", pwmxdevice->vendorcfg.HostDrvrConfig2); + TRACE("Debug: Vendor Config: HostDrvrConfig3 is 0x%x\n", pwmxdevice->vendorcfg.HostDrvrConfig3); + TRACE("Debug: Vendor Config: HostDrvrConfig4 is 0x%x\n", pwmxdevice->vendorcfg.HostDrvrConfig4); + TRACE("Debug: Vendor Config: HostDrvrConfig5 is 0x%x\n", pwmxdevice->vendorcfg.HostDrvrConfig5); + TRACE("Debug: Vendor Config: HostDrvrConfig6 is 0x%x\n", pwmxdevice->vendorcfg.HostDrvrConfig6); + + close(fh); + free(buffer); + + return B_OK; +} + + +status_t +BeceemDevice::PushConfig(unsigned int loc) +{ + size_t file_size = 0; + unsigned int* buffer = 0; + struct stat cfgStat; + status_t result; + + int chipwriteloc = 0; + int readposition = 0; + + int fh = open( FIRM_CFG, O_RDONLY ); + + if (fh == B_ERROR || fstat(fh, &cfgStat) < 0 ) { + TRACE_ALWAYS("Error: Unable to open the configuration at %s\n", FIRM_CFG); + return fh; + } + + file_size = cfgStat.st_size; + + TRACE_ALWAYS("Info: Vendor configuration to be pushed to 0x%x on device.\n", + loc); + + buffer=(unsigned int*)malloc(MAX_USB_TRANSFER); + + if ( !buffer ) { + TRACE_ALWAYS("Error: Memory allocation error.\n"); + return B_ERROR; + } + + // We have to spoon feed the data to the usb device as it is probbably too + // much to be written in one go. + while (1) + { + readposition = read(fh , buffer, MAX_USB_TRANSFER); + + if (readposition <= 0) + { + if (readposition < 0) + { + TRACE_ALWAYS("Error: Error reading firmware.\n"); + result = B_ERROR; + } else { + TRACE_ALWAYS("Info: Got end of file!\n"); + result = B_OK; + } + break; + } + + // Good data... but consumes too much I/O for larger file writes + // TRACE("Debug: Read: %d, To Write %d - %d\n", readposition, + // chipwriteloc, chipwriteloc+readposition); + + // As readposition should always be less then MAX_USB_TRANSFER + // and we have checked the validity of read's output above. + if ( WriteRegister(loc + chipwriteloc, readposition, buffer) != B_OK) + { + TRACE_ALWAYS("Write failure\n"); + result = B_ERROR; + break; + } + + // +1 as we don't want to write the same sector twice + chipwriteloc += (MAX_USB_TRANSFER+1); + } + + close(fh); + free(buffer); + + if (result < 0) + { + TRACE_ALWAYS("Error: Push of vendor configuration failed :%d\n", result); + return B_ERROR; + } else { + TRACE_ALWAYS("Info: Push of vendor configuration was successful.\n"); + return B_OK; + } +} + + +status_t +BeceemDevice::PushFirmware(unsigned int loc) +{ + size_t file_size = 0; + int chipwriteloc = 0; + int readposition = 0; + + unsigned int* buffer = 0; + struct stat firmStat; + status_t result; + + int fh = open( FIRM_BIN, O_RDONLY ); + + if (fh == B_ERROR || fstat(fh, &firmStat) < 0 ) { + TRACE_ALWAYS("Error: Unable to open the firmware at %s\n", FIRM_BIN); + return fh; + } else + TRACE_ALWAYS("Info: Found firmware at %s.\n", FIRM_BIN); + + // The size of the firmware can very slightly + // CLEAR 1900 Beceem firmware is 2018596 + // Sprint 1901 Beceem firmware is 2028080 + file_size = firmStat.st_size; + + TRACE_ALWAYS("Info: %ld byte firmware to be pushed to 0x%x on device.\n", + file_size, loc); + + // For the push we load the file into the buffer + buffer=(unsigned int*)malloc(MAX_USB_TRANSFER); + + if ( !buffer ) { + TRACE_ALWAYS("Error: Memory allocation error.\n"); + return B_ERROR; + } + + // TODO : Firmware Download : investigate this, SHADOW clearing thing causes a KDL atm + #if 0 + // Clear the NVM SHADOW signature always before fw download. + WriteRegister( EEPROM_CAL_DATA_INTERNAL_LOC-4, 1, 0); + WriteRegister( EEPROM_CAL_DATA_INTERNAL_LOC-8, 1, 0); + #endif + + // We have to spoon feed the data to the usb device as it is probbably too + // much to be written in one go. + while (1) + { + readposition = read(fh , buffer, MAX_USB_TRANSFER); + + if (readposition <= 0) + { + if (readposition < 0) + { + TRACE_ALWAYS("Error: Error reading firmware.\n"); + result = B_ERROR; + } else { + TRACE_ALWAYS("Info: Got end of file!\n"); + result = B_OK; + } + break; + } + + // Good data... but consumes too much I/O for larger file writes + // TRACE("Debug: Read: %d, To Write %d - %d\n", readposition, + // chipwriteloc, chipwriteloc + readposition); + + // As readposition should always be less then MAX_USB_TRANSFER + // and we have checked the validity of read's output above. + if ( WriteRegister(loc + chipwriteloc, readposition, buffer) != B_OK) + { + TRACE_ALWAYS("Write failure\n"); + result = B_ERROR; + break; + } + + // +1 as we don't want to write the same sector twice + chipwriteloc += (MAX_USB_TRANSFER+1); + } + + free(buffer); + close(fh); + + if (result != B_OK) + { + TRACE_ALWAYS("Error: Push of firmware to device failed :%d\n", + result); + return B_ERROR; + } else { + TRACE_ALWAYS("Info: Push of firmware to device was successful.\n"); + return B_OK; + } +} + + +status_t +BeceemDevice::OnNotify(uint32 actualLength) +{ + // TODO : OnNotify -- Device state change notification + if (actualLength != fNotifyBufferLength) { + TRACE_ALWAYS("Data underrun error. %d of 8 bytes received\n", + actualLength); + return B_BAD_DATA; + } + + return B_OK; +} + + +status_t +BeceemDevice::GetLinkState(ether_link_state *linkState) +{ + // TODO : Report link state of WiMAX connection + // media as specified in net/if_media.h + // quality one tenth of a percent (0.1 == 10%, 1.0 == 100%) + // speed in bits / s + + // Our starting state + linkState->media = IFM_ETHER | IFM_100_TX; + + if (fHasConnection == false) { + linkState->quality = 0; + linkState->speed = 100000000; + } else { + linkState->quality = 1.0; + linkState->media |= IFM_ACTIVE; + // 40Mbits is the maximum theoretical speed for a 802.16e connection. + linkState->speed = 100000000; + } + + return B_OK; +} + diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemDevice.h b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemDevice.h new file mode 100644 index 0000000000..ef9012a668 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemDevice.h @@ -0,0 +1,132 @@ +/* + * Beceem WiMax USB Driver. + * Copyright (c) 2010 Alexander von Gluck + * Distributed under the terms of the MIT license. + * + * Based on GPL code developed by: Beceem Communications Pvt. Ltd + * + * Driver for USB Ethernet Control Model devices + * Copyright (C) 2008 Michael Lotz + * Distributed under the terms of the MIT license. + * + * Description: Wrangle Beceem wimax usb device + */ + +#ifndef _USB_BECEEM_DEVICE_H_ +#define _USB_BECEEM_DEVICE_H_ + +#include +#include + +#include "BeceemNVM.h" +#include "BeceemDDR.h" +#include "BeceemCPU.h" +#include "BeceemLED.h" + +#include "Driver.h" +#include "DeviceStruct.h" + +#define MAX_USB_IO_RETRIES 1 +#define MAX_USB_TRANSFER 255 + +class BeceemDevice + : + public BeceemNVM, + public BeceemDDR, + public BeceemCPU, + public BeceemLED +{ + +public: + BeceemDevice(usb_device device, const char *description); + virtual ~BeceemDevice(); + + status_t InitCheck() { return fStatus; }; + + status_t Open(uint32 flags); + bool IsOpen() { return fOpen; }; + + status_t Close(); + status_t Free(); + + status_t Read(uint8 *buffer, size_t *numBytes); + status_t Write(const uint8 *buffer, size_t *numBytes); + status_t Control(uint32 op, void *buffer, size_t length); + status_t LoadConfig(); + status_t PushConfig(unsigned int loc); + status_t PushFirmware(unsigned int loc); + + void Removed(); + + status_t CompareAndReattach(usb_device device); +virtual status_t SetupDevice(bool deviceReplugged); + + status_t ReadRegister(unsigned int reg, size_t size, uint32_t* buffer); + status_t WriteRegister(unsigned int reg, size_t size, uint32_t* buffer); + status_t BizarroReadRegister(unsigned int reg, size_t size, uint32_t* buffer); + status_t BizarroWriteRegister(unsigned int reg, size_t size, uint32_t* buffer); + +private: +static void _ReadCallback(void *cookie, int32 status, + void *data, uint32 actualLength); +static void _WriteCallback(void *cookie, int32 status, + void *data, uint32 actualLength); +static void _NotifyCallback(void *cookie, int32 status, + void *data, uint32 actualLength); + + status_t _SetupEndpoints(); + + status_t IdentifyChipset(); + +static const int kFrameSize = 1518; +static const uint8 kRXHeaderSize = 3; +static const uint8 kTXHeaderSize = 2; + +protected: + /* overrides */ +virtual status_t StartDevice() ; +virtual status_t StopDevice(); +virtual status_t OnNotify(uint32 actualLength) ; +virtual status_t GetLinkState(ether_link_state *state) ; +virtual status_t SetPromiscuousMode(bool bOn); +virtual status_t ModifyMulticastTable(bool add, uint8 address); + + + // state tracking + status_t fStatus; + bool fOpen; + vint32 fInsideNotify; + usb_device fDevice; + uint16 fVendorID; + uint16 fProductID; +const char * fDescription; + bool fNonBlocking; + + // Our driver device struct +struct WIMAX_DEVICE *pwmxdevice; + + // pipes for notifications and data io + usb_pipe fNotifyEndpoint; + usb_pipe fReadEndpoint; + usb_pipe fWriteEndpoint; + + // data stores for async usb transfers + uint32 fActualLengthRead; + uint32 fActualLengthWrite; + int32 fStatusRead; + int32 fStatusWrite; + sem_id fNotifyReadSem; + sem_id fNotifyWriteSem; + + uint8 * fNotifyBuffer; + uint32 fNotifyBufferLength; + + // connection data + sem_id fLinkStateChangeSem; + ether_address_t fMACAddress; + bool fHasConnection; + bool fTXBufferFull; +}; + +#endif //_USB_BECEEM_DEVICE_H_ + diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemLED.cpp b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemLED.cpp new file mode 100644 index 0000000000..f78f2d2516 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemLED.cpp @@ -0,0 +1,344 @@ +/* + * Beceem WiMax USB Driver. + * Copyright (c) 2010 Alexander von Gluck + * Distributed under the terms of the MIT license. + * + * Based on GPL code developed by: Beceem Communications Pvt. Ltd + * + * Beceem devices use fairly complex GPIO registers to control the + * device LED(s). As each implimentation uses the LEDs differently, + * each vendor provides a binary target configuration telling the + * driver what GPIO led register is used for what device state. + */ + +#include "Settings.h" +#include "BeceemLED.h" + +BeceemLED::BeceemLED() +{ + TRACE("Debug: Load LED handler\n"); +} + + +status_t +BeceemLED::LEDInit(WIMAX_DEVICE* wmxdevice) +{ + pwmxdevice = wmxdevice; + + uint8_t GPIO_Array[NUM_OF_LEDS+1]; + unsigned char ucIndex = 0; + uint32_t uiIndex = 0; + unsigned char* puCFGData = NULL; + unsigned char bData = 0; + + memset(GPIO_Array, GPIO_DISABLE_VAL, NUM_OF_LEDS+1); + + TRACE("Debug: Raw GPIO information: 0x%x\n", pwmxdevice->gpioInfo); + + snooze(500000); + + if (pwmxdevice->deviceChipID == 0xbece0120 + || pwmxdevice->deviceChipID == 0xbece0121) + { + /*Hardcode the values of GPIO numbers for ASIC board.*/ + GPIO_Array[RED_LED] = 2; + GPIO_Array[BLUE_LED] = 3; + GPIO_Array[YELLOW_LED] = GPIO_DISABLE_VAL; + GPIO_Array[GREEN_LED] = 4; + } else { + // for all possible GPIO pins... + for (ucIndex = 0; ucIndex < 32; ucIndex++) + { + switch(pwmxdevice->gpioInfo[ucIndex]) + { + case RED_LED: + TRACE("Debug: GPIO: %d found RED_LED!\n", ucIndex); + GPIO_Array[RED_LED] = ucIndex; + pwmxdevice->gpioBitMap |= (1<gpioBitMap |= (1<gpioBitMap |= (1<gpioBitMap |= (1<gpioBitMap); + + // Load GPIO configuration data from vendor config + puCFGData = (unsigned char *)&pwmxdevice->vendorcfg.HostDrvrConfig1; + + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) + { + bData = *puCFGData; + + // Check Bit 8 for polarity. If it is set, polarity is reverse + if (bData & 0x80) + { + pwmxdevice->LEDMap.LEDState[uiIndex].BitPolarity = 0; + // unset bit 8 + bData = bData & 0x7f; + } else { + // If polarity is not reverse, set to normal state. + pwmxdevice->LEDMap.LEDState[uiIndex].BitPolarity = 1; + } + + pwmxdevice->LEDMap.LEDState[uiIndex].LED_Type = ( bData ); + + if (bData <= NUM_OF_LEDS) + pwmxdevice->LEDMap.LEDState[uiIndex].GPIO_Num = GPIO_Array[bData]; + else + pwmxdevice->LEDMap.LEDState[uiIndex].GPIO_Num = GPIO_DISABLE_VAL; + + puCFGData++; + bData = *puCFGData; + + pwmxdevice->LEDMap.LEDState[uiIndex].LED_On_State = bData; + + puCFGData++; + bData = *puCFGData; + + pwmxdevice->LEDMap.LEDState[uiIndex].LED_Blink_State = bData; + + puCFGData++; + } + + GPIOReset(); // Set all GPIO pins to off + + for (uiIndex = 0; uiIndexLEDMap.LEDState[uiIndex].GPIO_Num != GPIO_DISABLE_VAL) { + LEDOn(uiIndex); + TRACE("Debug: LED[%d].LED_Type = %x\n", + uiIndex, pwmxdevice->LEDMap.LEDState[uiIndex].LED_Type); + TRACE("Debug: LED[%d].LED_On_State = %x\n", + uiIndex, pwmxdevice->LEDMap.LEDState[uiIndex].LED_On_State); + TRACE("Debug: LED[%d].LED_Blink_State = %x\n", + uiIndex, pwmxdevice->LEDMap.LEDState[uiIndex].LED_Blink_State); + TRACE("Debug: LED[%d].GPIO_Num = %i\n", + uiIndex, pwmxdevice->LEDMap.LEDState[uiIndex].GPIO_Num); + TRACE("Debug: LED[%d].Polarity = %d\n", + uiIndex, pwmxdevice->LEDMap.LEDState[uiIndex].BitPolarity); + snooze(500000); + LEDOff(uiIndex); + } + } + + + // Spawn LED monitor / blink thread + pwmxdevice->LEDThreadID = spawn_kernel_thread(LEDThread, + "usb_beceemwmx GPIO:LED", + B_NORMAL_PRIORITY, this); + + if (pwmxdevice->LEDThreadID < 1) { + TRACE("Error: Problem spawning LED Thread: %i\n", pwmxdevice->LEDThreadID); + return B_ERROR; + } + + resume_thread(pwmxdevice->LEDThreadID); + TRACE("Debug: LED Thread spawned: %i\n", pwmxdevice->LEDThreadID); + return B_OK; +} + + +status_t +BeceemLED::GPIOReset() +{ + int index = 0; + + TRACE("Debug: GPIO reset called\n"); + + for (index = 0; index < NUM_OF_LEDS; index++) { + if (pwmxdevice->LEDMap.LEDState[index].GPIO_Num != GPIO_DISABLE_VAL) + LEDOff(index); + } + + return B_OK; +} + + +status_t +BeceemLED::LEDThreadTerminate() +{ + status_t thread_return_value; + + TRACE("Debug: Terminating LED thread PID %i\n", pwmxdevice->LEDThreadID); + + // Lets make sure driverHalt is true... if it is false this will + // wait forever. + if (!pwmxdevice->driverHalt) { + TRACE_ALWAYS("Wierd... driver is not halted. Halting\n"); + pwmxdevice->driverHalt = true; + } + + return wait_for_thread(pwmxdevice->LEDThreadID, &thread_return_value); +} + + +status_t +BeceemLED::LightsOut() +{ + unsigned int uiIndex = 0; + + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) + { + if (pwmxdevice->LEDMap.LEDState[uiIndex].GPIO_Num != GPIO_DISABLE_VAL) { + LEDOff(uiIndex); + } + } + return B_OK; +} + + +status_t +BeceemLED::LEDOn(unsigned int index) +{ + status_t result; + uint32_t gpio_towrite = 0; + uint32_t uiResetValue = 0; + + gpio_towrite = 1<LEDMap.LEDState[index].GPIO_Num; + + if (pwmxdevice->LEDMap.LEDState[index].BitPolarity == 0) + result = BizarroWriteRegister(GPIO_OUTPUT_SET_REG, + sizeof(gpio_towrite), &gpio_towrite); + else + result = BizarroWriteRegister(GPIO_OUTPUT_CLR_REG, + sizeof(gpio_towrite), &gpio_towrite); + + if (result != B_OK) { + TRACE_ALWAYS("Error: Problem setting LED(%d) at GPIO 0x%x (bit %d)\n", + index, gpio_towrite, pwmxdevice->LEDMap.LEDState[index].GPIO_Num); + } + + uiResetValue = BizarroReadRegister(GPIO_MODE_REGISTER, + sizeof(uiResetValue), &uiResetValue); + uiResetValue |= gpio_towrite; + BizarroWriteRegister(GPIO_MODE_REGISTER, sizeof(uiResetValue), &uiResetValue); + + return B_OK; +} + + +status_t +BeceemLED::LEDOff(unsigned int index) +{ + status_t result; + uint32_t gpio_towrite = 0; + uint32_t uiResetValue = 0; + + gpio_towrite = 1<LEDMap.LEDState[index].GPIO_Num; + + if (pwmxdevice->LEDMap.LEDState[index].BitPolarity == 0) + result = BizarroWriteRegister(GPIO_OUTPUT_CLR_REG, + sizeof(gpio_towrite), &gpio_towrite); + else + result = BizarroWriteRegister(GPIO_OUTPUT_SET_REG, + sizeof(gpio_towrite), &gpio_towrite); + + if (result != B_OK) { + TRACE_ALWAYS("Error: Problem setting LED(%d) at GPIO 0x%x (bit %d)\n", + index, gpio_towrite, pwmxdevice->LEDMap.LEDState[index].GPIO_Num); + } + + uiResetValue = BizarroReadRegister(GPIO_MODE_REGISTER, + sizeof(uiResetValue), &uiResetValue); + uiResetValue |= gpio_towrite; + BizarroWriteRegister(GPIO_MODE_REGISTER, + sizeof(uiResetValue), &uiResetValue); + + return B_OK; +} + + +status_t +BeceemLED::LEDThread(void *cookie) +{ + bool LEDisON = false; + BeceemLED *led = (BeceemLED *)cookie; + + // While the driver is active + while (!led->pwmxdevice->driverHalt) + { + unsigned int uiIndex = 0; + unsigned int uiLedIndex = 0; + bool blink = false; + + // LED state changes will be at least 500ms apart + snooze(500000); + + // determine what the LED is doing in each state + switch(led->pwmxdevice->driverState) + { + case STATE_FWPUSH: + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) + { + if (led->pwmxdevice->LEDMap.LEDState[uiIndex].LED_Blink_State + & STATE_FWPUSH) + { + if (led->pwmxdevice->LEDMap.LEDState[uiIndex].GPIO_Num + != GPIO_DISABLE_VAL) { + uiLedIndex = uiIndex; + } + } + } + blink = true; + break; + + case STATE_NONET: + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) + { + if (led->pwmxdevice->LEDMap.LEDState[uiIndex].LED_On_State + & STATE_NONET) + { + if (led->pwmxdevice->LEDMap.LEDState[uiIndex].GPIO_Num + != GPIO_DISABLE_VAL) { + uiLedIndex = uiIndex; + } + } + } + blink = false; + break; + + default: + blink = false; + break; + } + + TRACE("Debug: Detected to use LedIndex: 0x%x for driver state 0x%x\n", + uiLedIndex, led->pwmxdevice->driverState); + + if (blink == true) { + led->LEDOff(uiLedIndex); + LEDisON = false; + snooze(500000); + led->LEDOn(uiLedIndex); + LEDisON = true; + } else { + // else we just flip on the color it needs to be. + led->LEDOn(uiLedIndex); + LEDisON = true; + snooze(500000); + } + + } + + return(B_OK); +} + diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemLED.h b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemLED.h new file mode 100644 index 0000000000..c479c0ab61 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemLED.h @@ -0,0 +1,48 @@ +/* + * Beceem WiMax USB Driver. + * Copyright (c) 2010 Alexander von Gluck + * Distributed under the terms of the MIT license. + */ + +#ifndef _USB_BECEEM_LED_H_ +#define _USB_BECEEM_LED_H_ + +#include + +#include "DeviceStruct.h" + +class BeceemLED +{ + +public: + BeceemLED(); + status_t LEDInit(WIMAX_DEVICE* wmxdevice); + status_t LEDThreadTerminate(); + status_t LEDOff(unsigned int index); + status_t LEDOn(unsigned int index); + status_t LightsOut(); +static status_t LEDThread(void *cookie); + + WIMAX_DEVICE* pwmxdevice; + +// yuck. These are in a parent class +virtual status_t ReadRegister(unsigned int reg, size_t size, uint32_t* buffer){ return NULL; }; +virtual status_t WriteRegister(unsigned int reg, size_t size, uint32_t* buffer){ return NULL; }; +virtual status_t BizarroReadRegister(unsigned int reg, size_t size, uint32_t* buffer){ return NULL; }; +virtual status_t BizarroWriteRegister(unsigned int reg, size_t size, uint32_t* buffer){ return NULL; }; + +private: + status_t GPIOReset(); + + +}; + +typedef enum _LEDColors{ + RED_LED = 1, + BLUE_LED = 2, + YELLOW_LED = 3, + GREEN_LED = 4 +} LEDColors; /*Enumerated values of different LED types*/ + +#endif // _USB_BECEEM_LED_H + diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemNVM.cpp b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemNVM.cpp new file mode 100644 index 0000000000..2be4583890 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemNVM.cpp @@ -0,0 +1,1025 @@ +/* + * Beceem WiMax USB Driver. + * Copyright (c) 2010 Alexander von Gluck + * Distributed under the terms of the MIT license. + * + * Based on GPL code developed by: Beceem Communications Pvt. Ltd + * + * Handle the non-volatile memory space on the Beceem device. + * These functions act as a middleware between the raw usb registers + * and the onboard non-volatile storage (which can be flash or eeprom) + */ + + +#include "Settings.h" + +#include + +#include "Driver.h" + +#include "BeceemDevice.h" +#include "BeceemNVM.h" + +BeceemNVM::BeceemNVM() +{ + TRACE("Debug: Load non-volatile memory handler\n"); +} + + +status_t +BeceemNVM::NVMInit(WIMAX_DEVICE* swmxdevice) +{ + TRACE("Debug: Init non-volatile memory handler\n"); + pwmxdevice = swmxdevice; + + pwmxdevice->nvmFlashCSDone = false; + + NVMFlush(); + + // Detect non-volatile memory type + if (NVMDetect() != B_OK) + return B_ERROR; + + unsigned short usNVMVersion = 0; + + NVMRead(NVM_VERSION_OFFSET, 2, (unsigned int*)&usNVMVersion); + pwmxdevice->nvmVerMinor = usNVMVersion&0xFF; + pwmxdevice->nvmVerMajor = ((usNVMVersion>>8)&0xFF); + + TRACE_ALWAYS("Info: non-volatile memory version: Major:%i Minor:%i\n", + pwmxdevice->nvmVerMajor, pwmxdevice->nvmVerMinor); + + return B_OK; +} + + +status_t +BeceemNVM::NVMFlush() +{ + unsigned int value = 0; + + /* Chipset Bug : Clear the Avail bits on the Read queue. The default + * value on this register is supposed to be 0x00001102. + * But we get 0x00001122. */ + TRACE("Debug: Fixing reset value on 0x0f003004\n"); + value = NVM_READ_DATA_AVAIL; + BizarroWriteRegister(NVM_SPI_Q_STATUS1_REG, sizeof(value), &value); + + /* Flush the all of the NVM queues. */ + TRACE("Debug: Flushing the NVM Queues...\n"); + value = NVM_ALL_QUEUE_FLUSH; + BizarroWriteRegister(SPI_FLUSH_REG, sizeof(value), &value); + value = 0; + BizarroWriteRegister(SPI_FLUSH_REG, sizeof(value), &value); + +return B_OK; +} + + +status_t +BeceemNVM::NVMDetect() +{ + unsigned int uiData = 0; + + EEPROMBulkRead(0x0, 4, &uiData); + if (uiData == BECM) + { + TRACE_ALWAYS("Info: EEPROM non-volatile memory detected.\n"); + pwmxdevice->nvmType = NVM_EEPROM; + pwmxdevice->nvmDSDSize = EEPROMGetSize(); + return B_OK; + } + + // As this isn't a EEPROM device, lets look for a flash CS... + if (FlashReadCS() != B_OK) + return B_ERROR; + + FlashBulkRead(0x0 + pwmxdevice->nvmFlashCalStart, 4, &uiData); + if(uiData == BECM) + { + TRACE_ALWAYS("Info: Flash non-volatile memory detected.\n"); + pwmxdevice->nvmType = NVM_FLASH; + pwmxdevice->nvmDSDSize = FlashGetSize(); + return B_OK; + } + + pwmxdevice->nvmType = NVM_UNKNOWN; + + TRACE_ALWAYS("Error: Couldn't detect non-volatile storage method, found 0x%X\n", + uiData); + return B_ERROR; +} + + +status_t +BeceemNVM::NVMChipSelect(unsigned int offset) +{ + int ChipIndex = 0; + unsigned int PartNum = 0; + unsigned int FlashConfig = 0; + unsigned int GPIOConfig = 0; + + ChipIndex = offset / FLASH_PART_SIZE; + + // Chip to be selected is already selected + if (bSelectedChip == ChipIndex) + return B_OK; + + TRACE("Debug: Selecting chip %d for transaction at 0x%x\n", ChipIndex, offset); + + // Migrate selected chip to new selection + bSelectedChip = ChipIndex; + + BizarroReadRegister(FLASH_CONFIG_REG, 4, &FlashConfig); + BizarroReadRegister(FLASH_GPIO_CONFIG_REG, 4, &GPIOConfig); + + // TRACE("Reading GPIO config 0x%x\n", &GPIOConfig); + // TRACE("Reading Flash config 0x%x\n", &FlashConfig); + + switch(ChipIndex) + { + case 0: + PartNum = 0; + break; + case 1: + PartNum = 3; + GPIOConfig |= (0x4 << 12); + break; + case 2: + PartNum = 1; + GPIOConfig |= (0x1 << 12); + break; + case 3: + PartNum = 2; + GPIOConfig |= (0x2 << 12); + break; + } + + if (PartNum == ((FlashConfig >> 12) & 0x3)) + return B_OK; + + FlashConfig &= 0xFFFFCFFF; + FlashConfig = (FlashConfig | (PartNum<<12)); + + // TRACE("Writing GPIO config 0x%x\n", &GPIOConfig); + // TRACE("Writing Flash config 0x%x\n", &FlashConfig); + + TRACE("Debug: Selecting chip %x.\n", bSelectedChip); + + BizarroWriteRegister(FLASH_GPIO_CONFIG_REG, 4, &GPIOConfig); + snooze(100); + + BizarroWriteRegister(FLASH_CONFIG_REG, 4, &FlashConfig); + snooze(100); + + return B_OK; +} + + +int +BeceemNVM::NVMRead(unsigned int offset, unsigned int size, unsigned int* buffer) +{ + unsigned int temp = 0; + unsigned int value = 0; + int Status = 0; + unsigned int myOffset = 0; + + if (pwmxdevice->nvmType == NVM_FLASH) { + + // TODO : if bFlashRawRead is requested, this will need to be skipped + // Increase offset by FlashCalibratedStart + myOffset = offset + pwmxdevice->nvmFlashCalStart; + + TRACE("Debug: Performing read of non-volatile flash memory at 0x%x (%d)\n", + myOffset, size); + + // If firmware was already pushed, Beceem notes a hardware bug here. + if (pwmxdevice->driverFwPushed == true) { + // Save data at register + BizarroReadRegister(0x0f000C80, sizeof(temp), &temp); + // Flash register with 0 + BizarroWriteRegister(0x0f000C80, sizeof(value), &value); + } + + Status = FlashBulkRead(myOffset, + size, + buffer); + + if (pwmxdevice->driverFwPushed == true) { + // Write stored value back + BizarroWriteRegister(0x0f000C80, sizeof(temp), &temp); + } + + } else if (pwmxdevice->nvmType == NVM_EEPROM) { + TRACE_ALWAYS("TODO: NVM_EEPROM Read\n"); + Status = -1; + } else { + Status = -1; + } + + return Status; +} + + +int +BeceemNVM::NVMWrite(unsigned int offset, unsigned int size, unsigned int* buffer) +{ + unsigned int temp = 0; + unsigned int value = 0; + int Status = 0; + + if (pwmxdevice->nvmType == NVM_FLASH) { + // Save data at register + BizarroReadRegister(0x0f000C80, sizeof(temp), &temp); + + // Flash register with 0 + BizarroWriteRegister(0x0f000C80, sizeof(value), &value); + + Status = FlashBulkWrite(offset, + size, + buffer); + + // Write stored value back + BizarroWriteRegister(0x0f000C80, sizeof(temp), &temp); + + } else if (pwmxdevice->nvmType == NVM_EEPROM) { + TRACE_ALWAYS("Todo: NVM_EEPROM Write\n"); + Status = -1; + } else { + Status = -1; + } + + return Status; +} + + +int +BeceemNVM::FlashGetBaseAddr() +{ + if (pwmxdevice->driverDDRinit == true) { + if (pwmxdevice->nvmFlashCSDone == true && pwmxdevice->nvmFlashRaw == false && + !((pwmxdevice->nvmFlashMajor == 1) && (pwmxdevice->nvmFlashMinor == 1)) ) { + return pwmxdevice->nvmFlashBaseAddr; + } else { + return FLASH_CONTIGIOUS_START_ADDR_AFTER_INIT; + } + } else { + if (pwmxdevice->nvmFlashCSDone == true && pwmxdevice->nvmFlashRaw == false && + !((pwmxdevice->nvmFlashMajor == 1) && (pwmxdevice->nvmFlashMinor == 1)) ) { + return pwmxdevice->nvmFlashBaseAddr | FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT; + } else { + return FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT; + } + } + + TRACE_ALWAYS("Error: no base address?\n"); + return B_ERROR; +} + + +unsigned int +BeceemNVM::FlashGetSize() +{ + // TODO : Check for Flash2X + return 32 * 1024; +} + + +unsigned long +BeceemNVM::FlashReadID() +{ + unsigned long RDID = 0; + unsigned int value; + // Read the ID from FLASH_CMD_READ_ID + value = (FLASH_CMD_READ_ID<<24); + BizarroWriteRegister(FLASH_SPI_CMDQ_REG, sizeof(value), &value); + + snooze(10); + + // Read SPI READQ Register, The output will be 4 bytes long + // The ID is the first 3 bytes. + BizarroReadRegister(FLASH_SPI_READQ_REG, sizeof(RDID), (unsigned int*)&RDID); + + return (RDID >>8); +} + + +status_t +BeceemNVM::FlashReadCS() +{ + unsigned int value; + + // Set initial start addresses + pwmxdevice->nvmFlashCSStart = FLASH_CS_INFO_START_ADDR; + pwmxdevice->nvmFlashBaseAddr = 0; + pwmxdevice->nvmFlashCalStart = 0; + pwmxdevice->nvmFlashMajor = 0; + pwmxdevice->nvmFlashMinor = 0; + + memset(pwmxdevice->nvmFlashCSInfo, 0 , sizeof(FLASH_CS_INFO)); + + if (pwmxdevice->driverDDRinit == false) + { + value = FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT; + BizarroWriteRegister(0xAF00A080, sizeof(value), &value); + } + + // CS Signature(4), Minor(2), Major(2) + FlashBulkRead(pwmxdevice->nvmFlashCSStart, 8, (unsigned int*)pwmxdevice->nvmFlashCSInfo); + pwmxdevice->nvmFlashCSInfo->FlashLayoutVersion = ntohl(pwmxdevice->nvmFlashCSInfo->FlashLayoutVersion); + + TRACE_ALWAYS("Info: Flash CS Version/Signature: 0x%X/0x%X\n", + (pwmxdevice->nvmFlashCSInfo->FlashLayoutVersion), + ntohl(pwmxdevice->nvmFlashCSInfo->MagicNumber)); + + if ( ntohl(pwmxdevice->nvmFlashCSInfo->MagicNumber) == FLASH_CS_SIGNATURE ) { + pwmxdevice->nvmFlashMajor = MAJOR_VERSION(pwmxdevice->nvmFlashCSInfo->FlashLayoutVersion); + pwmxdevice->nvmFlashMinor = MINOR_VERSION(pwmxdevice->nvmFlashCSInfo->FlashLayoutVersion); + } else { + TRACE_ALWAYS("Error: Unknown flash magic signature!\n"); + pwmxdevice->nvmFlashMajor = 0; + pwmxdevice->nvmFlashMinor = 0; + return B_ERROR; + } + + if (pwmxdevice->nvmFlashMajor == 0x1) + { + // device is older flash map + FlashBulkRead(pwmxdevice->nvmFlashCSStart, sizeof(FLASH_CS_INFO), (unsigned int*)pwmxdevice->nvmFlashCSInfo); + snooze(100); + FlashCSFlip(pwmxdevice->nvmFlashCSInfo); + FlashCSDump(pwmxdevice->nvmFlashCSInfo); + + pwmxdevice->nvmFlashCalStart = (pwmxdevice->nvmFlashCSInfo->OffsetFromZeroForCalibrationStart); + + if(!((pwmxdevice->nvmFlashMajor == 1) && (pwmxdevice->nvmFlashMinor == 1))) + { + pwmxdevice->nvmFlashCSStart = (pwmxdevice->nvmFlashCSInfo->OffsetFromZeroForControlSectionStart); + } + + // TODO : Flash Write sizes.. no write support atm + #if 0 + if((FLASH_CS_SIGNATURE == (pwmxdevice->nvmFlashCSInfo->MagicNumber)) && + (SCSI_FIRMWARE_MINOR_VERSION <= MINOR_VERSION(pwmxdevice->nvmFlashCSInfo->SCSIFirmwareVersion)) && + (FLASH_SECTOR_SIZE_SIG == (pwmxdevice->nvmFlashCSInfo->FlashSectorSizeSig)) && + (BYTE_WRITE_SUPPORT == (pwmxdevice->nvmFlashCSInfo->FlashWriteSupportSize))) + { + pwmxdevice->ulFlashWriteSize = (pwmxdevice->nvmFlashCSInfo->FlashWriteSupportSize); + pwmxdevice->fpFlashWrite = flashByteWrite; + pwmxdevice->fpFlashWriteWithStatusCheck = flashByteWriteStatus; + } else { + pwmxdevice->ulFlashWriteSize = MAX_RW_SIZE; + pwmxdevice->fpFlashWrite = flashWrite; + pwmxdevice->fpFlashWriteWithStatusCheck = flashWriteStatus; + } + */ + + //BcmGetFlashSectorSize(Adapter, (Adapter->psFlashCSInfo->FlashSectorSizeSig), + // (Adapter->psFlashCSInfo->FlashSectorSize)); + #endif + + pwmxdevice->nvmFlashBaseAddr = pwmxdevice->nvmFlashCSInfo->FlashBaseAddr & 0xFCFFFFFF; + + } else { + // device is newer flash map layout + TRACE_ALWAYS("New flash map detected, not yet supported!\n"); + return B_ERROR; + } + + pwmxdevice->nvmFlashID = FlashReadID(); + pwmxdevice->nvmFlashCSDone = true; + + return B_OK; +} + + +status_t +BeceemNVM::FlashCSFlip(PFLASH_CS_INFO FlashCSInfo) +{ + FlashCSInfo->MagicNumber = ntohl(FlashCSInfo->MagicNumber); + FlashCSInfo->FlashLayoutVersion = ntohl(FlashCSInfo->FlashLayoutVersion); + FlashCSInfo->ISOImageVersion = ntohl(FlashCSInfo->ISOImageVersion); + + // won't convert according to old assumption + FlashCSInfo->SCSIFirmwareVersion = (FlashCSInfo->SCSIFirmwareVersion); + + FlashCSInfo->OffsetFromZeroForPart1ISOImage = ntohl(FlashCSInfo->OffsetFromZeroForPart1ISOImage); + FlashCSInfo->OffsetFromZeroForScsiFirmware = ntohl(FlashCSInfo->OffsetFromZeroForScsiFirmware); + FlashCSInfo->SizeOfScsiFirmware = ntohl(FlashCSInfo->SizeOfScsiFirmware); + FlashCSInfo->OffsetFromZeroForPart2ISOImage = ntohl(FlashCSInfo->OffsetFromZeroForPart2ISOImage); + FlashCSInfo->OffsetFromZeroForCalibrationStart = ntohl(FlashCSInfo->OffsetFromZeroForCalibrationStart); + FlashCSInfo->OffsetFromZeroForCalibrationEnd = ntohl(FlashCSInfo->OffsetFromZeroForCalibrationEnd); + FlashCSInfo->OffsetFromZeroForVSAStart = ntohl(FlashCSInfo->OffsetFromZeroForVSAStart); + FlashCSInfo->OffsetFromZeroForVSAEnd = ntohl(FlashCSInfo->OffsetFromZeroForVSAEnd); + FlashCSInfo->OffsetFromZeroForControlSectionStart = ntohl(FlashCSInfo->OffsetFromZeroForControlSectionStart); + FlashCSInfo->OffsetFromZeroForControlSectionData = ntohl(FlashCSInfo->OffsetFromZeroForControlSectionData); + FlashCSInfo->CDLessInactivityTimeout = ntohl(FlashCSInfo->CDLessInactivityTimeout); + FlashCSInfo->NewImageSignature = ntohl(FlashCSInfo->NewImageSignature); + FlashCSInfo->FlashSectorSizeSig = ntohl(FlashCSInfo->FlashSectorSizeSig); + FlashCSInfo->FlashSectorSize = ntohl(FlashCSInfo->FlashSectorSize); + FlashCSInfo->FlashWriteSupportSize = ntohl(FlashCSInfo->FlashWriteSupportSize); + FlashCSInfo->TotalFlashSize = ntohl(FlashCSInfo->TotalFlashSize); + FlashCSInfo->FlashBaseAddr = ntohl(FlashCSInfo->FlashBaseAddr); + FlashCSInfo->FlashPartMaxSize = ntohl(FlashCSInfo->FlashPartMaxSize); + FlashCSInfo->IsCDLessDeviceBootSig = ntohl(FlashCSInfo->IsCDLessDeviceBootSig); + FlashCSInfo->MassStorageTimeout = ntohl(FlashCSInfo->MassStorageTimeout); + + return B_OK; +} + + +status_t +BeceemNVM::FlashCSDump(PFLASH_CS_INFO FlashCSInfo) +{ + TRACE_ALWAYS("************Debug dump of Flash CS Info map************\n"); + TRACE_ALWAYS(" MagicNumber is 0x%x\n", FlashCSInfo->MagicNumber); + TRACE_ALWAYS(" FlashLayoutVersion is 0x%x\n", FlashCSInfo->FlashLayoutVersion); + TRACE_ALWAYS(" ISOImageVersion is 0x%x\n", FlashCSInfo->ISOImageVersion); + TRACE_ALWAYS(" SCSIFirmwareVersion is 0x%x\n", FlashCSInfo->SCSIFirmwareVersion); + TRACE_ALWAYS(" OffsetFromZeroForPart1ISOImage is 0x%x\n", FlashCSInfo->OffsetFromZeroForPart1ISOImage); + TRACE_ALWAYS(" OffsetFromZeroForScsiFirmware is 0x%x\n", FlashCSInfo->OffsetFromZeroForScsiFirmware); + TRACE_ALWAYS(" SizeOfScsiFirmware is 0x%x\n", FlashCSInfo->SizeOfScsiFirmware); + TRACE_ALWAYS(" OffsetFromZeroForPart2ISOImage is 0x%x\n", FlashCSInfo->OffsetFromZeroForPart2ISOImage); + TRACE_ALWAYS(" OffsetFromZeroForCalibrationStart is 0x%x\n", FlashCSInfo->OffsetFromZeroForCalibrationStart); + TRACE_ALWAYS(" OffsetFromZeroForCalibrationEnd is 0x%x\n", FlashCSInfo->OffsetFromZeroForCalibrationEnd); + TRACE_ALWAYS(" OffsetFromZeroForVSAStart is 0x%x\n", FlashCSInfo->OffsetFromZeroForVSAStart); + TRACE_ALWAYS(" OffsetFromZeroForVSAEnd is 0x%x\n", FlashCSInfo->OffsetFromZeroForVSAEnd); + TRACE_ALWAYS("OffsetFromZeroForControlSectionStart is 0x%x\n", FlashCSInfo->OffsetFromZeroForControlSectionStart); + TRACE_ALWAYS(" OffsetFromZeroForControlSectionData is 0x%x\n", FlashCSInfo->OffsetFromZeroForControlSectionData); + TRACE_ALWAYS(" CDLessInactivityTimeout is 0x%x\n", FlashCSInfo->CDLessInactivityTimeout); + TRACE_ALWAYS(" NewImageSignature is 0x%x\n", FlashCSInfo->NewImageSignature); + TRACE_ALWAYS(" FlashSectorSizeSig is 0x%x\n", FlashCSInfo->FlashSectorSizeSig); + TRACE_ALWAYS(" FlashSectorSize is 0x%x\n", FlashCSInfo->FlashSectorSize); + TRACE_ALWAYS(" FlashWriteSupportSize is 0x%x\n", FlashCSInfo->FlashWriteSupportSize); + TRACE_ALWAYS(" TotalFlashSize is 0x%x\n", FlashCSInfo->TotalFlashSize); + TRACE_ALWAYS(" FlashBaseAddr is 0x%x\n", FlashCSInfo->FlashBaseAddr); + TRACE_ALWAYS(" FlashPartMaxSize is 0x%x\n", FlashCSInfo->FlashPartMaxSize); + TRACE_ALWAYS(" IsCDLessDeviceBootSig is 0x%x\n", FlashCSInfo->IsCDLessDeviceBootSig); + TRACE_ALWAYS(" MassStorageTimeout is 0x%x\n", FlashCSInfo->MassStorageTimeout); + TRACE_ALWAYS("*******************************************************\n"); + + return B_OK; +} + + +status_t +BeceemNVM::FlashBulkRead(unsigned int offset, unsigned int size, unsigned int* buffer) +{ + unsigned int workOffset = offset; // our work offset + unsigned int partOffset = 0; // register we will read + unsigned int workBytes = 0; // bytes we are working on + unsigned int bytesLeft = size; // counter holding bytes left + unsigned int outputOffset = 0; // where we are in the output + + if (pwmxdevice->driverHalt == true) + return -ENODEV; + + if (size > sizeof(&buffer)) + TRACE("Warning: Reading more then the buffer can handle\n"); + + bSelectedChip = RESET_CHIP_SELECT; + + TRACE("Debug: About to read %d bytes from 0x%x \n", size, offset); + + while (bytesLeft > 0) + { + NVMChipSelect(workOffset); + + partOffset = (workOffset & (FLASH_PART_SIZE - 1)) + FlashGetBaseAddr(); + workBytes = MIN(MAX_RW_SIZE,bytesLeft); + // We read the max RW size or whats left + + TRACE("Debug: reading %d bytes from 0x%x to 0x%x (output offset %d)\n", + workBytes, partOffset, partOffset + workBytes, outputOffset); + + if (ReadRegister(partOffset, workBytes, + (unsigned int*)((unsigned char*)buffer+outputOffset)) != B_OK) { + // I've only done this once before. + TRACE_ALWAYS("Error: Read error at 0x%x. Read of %d bytes failed.\n", + partOffset, workBytes); + bSelectedChip = RESET_CHIP_SELECT; + return B_ERROR; + } + + bytesLeft -= workBytes; + // subtract the bytes we read + workOffset += workBytes; + // add the bytes we read to the offset + outputOffset += workBytes; + // increase output location by number of bytes worked on + } + + bSelectedChip = RESET_CHIP_SELECT; + return B_OK; +} + + +status_t +BeceemNVM::RestoreBlockProtect(unsigned long writestatus) +{ + unsigned int value; + value = (FLASH_CMD_WRITE_ENABLE<< 24); + BizarroWriteRegister(FLASH_SPI_CMDQ_REG, sizeof(value), &value); + + snooze(20); + value = (FLASH_CMD_STATUS_REG_WRITE<<24)|(writestatus << 16); + BizarroWriteRegister(FLASH_SPI_CMDQ_REG, sizeof(value), &value); + snooze(20); + + return B_OK; +} + + +unsigned long +BeceemNVM::DisableBlockProtect(unsigned int offset, size_t size) +{ + return 0; +} + + +status_t +BeceemNVM::FlashBulkWrite(unsigned int offset, unsigned int size, unsigned int* buffer) +{ + unsigned long BPStatus = 0; + unsigned int OffsetFromSectStart = 0; + unsigned int CurrSectOffsetAddr = 0; + unsigned int NumSectTobeRead = 0; + unsigned int SectAlignAddr = 0; + unsigned int SectBoundary = 0; + unsigned int PartOffset = 0; + // unsigned int uiIndex = 0; // used in validation + + status_t Status = B_ERROR; + + unsigned char* ucBuffer = (unsigned char*)buffer; + // unsigned char ucReadBk[16] = {0}; // used in validation + char* TempBuffer = NULL; + + // if (fRemoved == true) + // return -ENODEV; + + OffsetFromSectStart = offset & ~(NVM_SECTOR_SIZE - 1); + SectAlignAddr = offset & ~(NVM_SECTOR_SIZE - 1); + SectBoundary = SectAlignAddr + NVM_SECTOR_SIZE; + + TempBuffer = (char*)malloc(NVM_SECTOR_SIZE); + + if (TempBuffer == NULL) { + TRACE_ALWAYS("Error: Couldn't allocate temporary buffer.\n"); + Status = B_ERROR; + goto FlashBulkWriteEND; + } + + // See if data to be written goes over sector boundry + if (offset + size < SectBoundary) { + NumSectTobeRead = 1; + } else { + // Number of sectors = Last sector start address/First sector start address + NumSectTobeRead = (CurrSectOffsetAddr + size) / NVM_SECTOR_SIZE; + if ((CurrSectOffsetAddr + size)%NVM_SECTOR_SIZE) + { + NumSectTobeRead++; + } + } + + // TODO : Flash2x? + + bSelectedChip = RESET_CHIP_SELECT; + + while (NumSectTobeRead) + { + NVMChipSelect(offset); + PartOffset = (offset & (FLASH_PART_SIZE - 1)) + FlashGetBaseAddr(); + + if (FlashBulkRead(OffsetFromSectStart, + NVM_SECTOR_SIZE, + (unsigned int*)TempBuffer) != B_OK ) + { + TRACE_ALWAYS("Error: Couldn't perform FlashBulkRead\n"); + Status = B_ERROR; + goto FlashBulkWriteEND; + } + + BPStatus = DisableBlockProtect(SectAlignAddr, NVM_SECTOR_SIZE); + + if (NumSectTobeRead > 1) + { + memcpy(&TempBuffer[CurrSectOffsetAddr], ucBuffer, SectBoundary-(SectAlignAddr+CurrSectOffsetAddr)); + ucBuffer += ((SectBoundary-(SectAlignAddr + CurrSectOffsetAddr))); + size -= (SectBoundary-(SectAlignAddr + CurrSectOffsetAddr)); + } else { + memcpy(&TempBuffer[CurrSectOffsetAddr],ucBuffer, size); + } + + // TODO : SaveHeaderIfPresent if IsFlash2x? + + FlashSectorErase(PartOffset, 1); + + #if 0 + //for(uiIndex = 0; uiIndex < NVM_SECTOR_SIZE; uiIndex += MAX_RW_SIZE) + //{ + //if(devicePresent == false) + //{ + // free(TempBuffer); + // Status = B_ERROR; + // return Status; + //} + //if(B_OK != (*Adapter->fpFlashWrite)(Adapter,uiPartOffset+uiIndex,(&pTempBuff[uiIndex]))) + //{ + // free(TempBuffer); + // Status = B_ERROR; + // return Status; + //} + //} + + // TODO: Data verification needs structs not yet implimented.. this is optional + // add verify boolean option to function in future + for(uiIndex = 0;uiIndex < NVM_SECTOR_SIZE ;uiIndex += MAX_RW_SIZE) + { + if(FlashBulkRead(OffsetFromSectStart+uiIndex, MAX_RW_SIZE ,(unsigned int*)ucReadBk)) + { + if(Adapter->ulFlashWriteSize == 1) + { + unsigned int uiReadIndex = 0; + for(uiReadIndex = 0; uiReadIndex < 16; uiReadIndex++) + { + if(ucReadBk[uiReadIndex] != TempBuff[uiIndex+uiReadIndex]) + { + if(B_OK != (*Adapter->fpFlashWriteWithStatusCheck)(Adapter,uiPartOffset+uiIndex+uiReadIndex,&pTempBuff[uiIndex+uiReadIndex])) + { + Status = STATUS_FAILURE; + goto BeceemFlashBulkWrite_EXIT; + } + } + } + } + else + { + if(OsalMemCompare(ucReadBk,&pTempBuff[uiIndex],MAX_RW_SIZE)) + { + if(STATUS_SUCCESS != (*Adapter->fpFlashWriteWithStatusCheck)(Adapter,uiPartOffset+uiIndex,&pTempBuff[uiIndex])) + { + Status = STATUS_FAILURE; + goto BeceemFlashBulkWrite_EXIT; + } + } + } + } + } + #endif + + if(BPStatus) + { + RestoreBlockProtect(BPStatus); + BPStatus = 0; + } + + CurrSectOffsetAddr = 0; + SectAlignAddr = SectBoundary; + SectBoundary += NVM_SECTOR_SIZE; + OffsetFromSectStart += NVM_SECTOR_SIZE; + NumSectTobeRead--; + } + +FlashBulkWriteEND: + + if (BPStatus) + { + RestoreBlockProtect(BPStatus); + } + + if (TempBuffer) + free(TempBuffer); + + bSelectedChip = RESET_CHIP_SELECT; + return Status; +} + + +status_t +BeceemNVM::FlashSectorErase(unsigned int addr, unsigned int numOfSectors) +{ + unsigned int iIndex = 0, iRetries = 0; + unsigned int uiStatus = 0; + unsigned int value; + + TRACE("Debug: Erasing %d sectors at 0x%x\n", numOfSectors, addr); + + for (iIndex = 0 ; iIndex < numOfSectors ; iIndex++) + { + value = 0x06000000; + BizarroWriteRegister(FLASH_SPI_CMDQ_REG, sizeof(value), &value); + + value = (0xd8000000 | (addr & 0xFFFFFF)); + BizarroWriteRegister(FLASH_SPI_CMDQ_REG, sizeof(value), &value); + iRetries = 0; + + do + { + value = (FLASH_CMD_STATUS_REG_READ << 24); + if ( BizarroWriteRegister(FLASH_SPI_CMDQ_REG, + sizeof(value), &value) != B_OK ) + { + TRACE_ALWAYS("Error: Failure writing FLASH_SPI_CMDQ_REG\n"); + return B_ERROR; + } + + if ( BizarroReadRegister(FLASH_SPI_READQ_REG, + sizeof(uiStatus), &uiStatus) != B_OK) + { + TRACE_ALWAYS("Error: Failure reading FLASH_SPI_READQ_REG\n"); + return B_ERROR; + } + iRetries++; + // After every try lets make the CPU free for 10 ms. generally time + // taken by the the sector erase cycle is 500 ms to 40000 msec. + // Sleeping 10 ms won't hamper performance in any case. + snooze(10); + } while ((uiStatus & 0x1) && (iRetries < 400)); + + if (uiStatus & 0x1) + { + TRACE_ALWAYS("Error: sector erase retry loop exhausted"); + return B_ERROR; + } + + addr += NVM_SECTOR_SIZE; + } + + return B_OK; +} + + +status_t +BeceemNVM::ReadMACFromNVM(ether_address *address) +{ + status_t Status = B_ERROR; + unsigned char MacAddr[6] = {0}; + + Status = NVMRead(MAC_ADDR_OFFSET, + 6, + (unsigned int*)&MacAddr[0]); + + memcpy(address, MacAddr, 6); + + return (Status); +} + + +unsigned int +BeceemNVM::EEPROMGetSize() +{ + unsigned int uiData = 0; + unsigned int uiIndex = 0; + + // To find the EEPROM size read the possible boundaries of the + // EEPROM like 4K,8K etc..accessing the EEPROM beyond its size will + // result in wrap around. So when we get the End of the EEPROM we will + // get 'BECM' string which is indeed at offset 0. + + EEPROMBulkRead(0x0, 4, &uiData); + + if (ntohl(uiData) == BECM) + { + // If EEPROM is present ,it will have 'BECM' string at 0th offset. + + for (uiIndex = 1 ; uiIndex <= 256; uiIndex *= 2) + { + EEPROMBulkRead(uiIndex * 1024, 4, &uiData); + + if (ntohl(uiData) == BECM) + { + return uiIndex * 1024; + } + } + } + + return B_ERROR; +} + + +status_t +BeceemNVM::EEPROMRead(unsigned int offset, unsigned int *pdwData) +{ + // Read 4 bytes from EEPROM + + unsigned int dwReadValue = 0; + unsigned int dwRetries = 16; + unsigned int Value = 0; + + // read 0x0f003020 until bit 2 of 0x0f003008 is set. + BizarroReadRegister(EEPROM_SPI_Q_STATUS_REG, + sizeof(unsigned int), &Value); + + while ((( Value >>2 )&1)==0 ) + { + dwRetries--; + + snooze(200); + + if (dwRetries == 0) + { + TRACE_ALWAYS("Error: CMD FIFO is not empty\n"); + return B_ERROR; + } + + BizarroReadRegister(EEPROM_SPI_Q_STATUS_REG, + sizeof(unsigned int), &Value); + } + + // wrm (0x0f003018, 0xNbXXXXXX) + // N is the number of bytes u want to read + // (0 means 1, f means 16, b is the opcode for page read) + + // Follow it up by N executions of rdm(0x0f003020) to read + // the rxed bytes from rx queue. + + offset |= 0x3b000000; + + BizarroWriteRegister(EEPROM_CMDQ_SPI_REG, sizeof(unsigned int), &offset); + + dwRetries = 50; + + BizarroReadRegister(EEPROM_SPI_Q_STATUS_REG, sizeof(unsigned int), &Value); + + while ((( Value >>1)&1)==1 ) + { + dwRetries--; + + snooze(200); + + if (dwRetries == 0) + { + TRACE_ALWAYS("Error: READ FIFO is empty\n"); + return B_ERROR; + } + + BizarroReadRegister(EEPROM_SPI_Q_STATUS_REG, sizeof(unsigned int), &Value); + } + + BizarroReadRegister(EEPROM_READ_DATAQ_REG, sizeof(unsigned int), &Value); + + dwReadValue = Value; + + BizarroReadRegister(EEPROM_READ_DATAQ_REG, sizeof(unsigned int), &Value); + + dwReadValue |= (Value<<8); + + BizarroReadRegister(EEPROM_READ_DATAQ_REG, sizeof(unsigned int), &Value); + + dwReadValue |= (Value<<16); + + BizarroReadRegister(EEPROM_READ_DATAQ_REG, sizeof(unsigned int), &Value); + + dwReadValue |= (Value<<24); + + *pdwData = dwReadValue; + + return B_OK; +} + + +status_t +BeceemNVM::EEPROMBulkRead( unsigned int offset, size_t numBytes, unsigned int* buffer) +{ + unsigned int uiData[4] = {0}; + unsigned int uiBytesRemaining = numBytes; + unsigned int uiIndex = 0; + + unsigned int uiTempOffset = 0; + unsigned int uiExtraBytes = 0; + unsigned char* pcBuff = (unsigned char*)buffer; + + + TRACE("Debug: Reading %x bytes at offset %x.\n", numBytes, offset); + + if (offset%16 && uiBytesRemaining) + { + uiTempOffset = offset - (offset%16); + uiExtraBytes = offset - uiTempOffset; + + EEPROMBulkRead(uiTempOffset, 16, (unsigned int*)&uiData[0]); + + if (uiBytesRemaining >= (16 - uiExtraBytes)) + { + memcpy(buffer, + (((unsigned char*)&uiData[0])+uiExtraBytes), + 16 - uiExtraBytes); + uiBytesRemaining -= (16 - uiExtraBytes); + uiIndex += (16 - uiExtraBytes); + offset += (16 - uiExtraBytes); + } else { + memcpy(buffer, + (((unsigned char*)&uiData[0])+uiExtraBytes), + uiBytesRemaining); + uiIndex += uiBytesRemaining; + offset += uiBytesRemaining; + uiBytesRemaining = 0; + } + } + + while (uiBytesRemaining) + { + if (uiBytesRemaining >= 16) + { // for the requests more than or equal to 16 bytes, + // use bulk read function to make the access faster. + + // TODO : Impliment function to read more data faster + //ReadBeceemEEPROMBulk(offset, &uiData[0]); + EEPROMRead(offset, &uiData[0]); + memcpy(pcBuff + uiIndex, &uiData[0], 16); // yes requested. + offset += 16; + uiBytesRemaining -= 16; + uiIndex += 16; + } else if (uiBytesRemaining >= 4) { + EEPROMRead(offset, &uiData[0]); + memcpy(pcBuff + uiIndex, &uiData[0], 4); // yes requested. + offset += 4; + uiBytesRemaining -= 4; + uiIndex+= 4; + } else { + // Handle the reads less than 4 bytes... + unsigned char* pCharBuff = (unsigned char*)buffer; + pCharBuff += uiIndex; + EEPROMRead(offset, &uiData[0]); // read 4 byte + memcpy(pCharBuff, &uiData[0], uiBytesRemaining); + // copy only the bytes requested. + uiBytesRemaining = 0; + } + } + + return B_OK; +} + + +status_t +BeceemNVM::ValidateDSD(unsigned long hwParam) +{ + unsigned long dwReadValue = hwParam; + unsigned short HwParamLen = 0; + unsigned char* puBuffer = NULL; + unsigned short usChksmCalc = 0; + unsigned short usChksmOrg = 0; + + dwReadValue = (dwReadValue + DSD_START_OFFSET); + // Get DSD start offset + + // DSD + // +---+ + // B| 2 | Hardware Param Length + // Y+---+ + // T| X | Hardware Param + // E+---+ + // S| 2 | Stored Checksum + // +---+ + + /* Read the Length of structure */ + NVMRead(dwReadValue, 2, (unsigned int*)&HwParamLen); + HwParamLen = ntohs(HwParamLen); + + /* Validate length */ + if (0==HwParamLen || HwParamLen > MAX_NVM_SIZE) { + TRACE_ALWAYS("Error: Param length is invalid! (%d)\n", HwParamLen); + return B_ERROR; + } else + TRACE("Debug: Found valid param length. (%d)\n", HwParamLen); + + puBuffer = (unsigned char*)malloc(HwParamLen); + // Allocate memory to calculate checksum on + + if (!puBuffer) { + TRACE_ALWAYS("Error: HW_PARAM buffer is too small!\n"); + free(puBuffer); + return B_ERROR; + } + + NVMRead(dwReadValue, HwParamLen, (unsigned int*)puBuffer); + // Populate allocated memory with string for checksum + + usChksmCalc = CalculateHWChecksum(puBuffer, HwParamLen); + // Perform checksum on values + + NVMRead(dwReadValue + HwParamLen, 2, (unsigned int*)&usChksmOrg); + // Read what the device thinks the checksum should be + + usChksmOrg = ntohs(usChksmOrg); + // Compare the checksum calculated with the checksum in nvm + + if (usChksmCalc ^ usChksmOrg) { + TRACE_ALWAYS("Error: Param checksum mismatch!\n"); + TRACE_ALWAYS(" HW Param Length = %d\n", HwParamLen); + TRACE_ALWAYS(" Calculated checksum = %x\n", usChksmCalc); + TRACE_ALWAYS(" Stored checksum = %x\n", usChksmOrg); + free(puBuffer); + return B_ERROR; + } else { + TRACE_ALWAYS("Info: Hardware param checksum valid." + " Calculated: 0x%x, Stored: 0x%x\n", + usChksmCalc, usChksmOrg); + } + + free(puBuffer); + + return B_OK; +} + diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemNVM.h b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemNVM.h new file mode 100644 index 0000000000..1f14d5e539 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/BeceemNVM.h @@ -0,0 +1,119 @@ +/* + * Beceem WiMax USB Driver. + * Copyright (c) 2010 Alexander von Gluck + * Distributed under the terms of the MIT license. + * + * Based on GPL code developed by: Beceem Communications Pvt. Ltd + */ + +#ifndef _USB_BECEEM_NVM_H_ +#define _USB_BECEEM_NVM_H_ + +#include +#include + +#include "util.h" +#include "DeviceStruct.h" + + +#define BECM ntohl(0x4245434d) + +#define MAC_ADDR_OFFSET 0x200 + +#define SPI_FLUSH_REG 0x0F00304C + +// Our Flash addresses +#define FLASH_PART_SIZE (16 * 1024 * 1024) +#define FLASH_CONFIG_REG 0xAF003050 +#define FLASH_GPIO_CONFIG_REG 0xAF000030 +#define FLASH_CS_INFO_START_ADDR 0xFF0000 // Location for Flash calibration info +#define FLASH_AUTO_INIT_BASE_ADDR 0xF00000 +#define FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT 0x1F000000 // Flash base before DDR Init +#define FLASH_CONTIGIOUS_START_ADDR_AFTER_INIT 0x1C000000 // Flash base after DDR Init +#define FLASH_SPI_CMDQ_REG 0xAF003040 +#define FLASH_SPI_WRITEQ_REG 0xAF003044 +#define FLASH_SPI_READQ_REG 0xAF003048 +#define FLASH_SIZE_ADDR 0xFFFFEC // Location of Flash memory size +#define FLASH_CMD_STATUS_REG_WRITE 0x01 +#define FLASH_CMD_STATUS_REG_READ 0x05 +#define FLASH_CMD_WRITE_ENABLE 0x06 +#define FLASH_CMD_READ_ID 0x9F // Command to read the flash chip ID +#define FLASH_CS_SIGNATURE 0xBECEF1A5 // Beceem FLAS(H) (get it?) + +// Our EEPROM addresses +#define EEPROM_SPI_Q_STATUS_REG 0x0F003008 +#define EEPROM_CMDQ_SPI_REG 0x0F003018 +#define EEPROM_READ_DATAQ_REG 0x0F003020 + +#define RESET_CHIP_SELECT -1 +#define MAX_RW_SIZE 0x10 // bytes +#define MAX_NVM_SIZE (8*1024) + +// Different models have different storage devices (sigh) +#define NVM_UNKNOWN 0 +#define NVM_EEPROM 1 +#define NVM_FLASH 2 + +#define NVM_VERSION_OFFSET 0x020E +#define NVM_SECTOR_SIZE 0x10000 + +#define NVM_READ_DATA_AVAIL 0x00000020 // was EEPROM_READ_DATA_AVAIL +#define NVM_SPI_Q_STATUS1_REG 0x0F003004 // was EEPROM_SPI_Q_STATUS1_REG +#define NVM_ALL_QUEUE_FLUSH 0x0000000f // was EEPROM_ALL_QUEUE_FLUSH + +#define SCSI_FIRMWARE_MINOR_VERSION 0x5 + +#ifndef MIN +#define MIN(_a, _b) ((_a) < (_b)? (_a): (_b)) +#endif + +#define MAJOR_VERSION(x) (x & 0xFFFF) +#define MINOR_VERSION(x) ((x >>16) & 0xFFFF) + +class BeceemNVM +{ + int bSelectedChip; // selected chip + +public: + BeceemNVM(); + status_t NVMInit(WIMAX_DEVICE* swmxdevice); + status_t ReadMACFromNVM(ether_address *address); + status_t ValidateDSD(unsigned long hwParam); + + + int NVMRead(unsigned int offset, unsigned int size, unsigned int* buffer); + int NVMWrite(unsigned int offset, unsigned int size, unsigned int* buffer); + + // yuck. These are in a child class class + virtual status_t ReadRegister(unsigned int reg, size_t size, uint32_t* buffer){ return NULL; }; + virtual status_t WriteRegister(unsigned int reg, size_t size, uint32_t* buffer){ return NULL; }; + virtual status_t BizarroReadRegister(unsigned int reg, size_t size, uint32_t* buffer){ return NULL; }; + virtual status_t BizarroWriteRegister(unsigned int reg, size_t size, uint32_t* buffer){ return NULL; }; + +private: + WIMAX_DEVICE* pwmxdevice; + + status_t NVMDetect(); + status_t NVMFlush(); + status_t NVMChipSelect(unsigned int offset); + status_t RestoreBlockProtect(unsigned long writestatus); + unsigned long DisableBlockProtect(unsigned int offset, size_t size); + + int FlashGetBaseAddr(); + unsigned long FlashReadID(); + status_t FlashReadCS(); + status_t FlashSectorErase(unsigned int addr, unsigned int numOfSectors); + status_t FlashBulkRead(unsigned int offset, unsigned int size, unsigned int* buffer); + status_t FlashBulkWrite(unsigned int offset, unsigned int size, unsigned int* buffer); + status_t FlashCSFlip(PFLASH_CS_INFO FlashCSInfo); + status_t FlashCSDump(PFLASH_CS_INFO FlashCSInfo); + + unsigned int EEPROMGetSize(); + unsigned int FlashGetSize(); + + status_t EEPROMRead(unsigned int offset, unsigned int *pdwData); + status_t EEPROMBulkRead( unsigned int offset, size_t numBytes, unsigned int* buffer); +}; + +#endif // _USB_BECEEM_NVM_H + diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/DeviceStruct.h b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/DeviceStruct.h new file mode 100644 index 0000000000..e698ec86df --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/DeviceStruct.h @@ -0,0 +1,517 @@ +/* + * Beceem WiMax USB Driver. + * Copyright (c) 2010 Alexander von Gluck + * Distributed under the terms of the MIT license. + * + * Based on GPL code developed by: Beceem Communications Pvt. Ltd + */ + +#ifndef _USB_BECEEM_DEVICE_STRUCT_ +#define _USB_BECEEM_DEVICE_STRUCT_ + +#include "Driver.h" + +typedef struct FirmwareInfo +{ + void* pvMappedFirmwareAddress; + unsigned long u32FirmwareLength; + unsigned long u32StartingAddress; +}__attribute__((packed)) FIRMWARE_INFO, *PFIRMWARE_INFO; + +/* WARNING: DO NOT edit this struct + * This struct is size / location dependant to vendor conf + */ +typedef struct _VENDORCFG +{ + /* + Vendor Configuration Versions -- Beceem Internal + Clear drivers use version 26 + # Version 1 - Creation + # Version 2 - Major revision - Created the current structure + # Version 3 - Renaming to HARQ structure to 'General'. HARQ will be + # reintroduced later. + # Version 4 - Added enabling of Tx Power Report from config file + # Version 5 - Added enabling of Random FA selection + # Version 7 - Added the firmware config option + # Version 8 - Added the config option for 8.75 or 10 MHz bandwidth + # Version 9 - Added the config option for ShutDown Timer + # - Removed changes in Version 8 + # Version 10 - Merged versions 8 and 9 + # Version 11 - EncrSupport & NumOfSAId added + # Version 12 - Radio and PHY Parameters added + # Version 13 - options for testing cqich, rang etc + # Version 14 - NA + # Version 15 - Added Max MAC Data per Frame to be sent in REG-REQ + # Version 16 - Added flags to enable Corrigendum 2 + # Version 17 - IDLE Reserved1 field is changed to idle mode option. + # 0 means normal, 1 for CPE special Idle mode + # Version 18 - Changes to Radio Parameter, high band support added + # Version 19 - Changed Idlemode Enable to powersaving modes enable for Sleep + # - Changed Idlemode options to powersaving mode enable for Sleep + # Version 20 - Changed Rtps Enable to Minimum Grant size, nRtps Enable to + # Maximum Grant size, PC reserved 4 to MimoEnabled + # Version 21 - Changed eRtps Enable to PHS Enabled + # Version 22 - Removed PC related cfg options (made them unused). + # - Added a test option for connect-disconnect testing + # Version 23 - Removed the unused parameter from the config file + # version 24 - change config file as the latest config file not consistent + # version 25 - Added Segmented PUSC config option + # version 26 - Updated customize field for Wibro Nw + # version 27 - Added Shutdown Related Params + # version 28 - Added Band AMC Related Params + # version 29 - Updated HostDrvrConfig6 for DDR Memory Clock Frequency + # selection & Power Save Mode Selection. + # version 30 - Changed the "MAX MAC Data per frame" from 15:4 to 75:0 + # (to reflect T3 capability - for T2 its still 15:4 this is + # handled in MS firmware) + # Version 31 - Added CFG option for HARQ channel mapping + # Version 32 - Added CFG options for ERTPS + # - Removed CFG option for HARQ channel mapping + # Version 33 - Sync 4.x and 5.x CFG file + # Version 34 - Updated the comments for HostDrvrConfig6. + # - Added Cfg options for Enabled Action Trigger and TTWF + # values for Sleepmode + # Version 35 - Added support for IP retention (bit 1 of customize field) + # Version 36 - Renamed the PHS Enable field to CS options. This has now been + # made a bit field + # Version 37 - Updated HostDrvrConfig4(31:30) and HostDrvrConfig5(31:0) for + # WiMAX trigger type and threshold + # Version 39 - Using the handoff enable flags to enable/disable HO on signal + # fade (Active State Retention feature). + # Version 40 - Clean up and add support for MIMO B enable/disable, and + # Encryption enable/disable + # Version 41 - Added bitwise support for Eth CS + # Version 42 - Added support for CFG based purge timer setting for real time + # HARQ connections + # Version 43 - Added config for out of HARQ order delivery feature + # Version 44 - Added config for enabling RPD 124 changes related to Tx power + # report + # Version 45 - Added flag in Wimax options to enable/disable GPIO 2 + # signaling of Out of Wimax Coverage. + # Version 46 - Added flag to enable inclusion of Idlemode MAC Hash Skip + # Threshold TLV + # Version 47 - Added DP options + # Version 48 - Added flag in Wimax options to enable/disable GPIO 14 based + # low power mode (LPM) entry + # Version 49 - Added flag under ARQ ENable for disabling ARQ Cut Thru for + # Ack generation + # Version 50 - Added flag for handling partial nacking of PDUs, and retxing + # only nacked blocks */ + unsigned int m_u32CfgVersion; + + /* + Scanning Parameters + Make center frequency as 0 to enable scanning + Or use: 2336, 2345, 2354, 2367.5, 2385.5 + Choosing the center frequency non-zero will + disable scanning! */ + unsigned int m_u32CenterFrequency; + unsigned int m_u32BandAScan; + unsigned int m_u32BandBScan; + unsigned int m_u32BandCScan; + + // QoS Params + unsigned int m_u32minGrantsize; // size of minimum grant is 0 or 6 + unsigned int m_u32PHSEnable; + + // HO Params + unsigned int m_u32HoEnable; + unsigned int m_u32HoReserved1; + unsigned int m_u32HoReserved2; + + /* + MIMO Enable ==> 0xddccbbaa + aa = 0x01 Enables DL MIMO, + bb = 0x01 Enabled UL CSM ; + cc = 0x01 to disable MIMO B support + 0xdd Reserved + 0x0101 => Enables DL MIMO and UL CSM + 0x010101 =? Enable DL MIMO, UL CSM, and disable MIMO B in DL */ + unsigned int m_u32MimoEnable; + + /* + Security Parameters + bit 0 = Enable PKMV2 support (Auth support) + bit 1 = Enable index based SFID mapping for MS init SFs + bit 2 = Enable domain restriction for security + bit 3 = Disable encryption support + bit[31:4] = Unused. */ + unsigned int m_u32SecurityEnable; + + /* + PowerSaving enable + bit 1 = 1 Idlemode enable + bit 2 = 1 Sleepmode Enable */ + unsigned int m_u32PowerSavingModesEnable; + + /* + PowerSaving Mode Options + bit 0 = 1: CPE mode - to keep pcmcia if alive; + bit 1 = 1: CINR reporing in Idlemode Msg + bit 2 = 1: Default PSC Enable in sleepmode */ + unsigned int m_u32PowerSavingModeOptions; + + /* + ARQ Enable ==> 0xddccbbaa + aa => 0x01 Enables ARQ + bb => 0x01 Disables the ARQ feature where MS combines ARQ FB and tranport + CID Bw Requests: + cc => 0x01 Enable ARQ FB BW req enh + dd => 0th bit Disable ARQ Cut thru for Ack Generation + dd => 1st bit enables handling of partial nacking of PDUs, and retxing */ + unsigned int m_u32ArqEnable; + + /* + HARQ Enable ==> 0xddccbbaa + aa => 0x01 Enables HARQ on Transport; + bb => 0 bit Enables HARQ on Management + bb => 1 bit Enables Out of order delivery on non-ARQ Rx ERTPS HARQ connections + bb => 2 bit Enables Out of order delivery on all non-ARQ RX HARQ connections + dd => If set, used as the PDU purge timer on the non-ARQ Rx HARQ RT connections + ERTPS, RTPS, UGS + HARQ on Management only is NOT Permitted. + Eg. 0x0101 => Enables HARQ on Management and HARQ on Transport Connections + Eg. 0x0301 => Enables HARQ on Management and HARQ on Transport Connections + Enables out of deliver on the non-ARQ rx ERTPS HARQ connections + Eg. 0x0501 => Enables HARQ on Management and HARQ on Transport Connections + Enables out of deliver on the non-ARQ RX HARQ connections */ + unsigned int m_u32HarqEnable; + + // EEPROM Param Location + unsigned int m_u32EEPROMFlag; + + /* + Customize + Normal Mode should be set to (0x00000100) + Set bit 0 for using D5 CQICH IE (WiBro NW) + Bit 26 should be set to disable the BEU */ + unsigned int m_u32Customize; + + /* + Config Bandwidth + Should be in Hz i.e. 8750000, 10000000 */ + unsigned int m_u32ConfigBW; + + /* + Shutdown Timer + number of frames (5 ms) + ShutDown Timer Value = 0x7fffffff */ + unsigned int m_u32ShutDownTimer; + + /* + Radio Parameter + e.g. 0x000dccba + d = [19:16] Second/High Band Select + { 2->2.3 to 2.4G; 3->2.5 to 2.7G; 4->3.4 to 3.6G, + F-> Select from EEPROM if info available } + Do not fill for single band unit + cc = [15:8] Board Type, set to 0 + b = [7:4] Primary/Low Band Select + { 2->2.3 to 2.4G; 3->2.5 to 2.7G; 4->3.4 to 3.6G, + F-> Select from EEPROM if info available } + a = [3:0] Set to 2 + + Examples: + # 2.3GHz MS120 single band unit needs 0x22 + # 2.5GHz MS120 single band unit needs 0x32 + # 3.5GHz MS120 single band unit needs 0x42 + # 2.3G and/or 3.5G BCS200 unit needs 0x40022 + # 2.5G and/or 3.5G BCS200 unit needs 0x40032 */ + unsigned int m_u32RadioParameter; + + /* + PhyParameter1 e.g. 0xccccbbaa + cccc = [31:16] 80 * Value of TTG in us + bb = [15:8] Number of DL symbols + aa = [7:0] Number of UL symbols + Special value of 0xFFFFFFFF indicates use of embedded logic + PhyParameter1 = 0xFFFFFFFF */ + unsigned int m_u32PhyParameter1; + + /* + PhyParameter2 + [16] Set to 1 for accurate CINR measurement on noise limited scenarios + If set to 1, note the BTS Link Adaptation tables may need change + [15:8] Backoff in 0.25dBm steps in Transmit power to be + applied for an uncalibrated unit */ + unsigned int m_u32PhyParameter2; + + /* + PhyParameter3 = 0x0 */ + unsigned int m_u32PhyParameter3; + + /* + TestOptions + in eval mode only; + -lower 16bits = basic cid for testing; + -then bit 16 is test cqich, + -bit 17 test init rang; + -bit 18 test periodic rang + -bit 19 is test harq ack/nack + + in normal mode; + -#define ENABLE_RNG_REQ_RPD_R4 0x1 + -#define ENABLE_RNG_REQ_RPD_R3 0x2 + -#define TEST_HOCODE_IN_IM_REENTRY_RPD 0x4 + -#define ENABLE_PHY_PARAMETERS_RPD 0x8 + -#define ENABLE_INDEP_CONTROL_DATA_POW_SCALLING 0x10 + -#define ENABLE_PTXIRMAX_FOR_ALL_CDMA_CODES 0x20 + -#define ENABLE_EXT_BS_INITIATED_IDLE_MODE 0x40 + -#define DISABLE_RNG_REQ_ANOMALY 0x100 + -#define ENABLE_HARQ_TLVS_IN_DSA_RSP_IOPR 0x200 + -#define ENABLE_TX_PWR_RPT_RPD_124 0x400 + -#define INCLUDE_IM_MAC_HASH_SKIP_THRESH_TLV 0x800 + -#define ENABLE_POLL_ME_BIT_USING_UGS 0x8000 + -#define NW_ENTRY_DREG 0x100000 + -#define TEST_DISABLE_DSX_FLOW_CONTROL_TLV 0x200000 + -#define TEST_SBC_OPTIMIZATION 0x400000 + -#define TEST_DISABLE_EARLY_TX_POWER_GEN 0x1000000 + -#define LA_DISABLE_ECINR_SUPPORT 0x2000000 + -#define ENABLE_NSP_SBC_DISCOVERY_METHOD 0x8000000 + -#define ENABLE__BF_WA 0x20000000 + -#define ENABLE_BR_PWR_INCR_AND_IGNORE_PC_IE_OUT_DYNAMIC_RNG 0x40000000 + -#define ENABLE_BR_CODE_TIMEOUT_PWR_ADJ_PDUS 0x80000000*/ + unsigned int m_u32TestOptions; + + /* + Max MAC Data per Frame to be sent in REG-REQ */ + unsigned int m_u32MaxMACDataperDLFrame; + unsigned int m_u32MaxMACDataperULFrame; + + unsigned int m_u32Corr2MacFlags; + + /* + HostDrvrConfig1/HostDrvrConfig2/HostDrvrConfig3 + 12 Bytes are required for setting the LED Configurations. + LED Type (This can be either RED/YELLOW/GREEN/FLUORESCENT) + ON State (This makes sure that the LED is ON till a state is achieved) + Blink State (This makes sure that the LED Keeps Blinking till a state is + achieved e.g. firmware download state)*/ + unsigned int HostDrvrConfig1; + unsigned int HostDrvrConfig2; + unsigned int HostDrvrConfig3; + + /* + HostDrvrConfig4/HostDrvrConfig5 + Used for "WiMAX Trigger" for out of WiMAX Coverage. + HostDrvrConfig4 [31:30] + To set WiMAX Trigger Type: + 00 -"Not Defined", 01 -"RSSI", 10 -"CINR", 11 -"Reserved" + HostDrvrConfig5 [31:0] + To set WiMAX Trigger Threshold for the type + selected in HostDrvrConfig4 */ + unsigned int HostDrvrConfig4; + unsigned int HostDrvrConfig5; + + /* + HostDrvrConfig6: + Important device configuration data + Bit[3..0] Control Flags + Bit 0: Automatic Firmware Download 1: Enable, 0: Disable + Bit 1: Auto Linkup 1: Enable, 0: Disable + Bit 2: Reserved. + Bit 3: Reserved. + Bit[7..4] RESERVED + Bit[11..8] DDR Memory Clock Configuration + MEM_080_MHZ = 0x0 + MEM_133_MHZ = 0x3 + MEM_160_MHZ = 0x5 + Bit[14..12] PowerSaveMethod + DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING = 0x0 + DEVICE_POWERSAVE_MODE_AS_PMU_CLOCK_GATING = 0x1 + DEVICE_POWERSAVE_MODE_AS_PMU_SHUTDOWN = 0x2 + Bit[15] Idlemode Auto correct mode. + 0-Enable, 1- Disable. */ + unsigned int HostDrvrConfig6; + + /* + Segmented PSUC + Option to enable support of Segmented PUSC. + If set to 0, only full reuse profiles are supported */ + unsigned int m_u32SegmentedPUSCenable; + + /* + BAMC Related Parameters + 4.x does not support this feature + This is added just to sync 4.x and 5.x CFGs + Bit[0..15] Band AMC signaling configuration: + Bit 0 = 1 Enable Band AMC signaling. + Bit[16..31] Band AMC Data configuration: + Bit 16 = 1 Band AMC 2x3 support. + Bit 0 is effective only if bit 16 is set. */ + unsigned int m_u32BandAMCEnable; + +} VENDORCFG, *PSVENDORCFG; + +/*Structure which stores the information of different LED types + * and corresponding LED state information of driver states*/ +typedef struct _GPIO_LED_STATE +{ + uint8_t LED_Type; + // specify GPIO number - use 0xFF if not used + uint8_t LED_On_State; + // Bits set or reset for different states + uint8_t LED_Blink_State; + // Bits set or reset for blinking LEDs for different states + uint8_t GPIO_Num; + // GPIO number (this is the bit offset and is 1< + * Distributed under the terms of the MIT license. + * + * Heavily based on code of : + * Driver for USB Ethernet Control Model devices + * Copyright (C) 2008 Michael Lotz + * Distributed under the terms of the MIT license. + * + * The Beceem chipset can be used via multiple interfaces + * such as PCMCIA, MII, PCI, SDIO, and Serial. However I have + * only found it implemented commercially for PC use as USB. + * + */ + +#include +#include +#include + +#ifdef HAIKU_TARGET_PLATFORM_HAIKU +#include // for mutex +#else +#include "BeOSCompatibility.h" // for pseudo mutex +#endif + +#include "BeceemDevice.h" +#include "Driver.h" +#include "Settings.h" + +int32 api_version = B_CUR_DRIVER_API_VERSION; +static const char *sDeviceBaseName = "net/usb_beceemwmx/"; +BeceemDevice *gBeceemDevices[MAX_DEVICES]; +char *gDeviceNames[MAX_DEVICES + 1]; +usb_module_info *gUSBModule = NULL; + +usb_support_descriptor gSupportedDevices[] = { + { 0, 0, 0, 0x0489, 0xe016}, + // "Ubee WiMAX Mobile USB - PXU1900 (Clear)" + { 0, 0, 0, 0x0489, 0xe017}, + // "Ubee WiMAX Mobile USB - PXU1901 (Sprint)" + { 0, 0, 0, 0x198f, 0x0210}, + // "Motorola USBw 100 WiMAX CPE" + { 0, 0, 0, 0x198f, 0x0220}, + // "Huawei Mobile USB, Sierra 250U Dual 3G/WiMAX, Sprint U301 WiMAX" + { 0, 0, 0, 0x19d2, 0x0007} + // "ZTE TU25 WiMAX Adapter [Beceem BCS200]" +}; + +mutex gDriverLock; + +// auto-release helper class +class DriverSmartLock { +public: + DriverSmartLock() { mutex_lock(&gDriverLock); } + ~DriverSmartLock() { mutex_unlock(&gDriverLock); } +}; + +BeceemDevice * +create_beceem_device(usb_device device) +{ + const usb_device_descriptor *deviceDescriptor + = gUSBModule->get_device_descriptor(device); + + if (deviceDescriptor == NULL) { + TRACE_ALWAYS("Error: Problem getting USB device descriptor.\n"); + return NULL; + } + +#define IDS(__vendor, __product) (((__vendor) << 16) | (__product)) + + switch(IDS(deviceDescriptor->vendor_id, deviceDescriptor->product_id)) { + case IDS(0x0489, 0xe016): + return new BeceemDevice(device, "Ubee WiMAX Mobile USB - PXU1900 (Clear)"); + case IDS(0x0489, 0xe017): + return new BeceemDevice(device, "Ubee WiMAX Mobile USB - PXU1901 (Sprint)"); + case IDS(0x198f, 0x0210): + return new BeceemDevice(device, "Motorola USBw 100 WiMAX CPE"); + case IDS(0x198f, 0x0220): + return new BeceemDevice(device, "Beceem Mobile USB WiMAX CPE"); + case IDS(0x19d2, 0x0007): + return new BeceemDevice(device, "ZTE TU25 WiMAX Adapter [Beceem BCS200]"); + } + return NULL; +} + + +status_t +usb_beceem_device_added(usb_device device, void **cookie) +{ + *cookie = NULL; + + DriverSmartLock driverLock; // released on exit + + // check if this is a replug of an existing device first + for (int32 i = 0; i < MAX_DEVICES; i++) { + if (gBeceemDevices[i] == NULL) + continue; + + if (gBeceemDevices[i]->CompareAndReattach(device) != B_OK) + continue; + + TRACE("Debug: The device is plugged back. Use entry at %ld.\n", i); + *cookie = gBeceemDevices[i]; + return B_OK; + } + + // no such device yet, create a new one + BeceemDevice *beceemDevice = create_beceem_device(device); + if (beceemDevice == 0) { + return ENODEV; + } + + status_t status = beceemDevice->InitCheck(); + if (status < B_OK) { + delete beceemDevice; + return status; + } + + status = beceemDevice->SetupDevice(false); + if (status < B_OK) { + delete beceemDevice; + return status; + } + + for (int32 i = 0; i < MAX_DEVICES; i++) { + if (gBeceemDevices[i] != NULL) + continue; + + gBeceemDevices[i] = beceemDevice; + *cookie = beceemDevice; + + TRACE("Debug: New device is added at %ld.\n", i); + return B_OK; + } + + // no space for the device + TRACE_ALWAYS("Error: no more device entries availble.\n"); + + delete beceemDevice; + return B_ERROR; +} + + +status_t +usb_beceem_device_removed(void *cookie) +{ + + TRACE("Debug: device was removed.\n"); + DriverSmartLock driverLock; // released on exit + + BeceemDevice *device = (BeceemDevice *)cookie; + for (int32 i = 0; i < MAX_DEVICES; i++) { + if (gBeceemDevices[i] == device) { + if (device->IsOpen()) { + // the device will be deleted upon being freed + TRACE("Debug: Device %ld will be deleted upon being freed.\n", i); + device->Removed(); + } else { + TRACE("Debug: Device at %ld will be deleted.\n", i); + gBeceemDevices[i] = NULL; + delete device; + TRACE("Debug: Device at %ld deleted.\n", i); + } + break; + } + } + + return B_OK; +} + + +//#pragma mark - + + +status_t +init_hardware() +{ + return B_OK; +} + + +status_t +init_driver() +{ + status_t status = get_module(B_USB_MODULE_NAME, + (module_info **)&gUSBModule); + if (status < B_OK) + return status; + + load_settings(); + + TRACE_ALWAYS("%s\n", kVersion); + + for (int32 i = 0; i < MAX_DEVICES; i++) + gBeceemDevices[i] = NULL; + + gDeviceNames[0] = NULL; + mutex_init(&gDriverLock, DRIVER_NAME"_devices"); + + static usb_notify_hooks notifyHooks = { + &usb_beceem_device_added, + &usb_beceem_device_removed + }; + + gUSBModule->register_driver(DRIVER_NAME, gSupportedDevices, + sizeof(gSupportedDevices) / sizeof(usb_support_descriptor), NULL); + gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); + return B_OK; +} + + +void +uninit_driver() +{ + gUSBModule->uninstall_notify(DRIVER_NAME); + mutex_lock(&gDriverLock); + + for (int32 i = 0; i < MAX_DEVICES; i++) { + if (gBeceemDevices[i]) { + delete gBeceemDevices[i]; + gBeceemDevices[i] = NULL; + } + } + + for (int32 i = 0; gDeviceNames[i]; i++) { + free(gDeviceNames[i]); + gDeviceNames[i] = NULL; + } + + mutex_destroy(&gDriverLock); + put_module(B_USB_MODULE_NAME); + + release_settings(); +} + + +static status_t +usb_beceem_open(const char *name, uint32 flags, void **cookie) +{ + DriverSmartLock driverLock; // released on exit + + *cookie = NULL; + status_t status = ENODEV; + int32 index = strtol(name + strlen(sDeviceBaseName), NULL, 10); + if (index >= 0 && index < MAX_DEVICES && gBeceemDevices[index]) { + status = gBeceemDevices[index]->Open(flags); + *cookie = gBeceemDevices[index]; + } + + return status; +} + + +static status_t +usb_beceem_read(void *cookie, off_t position, void *buffer, size_t *numBytes) +{ + BeceemDevice *device = (BeceemDevice *)cookie; + return device->Read((uint8 *)buffer, numBytes); +} + + +static status_t +usb_beceem_write(void *cookie, off_t position, const void *buffer, + size_t *numBytes) +{ + BeceemDevice *device = (BeceemDevice *)cookie; + return device->Write((const uint8 *)buffer, numBytes); +} + + +static status_t +usb_beceem_control(void *cookie, uint32 op, void *buffer, size_t length) +{ + BeceemDevice *device = (BeceemDevice *)cookie; + return device->Control(op, buffer, length); +} + + +static status_t +usb_beceem_close(void *cookie) +{ + BeceemDevice *device = (BeceemDevice *)cookie; + return device->Close(); +} + + +static status_t +usb_beceem_free(void *cookie) +{ + TRACE("Debug: Device to be freed\n"); + BeceemDevice *device = (BeceemDevice *)cookie; + + DriverSmartLock driverLock; // released on exit + + status_t status = device->Free(); + for (int32 i = 0; i < MAX_DEVICES; i++) { + if (gBeceemDevices[i] == device) { + // the device is removed already but as it was open the + // removed hook has not deleted the object + TRACE("Debug: Device was removed, but it was open.\n"); + gBeceemDevices[i] = NULL; + delete device; + TRACE("Debug: Device at %ld deleted.\n", i); + break; + } + } + + return status; +} + + +const char ** +publish_devices() +{ + for (int32 i = 0; gDeviceNames[i]; i++) { + free(gDeviceNames[i]); + gDeviceNames[i] = NULL; + } + + DriverSmartLock driverLock; // released on exit + + int32 deviceCount = 0; + for (int32 i = 0; i < MAX_DEVICES; i++) { + if (gBeceemDevices[i] == NULL) + continue; + + gDeviceNames[deviceCount] = (char *)malloc(strlen(sDeviceBaseName) + 4); + if (gDeviceNames[deviceCount]) { + sprintf(gDeviceNames[deviceCount], "%s%ld", sDeviceBaseName, i); + TRACE("Debug: publishing %s\n", gDeviceNames[deviceCount]); + deviceCount++; + } else + TRACE_ALWAYS("Error: out of memory during allocating device name.\n"); + } + + gDeviceNames[deviceCount] = NULL; + return (const char **)&gDeviceNames[0]; +} + + +device_hooks * +find_device(const char *name) +{ + static device_hooks deviceHooks = { + usb_beceem_open, + usb_beceem_close, + usb_beceem_free, + usb_beceem_control, + usb_beceem_read, + usb_beceem_write, + NULL, /* select */ + NULL /* deselect */ + }; + + return &deviceHooks; +} + diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Driver.h b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Driver.h new file mode 100644 index 0000000000..adcd2ef85b --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Driver.h @@ -0,0 +1,116 @@ +/* + * Beceem WiMax USB Driver. + * Copyright (c) 2010 Alexander von Gluck + * Distributed under the terms of the MIT license. + * + * Heavily based on code of : + * Driver for USB Ethernet Control Model devices + * Copyright (C) 2008 Michael Lotz + * Distributed under the terms of the MIT license. + * + */ + +#ifndef _USB_BECEEM_DRIVER_H_ +#define _USB_BECEEM_DRIVER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRIVER_NAME "usb_beceemwmx" +#define MAX_DEVICES 8 + +#define FIRM_BIN "/boot/system/data/firmware/macxvi200/macxvi200.bin" + // location on file system of device firmware +#define FIRM_CFG "/boot/system/data/firmware/macxvi200/macxvi.cfg" + // location on file system of vendor configuration + +#define SYS_CFG 0x0F000C00 + +#define FIRM_BEGIN_ADDR 0xBFC00000 + // register we push firmware to +#define CONF_BEGIN_ADDR 0xBF60B004 + // register we push vendor configuration to + +#define EEPROM_COMMAND_Q_REG 0x0F003018 +#define EEPROM_READ_DATA_Q_REG 0x0F003020 +#define EEPROM_CAL_DATA_INTERNAL_LOC 0x1FB00008 + +#define DSD_START_OFFSET 0x200 + // DSD start offset +#define GPIO_START_OFFSET 0x3 + // offset of GPIO start +#define GPIO_PARAM_POINTER 0x0218 + // offset on DSD containing GPIO paramaters (flash map <5) +#define GPIO_PARAM_POINTER_MAP5 0x0220 + // offset on DSD containing GPIO paramaters (flash map 5>) +#define GPIO_MODE_REGISTER 0x0F000034 + // register to set GPIO mode (input or output) +#define GPIO_OUTPUT_SET_REG 0x0F000040 + // register to set active GPIO pin, 1 enables, 0 does nothing +#define GPIO_OUTPUT_CLR_REG 0x0F000044 + // register to clear active GPIO pin, 1 enables, 0 does nothing +#define GPIO_DISABLE_VAL 0xFF + // value of a disabled GPIO pin +#define NUM_OF_LEDS 4 + // number of possible GPIO leds + +#define CLOCK_RESET_CNTRL_REG_1 0x0F00000C +#define HPM_CONFIG_LDO145 0x0F000D54 + +#define CHIP_ID_REG 0x0F000000 + // register containing chipset ID + +//Beceem chip models |Chip_ID |NVM type +//UNKNOWN 0xbece0110 +//UNKNOWN 0xbece0120 +//UNKNOWN 0xbece0121 +//UNKNOWN 0xbece0130 +#define T3 0xbece0300 // EEPROM +#define T3B 0xbece0310 +//UNKNOWN 0xbece3200 +#define T3LPB 0xbece3300 +#define BCS250_BC 0xbece3301 // FLASH +#define BCS220_2 0xbece3311 +#define BCS220_2BC 0xbece3310 +#define BCS220_3 0xbece3321 + +// Driver states for pwmxdevice->driverState +#define STATE_INIT 0x1 // DRIVER_INIT +#define STATE_FWPUSH 0x2 // FW_DOWNLOAD +#define STATE_FWPUSH_OK 0x4 // FW_DOWNLOAD_DONE +#define STATE_NONET 0x8 // NO_NETWORK_ENTRY +#define STATE_NORMAL 0x10 // NORMAL_OPERATION +#define STATE_IDLEENTER 0x20 // IDLEMODE_ENTER +#define STATE_IDLECONT 0x40 // IDLEMODE_CONTINUE +#define STATE_IDLEEXIT 0x80 // IDLEMODE_EXIT +#define STATE_HALT 0x00 // SHUTDOWN_EXIT + +const uint8 kInvalidRequest = 0xff; + +// version of bcm driver this was based upon + end .1 +const char* const kVersion = "ver.5.2.45.1"; + +extern usb_module_info *gUSBModule; + +extern "C" { +status_t usb_beceem_device_added(usb_device device, void **cookie); +status_t usb_beceem_device_removed(void *cookie); + +status_t init_hardware(); +void uninit_driver(); + +const char **publish_devices(); +device_hooks *find_device(const char *name); +} + +#endif //_USB_BECEEM_DRIVER_H_ + diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Jamfile b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Jamfile new file mode 100644 index 0000000000..082adfe93c --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Jamfile @@ -0,0 +1,16 @@ +SubDir HAIKU_TOP src add-ons kernel drivers network wimax usb_beceemwmx ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders kernel net ; + +KernelAddon usb_beceemwmx : + Driver.cpp + BeceemDevice.cpp + Settings.cpp + util.cpp + BeceemNVM.cpp + BeceemDDR.cpp + BeceemLED.cpp + BeceemCPU.cpp + ; diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/README b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/README new file mode 100644 index 0000000000..a8a3be9388 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/README @@ -0,0 +1,29 @@ +USB Driver for Beceem WiMAX devices +==================================================== +Realeased under the MIT license for Haiku +2010 Alexander von Gluck + +This driver requires a Beceem firmware/vendor configuration + +The firmware is binary code pushed to the device and is +a requirement to operate. + +The vendor config is a binary configuration file provided +by the device vendor (Ubee, ZTE, Sierra,etc) to tell the +device about it's internal configuration. + +Obtaining the Firmware / Vendor configuration +========================================================= +The driver will gracefully search the following directory +for it's needed binary files: +/boot/system/data/firmware/macxvi200/ + +macxvi200.bin +macvi.cfg + +These needed files can be obtained by installing the vendor +provided drivers onto a windows system and checking in +system32/drivers + +*Warning* +The license of the binary files is currently unknown. diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Settings.cpp b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Settings.cpp new file mode 100644 index 0000000000..5949c90af4 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Settings.cpp @@ -0,0 +1,111 @@ +/* + * Beceem WiMax USB Driver. + * Copyright (c) 2010 Alexander von Gluck + * Distributed under the terms of the MIT license. + * + * Heavily based on code of : + * Driver for USB Ethernet Control Model devices + * Copyright (C) 2008 Michael Lotz + * Distributed under the terms of the MIT license. + * + */ + +#include // for mutex + +#include "Settings.h" + +bool gTraceOn = false; +bool gTruncateLogFile = false; +bool gAddTimeStamp = true; +bool gTraceFlow = false; +static char *gLogFilePath = NULL; +mutex gLogLock; + +static +void create_log() +{ + if(gLogFilePath == NULL) + return; + + int flags = O_WRONLY | O_CREAT | ((gTruncateLogFile) ? O_TRUNC : 0); + close(open(gLogFilePath, flags, 0666)); + + mutex_init(&gLogLock, DRIVER_NAME"-logging"); +} + +void load_settings() +{ + void *handle = load_driver_settings(DRIVER_NAME); + if(handle == 0) + return; + + gTraceOn = get_driver_boolean_parameter(handle, "trace", gTraceOn, true); + gTraceFlow = get_driver_boolean_parameter(handle, "trace_flow", gTraceFlow, true); + gTruncateLogFile = get_driver_boolean_parameter(handle, "truncate_logfile", + gTruncateLogFile, true); + gAddTimeStamp = get_driver_boolean_parameter(handle, "add_timestamp", + gAddTimeStamp, true); + const char * logFilePath = get_driver_parameter(handle, "logfile", + NULL, "/var/log/"DRIVER_NAME".log"); + if(logFilePath != NULL) { + gLogFilePath = strdup(logFilePath); + } + + unload_driver_settings(handle); + + create_log(); +} + +void release_settings() +{ + if(gLogFilePath != NULL) { + mutex_destroy(&gLogLock); + free(gLogFilePath); + } +} + +void usb_beceem_trace(bool force, const char* func, const char *fmt, ...) +{ + if(!(force || gTraceOn)) { +// return; + } + + va_list arg_list; + static const char *prefix = "\33[33m"DRIVER_NAME":\33[0m"; + static char buffer[1024]; + char *buf_ptr = buffer; + if(gLogFilePath == NULL){ + strcpy(buffer, prefix); + buf_ptr += strlen(prefix); + } + + if(gAddTimeStamp) { + bigtime_t time = system_time(); + uint32 msec = time / 1000; + uint32 sec = msec / 1000; + sprintf(buf_ptr, "%02ld.%02ld.%03ld:", + sec / 60, sec % 60, msec % 1000); + buf_ptr += strlen(buf_ptr); + } + + if(func != NULL) { + sprintf(buf_ptr, "%s::", func); + buf_ptr += strlen(buf_ptr); + } + + va_start(arg_list, fmt); + vsprintf(buf_ptr, fmt, arg_list); + va_end(arg_list); + + if(gLogFilePath == NULL) { + dprintf(buffer); + return; + } + + mutex_lock(&gLogLock); + int fd = open(gLogFilePath, O_WRONLY | O_APPEND); + write(fd, buffer, strlen(buffer)); + close(fd); + mutex_unlock(&gLogLock); +} + diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Settings.h b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Settings.h new file mode 100644 index 0000000000..5b4ff67f2f --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Settings.h @@ -0,0 +1,35 @@ +/* + * Ubee WiMax USB Driver. + * Copyright (c) 2010 Alexander von Gluck + * Distributed under the terms of the MIT license. + * + * Heavily based on code of : + * Driver for USB Ethernet Control Model devices + * Copyright (C) 2008 Michael Lotz + * Distributed under the terms of the MIT license. + * + */ + +#ifndef _USB_BECEEM_SETTINGS_H_ +#define _USB_BECEEM_SETTINGS_H_ + +#include + +#include "Driver.h" + +void load_settings(); +void release_settings(); + +void usb_beceem_trace(bool force, const char *func, const char *fmt, ...); + +#define TRACE(x...) usb_beceem_trace(false, __func__, x) +#define TRACE_ALWAYS(x...) usb_beceem_trace(true, __func__, x) + +extern bool gTraceFlow; +#define TRACE_FLOW(x...) usb_beceem_trace(gTraceFlow, NULL, x) + +#define TRACE_RET(result) usb_beceem_trace(false, __func__, \ + "Returns:%#010x\n", result); + +#endif /*_USB_BECEEM_SETTINGS_H_*/ + diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/usb_beceemwmx.settings b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/usb_beceemwmx.settings new file mode 100644 index 0000000000..b067773b2f --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/usb_beceemwmx.settings @@ -0,0 +1,33 @@ +## +## USB Beceem driver +## Distributed under the terms of the MIT license. +## + +## trace [on|off] - activate additional tracing. +## default value: off + +trace on + +## logfile [full path to private log file] +## default path value: /var/log/usb_beceem.log +## if disabled - all output goes to syslog + +logfile /var/log/usb_beceem.log + +## reset_logfile [on|off] - truncate private log file on driver/system restart +## default value: off +## + +reset_logfile on + +## add_timestamp [on|off] - add time of writing the string in private log file. +## default value: on +## + +# add_timestamp off + +## trace_flow [on|off] - activate data flow tracing. Statistic about of +## transferred data amount and media state. +## default value: off + +# trace_flow on diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/util.cpp b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/util.cpp new file mode 100644 index 0000000000..35a2d7bc55 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/util.cpp @@ -0,0 +1,38 @@ +/* + * Beceem WiMax USB Driver. + * Copyright (c) 2010 Alexander von Gluck + * Distributed under the terms of the MIT license. + * + */ + +#include + +#include "util.h" + +void +convertEndian(bool write, unsigned int uiByteCount, unsigned int* buffer) +{ + unsigned int uiIndex = 0; + + if( write == true ) { + for(uiIndex = 0; uiIndex < (uiByteCount/sizeof(unsigned int)); uiIndex++) { + buffer[uiIndex] = htonl(buffer[uiIndex]); + } + } else { + for(uiIndex = 0; uiIndex < (uiByteCount/sizeof(unsigned int)); uiIndex++) { + buffer[uiIndex] = ntohl(buffer[uiIndex]); + } + } +} + +uint16_t +CalculateHWChecksum(uint8_t* pu8Buffer, uint32_t u32Size) +{ + uint16_t u16CheckSum=0; + while(u32Size--) { + u16CheckSum += (uint8_t)~(*pu8Buffer); + pu8Buffer++; + } + return u16CheckSum; +} + diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/util.h b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/util.h new file mode 100644 index 0000000000..50f90092f5 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/util.h @@ -0,0 +1,12 @@ +/* + * Beceem WiMax USB Driver. + * Copyright (c) 2010 Alexander von Gluck + * Distributed under the terms of the MIT license. + * + */ + +#include "Driver.h" + +void convertEndian(bool write, unsigned int uiByteCount, unsigned int* buffer); +uint16_t CalculateHWChecksum(uint8_t* pu8Buffer, uint32_t u32Size); +