diff -urN linux-2.6.16.18-old/drivers/i2c/chips/Kconfig linux-2.6.16.18/drivers/i2c/chips/Kconfig --- linux-2.6.16.18-old/drivers/i2c/chips/Kconfig 2006-05-22 20:04:35.000000000 +0200 +++ linux-2.6.16.18/drivers/i2c/chips/Kconfig 2006-06-02 23:21:21.000000000 +0200 @@ -74,6 +74,14 @@ This driver can also be built as a module. If so, the module will be called i2c-rtc8564. +config THECUS_RTC + tristate "Thecus GPIO and RTC support" + depends on ARCH_EP80219 && I2C + default m + help + The GPIO support for Thecus N4100 and Ricoh RS372 RTC + driver. + config ISP1301_OMAP tristate "Philips ISP1301 with OMAP OTG" depends on I2C && ARCH_OMAP_OTG diff -urN linux-2.6.16.18-old/drivers/i2c/chips/Makefile linux-2.6.16.18/drivers/i2c/chips/Makefile --- linux-2.6.16.18-old/drivers/i2c/chips/Makefile 2006-05-22 20:04:35.000000000 +0200 +++ linux-2.6.16.18/drivers/i2c/chips/Makefile 2006-06-02 23:21:21.000000000 +0200 @@ -14,6 +14,7 @@ obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o obj-$(CONFIG_TPS65010) += tps65010.o obj-$(CONFIG_RTC_X1205_I2C) += x1205.o +obj-$(CONFIG_THECUS_RTC) += thecus_rtc.o ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG diff -urN linux-2.6.16.18-old/drivers/i2c/chips/thecus_rtc.c linux-2.6.16.18/drivers/i2c/chips/thecus_rtc.c --- linux-2.6.16.18-old/drivers/i2c/chips/thecus_rtc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.18/drivers/i2c/chips/thecus_rtc.c 2006-06-02 23:21:21.000000000 +0200 @@ -0,0 +1,2224 @@ +/* + * Copyright (C) 2004 Thecus Technology Corp. + * + * Written by Y.T. Lee (yt_lee@thecus.com) + * + * based on linux/drivers/i2c/chips/rtc8564.c + * + * Copyright (C) 2002-2004 Stefan Eletzhofer + * + * based on linux/drivers/acron/char/pcf8583.c + * Copyright (C) 2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Driver for Ricoh RTC RS372 chip on Thecus N4100 + */ +#include +#include +#include +#include +#include +#include /* get the user-level API */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include "thecus_rtc.h" +#include + +// #define DEBUG 1 +#define SET_FAN2 1 +#define I2C_RETRY 5 +#define ACCESS_RTC 1 + +#ifdef DEBUG +# define _DBG(x, fmt, args...) do{ if (debug>=x) printk(KERN_DEBUG"%s: " fmt "\n", __FUNCTION__, ##args); } while(0); +#else +# define _DBG(x, fmt, args...) do { } while(0); +#endif + +#define _DBGRTCTM(x, rtctm) if (debug>=x) printk("%s: secs=%d, mins=%d, hours=%d, mday=%d, " \ + "mon=%d, year=%d, wday=%d\n", __FUNCTION__, \ + (rtctm).secs, (rtctm).mins, (rtctm).hours, (rtctm).mday, \ + (rtctm).mon, (rtctm).year, (rtctm).wday); + +MODULE_AUTHOR("Stefan Eletzhofer "); +MODULE_DESCRIPTION("Ricoh(Thecus) RTC RS372 Driver"); +MODULE_LICENSE("GPL"); +static int HPI = 0; +static int debug; +static int TRIM=0x1; +module_param(TRIM, int, S_IRUGO | S_IWUSR); +module_param(debug, int, S_IRUGO | S_IWUSR); +module_param(HPI, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(HPI, "HPI enable"); + +struct rtc_rs372_data { + struct i2c_client client; + u16 ctrl; +}; + +struct pca_9532_data { + struct i2c_client client; + u8 ctrl; +}; + +struct f75373_data { + struct i2c_client client; + u8 ctrl; +}; + +static int XSTP=0; + +static struct i2c_client *rs372; +static struct i2c_client *pca9532; +static struct i2c_client *f75373; + +static char kmsgs[80]; + +static inline u8 _rtc_rs372_ctrl1(struct i2c_client *client) +{ + struct rtc_rs372_data *data = i2c_get_clientdata(client); + return data->ctrl & 0xff; +} +static inline u8 _rtc_rs372_ctrl2(struct i2c_client *client) +{ + struct rtc_rs372_data *data = i2c_get_clientdata(client); + return (data->ctrl & 0xff00) >> 8; +} + +extern spinlock_t rtc_lock; +static int rtc_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); + +static int rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data); + +//static void get_rtc_time(struct rtc_time *rtc_tm); +/* + * Bits in rtc_status. (6 bits of room for future expansion) + */ + +#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ +#define RTC_TIMER_ON 0x02 /* missed irq timer active */ + +#define RS372_I2C_ID 0x32 +#define PCA9532_I2C_ID 0x60 +#define F75373_I2C_ID 0x2e + +u8 f75375_slave_addr=F75373_I2C_ID; + + +static unsigned char rtc_status; /* bitmapped status byte. */ + +/* + * If this driver ever becomes modularised, it will be really nice + * to make the epoch retain its value across module reload... + */ + +static unsigned long epoch = 1970; /* year corresponding to 0x00 */ + +static const unsigned char days_in_mo[] = +{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + + +#define CTRL1(c) _rtc_rs372_ctrl1(c) +#define CTRL2(c) _rtc_rs372_ctrl2(c) + +static struct i2c_driver rtc_rs372_driver; +static struct i2c_driver PCA_9532_driver; +static struct i2c_adapter *pca9532_adaptor; +static struct i2c_driver f75373_driver; +static struct i2c_adapter *f75373_adaptor; + +static unsigned short ignore[] = { I2C_CLIENT_END }; +static unsigned short normal_addr[] = { RS372_I2C_ID, I2C_CLIENT_END }; +static unsigned short pca_9532_addr[] = { PCA9532_I2C_ID, I2C_CLIENT_END }; +static unsigned short f75373_addr[] = { F75373_I2C_ID, I2C_CLIENT_END }; + +static struct i2c_client_address_data addr_data = { + .normal_i2c = normal_addr, + .probe = ignore, + .ignore = ignore, +}; + +static struct i2c_client_address_data pca_9532_addr_data = { + .normal_i2c = pca_9532_addr, + .probe = ignore, + .ignore = ignore, +}; + +static struct i2c_client_address_data f75373_addr_data = { + .normal_i2c = f75373_addr, + .probe = ignore, + .ignore = ignore, +}; + +static int rtc_rs372_read_mem(struct i2c_client *client, struct mem *mem); +static int rtc_rs372_write_mem(struct i2c_client *client, struct mem *mem); +static int pulse=1; + +/* Input: BIT#, action=0/1 */ +static void gpio_write(int gpio_bit,int action) +{ + unsigned char gpio_byte,out_byte; + out_byte = *IOP321_GPID; + gpio_byte = (1 << gpio_bit); + if(action==0){ //input 0: want to turn off + out_byte |= gpio_byte; + } + else{ + gpio_byte ^= 0xFF; + out_byte &= gpio_byte; + } + *IOP321_GPOD = out_byte; + +} +/* return 0 for no error */ +static int pca_9532_rw(struct i2c_adapter *adap, u8 reg_num, u8 *val, int wr) +{ + int ret; + unsigned char ad[1]; + unsigned char data[2]; + struct i2c_msg ctrl_wr[1] = { + {PCA9532_I2C_ID, 0, 2, data} + }; + struct i2c_msg ctrl_rd[2] = { + {PCA9532_I2C_ID, 0, 1, ad}, + {PCA9532_I2C_ID, I2C_M_RD, 1, data} + }; + + if(NULL == adap) { + printk(KERN_INFO "thecus_rtc: i2c_adapter is NULL\n"); + return 1; + } + + if(wr){ //Write + data[0]=reg_num; + data[1]=*val; + + ret = i2c_transfer(adap, ctrl_wr, 1); + if (ret != 1) { + printk(KERN_INFO "thecus_rtc: cant write PCA9532 Reg#%02X\n",reg_num); + return ret; + } + } + else{ //Read + + data[0]=0; + data[1]=0; + ad[0]=reg_num; + ret = i2c_transfer(adap, ctrl_rd, 2); + if (ret != 2) { + printk(KERN_INFO "thecus_rtc: cant read PCA9532 Reg#%02X\n",reg_num); + return ret; + } + *val=data[0]; + } + return 0; +} + +static int pca_9532_attach(struct i2c_adapter *adap, int addr, int kind) +{ + int ret; + struct i2c_client *new_client; + struct pca_9532_data *d; + unsigned char data[16]; + unsigned char ad[1] = { 0x03 }; + struct i2c_msg ctrl_rd[2] = { + {addr, 0, 1, ad}, + {addr, I2C_M_RD, 1, data} + }; + + d = kzalloc(sizeof(struct pca_9532_data), GFP_KERNEL); + if (!d) { + ret = -ENOMEM; + goto done; + } + new_client = &d->client; + + strlcpy(new_client->name, "PCA_9532", I2C_NAME_SIZE); + i2c_set_clientdata(new_client, d); + new_client->addr = addr; + new_client->adapter = adap; + new_client->driver = &PCA_9532_driver; + + _DBG(1, "client=%p", new_client); + + /* read back ctrl1 and ctrl2 */ + gpio_write( GPIO_LED_RESET, 0); + mdelay(50); + gpio_write( GPIO_LED_RESET, 1); + + data[0]=0; + data[1]=0; + ad[0]=0x03; + ret = i2c_transfer(new_client->adapter, ctrl_rd, 2); + + if (ret != 2) { + printk(KERN_INFO "pca_9532_attach: cant read ctrl\n"); + ret = -ENODEV; + goto done; + } + + if(data[0]!=0x80){ //PCA9532 not found + pca9532_adaptor=0; + ret = -ENODEV; + goto done; + } + pca9532_adaptor=adap; + d->ctrl = data[0]; + + _DBG(1, "PCA9532_REG_PWM1=%02x",data[0]); + + /* + data[0]=0x02; + data[1]=128; + + ret = i2c_transfer(new_client->adapter, ctrl_wr, 1); + if (ret != 1) { + printk(KERN_INFO "thecus_rtc: cant write PSC0\n"); + ret = -ENODEV; + goto done; + } + + data[0]=0x03; + data[1]=30; + + ret = i2c_transfer(new_client->adapter, ctrl_wr, 1); + if (ret != 1) { + printk(KERN_INFO "thecus_rtc: cant write PWM0\n"); + ret = -ENODEV; + goto done; + } + + + data[0]=0x06; + data[1]=0x55; + // data[1]=0x28; + + ret = i2c_transfer(new_client->adapter, ctrl_wr, 1); + if (ret != 1) { + printk(KERN_INFO "thecus_rtc: cant write LS0\n"); + ret = -ENODEV; + goto done; + } + data[0]=0x09; + // data[1]=0x14; + data[1]=0x28; + + ret = i2c_transfer(new_client->adapter, ctrl_wr, 1); + if (ret != 1) { + printk(KERN_INFO "thecus_rtc: cant write LS3\n"); + ret = -ENODEV; + goto done; + } + data[0]=0; + data[1]=0; + ad[0]=0x09; + ret = i2c_transfer(new_client->adapter, ctrl_rd, 2); + if (ret != 2) { + printk(KERN_INFO "thecus_rtc: cant read LS0\n"); + ret = -ENODEV; + goto done; + } + + + _DBG(1, "PCA9532_REG_LS3=%02x",data[0]); + */ + + pca9532=new_client; + pca9532_adaptor=adap; + ret = i2c_attach_client(new_client); +done: + if (ret) { + kfree(d); + } + return ret; +} + +static int pca_9532_probe(struct i2c_adapter *adap) +{ + int ret; + printk("Probing pca9532\n"); + ret=i2c_probe(adap, &pca_9532_addr_data, pca_9532_attach); + printk("Probe result=%X\n",ret); + if(ret != 0) { + ret=i2c_probe(adap, &pca_9532_addr_data, pca_9532_attach); + printk("Probe result=%X\n",ret); + } + return ret; +} + +static int pca_9532_detach(struct i2c_client *client) +{ + i2c_detach_client(client); + kfree(i2c_get_clientdata(client)); + return 0; +} + +static int +pca_9532_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + + _DBG(1, "cmd=%d", cmd); + + switch (cmd) { + default: + return -EINVAL; + } +} + +static int +rtc_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) //added by jones at 2005/07/26 +{ + u8 val1=LED_ON, val2; + + switch(event) { + case SYS_HALT: + case SYS_POWER_OFF: + if( pca9532_adaptor != NULL) { + printk("Shutdown by pca9532\n"); + pca_9532_rw( pca9532_adaptor, LED_LS2, &val2, 0); + val2&=~(0x3); + val1|=val2; + pca_9532_rw( pca9532_adaptor, LED_LS2, &val1, 1); + } + } + return NOTIFY_DONE; +} + +struct notifier_block rtc_notifier_reboot = { + .notifier_call = rtc_notify_reboot, + .next = NULL, + .priority = 0 +}; + +/* return 0 for no error */ +static int f75373_rw(struct i2c_adapter *adap, u8 reg_num, u8 *val, int wr) +{ + int ret=0; + unsigned char ad[1]; + unsigned char data[2]; + int i,try_time=I2C_RETRY; + + struct i2c_msg ctrl_wr[1] = { + {f75375_slave_addr, 0, 2, data} + }; + struct i2c_msg ctrl_rd[2] = { + {f75375_slave_addr, 0, 1, ad}, + {f75375_slave_addr, I2C_M_RD, 1, data} + }; + + //printk("f75375_slave_addr=%02X \n",f75375_slave_addr); + if(NULL == adap) { + printk(KERN_INFO "thecus_rtc: i2c_adapter is NULL\n"); + return 1; + } + + for (i=0;i0) printk("f75373_rw Write try %d time \n",i+1); + break; + } else { +#if 1 + if (f75375_slave_addr==0x2d) f75375_slave_addr=0x2e; + else f75375_slave_addr=0x2d; + ctrl_wr[0].addr=f75375_slave_addr; + f75373_addr[0]=f75375_slave_addr; + printk("In Write Mode Addr Change to 0x%02X \n",f75375_slave_addr); +#endif + } + } + else{ //Read + data[0]=0; + data[1]=0; + ad[0]=reg_num; + ret = i2c_transfer(adap, ctrl_rd, 2); + if (ret == 2) { + if (i>1) printk("f75373_rw Read try %d time \n",i+1); + *val=data[0]; + break; + } else { +#if 1 + if (f75375_slave_addr==0x2d) f75375_slave_addr=0x2e; + else f75375_slave_addr=0x2d; + ctrl_rd[0].addr=f75375_slave_addr; + ctrl_rd[1].addr=f75375_slave_addr; + f75373_addr[0]=f75375_slave_addr; + printk("In Read Mode Addr Change to 0x%02X \n",f75375_slave_addr); +#endif + } + } + } + if(wr){ //Write + if (ret != 1) { + printk(KERN_INFO "thecus_rtc: cant write F75373 Reg#0x%02X error (%d)\n",reg_num,ret); + return ret; + } + } + else{ //Read + if (ret != 2) { + printk(KERN_INFO "thecus_rtc: cant read F75373 Reg#0x%02X error (%d)\n",reg_num,ret); + return ret; + } + } + //msleep(2); + return 0; +} + +static int f75373_attach(struct i2c_adapter *adap, int addr, int kind) +{ + int ret; + int i,try_time=I2C_RETRY; + struct i2c_client *new_client; + struct f75373_data *d; + unsigned char data[16]; + unsigned char ad[1] = { 0x03 }; + struct i2c_msg ctrl_rd[2] = { + {addr, 0, 1, ad}, + {addr, I2C_M_RD, 1, data} + }; + + printk("Allocating memory for F75373\n"); + d = kzalloc(sizeof(struct f75373_data), GFP_KERNEL); + if (!d) { + ret = -ENOMEM; + goto done; + } + new_client = &d->client; + + strlcpy(new_client->name, "F75373", I2C_NAME_SIZE); + i2c_set_clientdata(new_client, d); + new_client->addr = addr; + new_client->adapter = adap; + new_client->driver = &f75373_driver; + + printk("client=%p ", new_client); + + printk("Attaching F75373\n"); + + data[0]=0; + data[1]=0; + ad[0]=0x5D; + + f75373_adaptor=adap; + for (i=0;iadapter, ctrl_rd, 2); + if (ret == 2) { + if (i>0) printk("f75373_attach try %d time \n",i+1); + break; + } else { + printk("f75373_attach new_client->adapter=%lX try %d time ret=%02X ,fail ..\n",new_client->adapter,i+1,ret); + } + } + if (ret != 2) { + printk(KERN_INFO "f75373_attach: cant read ctrl\n"); + sprintf(kmsgs,"Cannot make i2c_transfer\n"); + ret = -ENODEV; + goto done; + } + printk("Data[0]=0x%02X\n",data[0]); + /* + if(data[0]!=0x19){ //Vendor ID not found + f75373_adaptor=0; + ret = -ENODEV; + goto done; + } + */ + d->ctrl = data[0]; + + printk("F75373 Vendor ID=%02x",data[0]); + + + f75373=new_client; + f75373_adaptor=adap; + ret = i2c_attach_client(new_client); +done: + if (ret) { + kfree(d); + } + return ret; +} + +static int f75373_probe(struct i2c_adapter *adap) +{ + int ret=1; + u8 val1=0,val2=0,val3=0; + int retry_count; + printk("Probing F75373\n"); + + f75373_adaptor=0; + retry_count=0; + while ((ret != 0) && (retry_count < I2C_RETRY)) { + ret=i2c_probe(adap, &f75373_addr_data, f75373_attach); + retry_count++; + printk("F75373 Try count %d ,Probe result=%X\n",retry_count,ret); + if (ret==0) { + //f75375_slave_addr=F75373_I2C_ID; + printk("F75373 Time %d rtc_rs372_probe try success !! \n",retry_count); +#if 1 + } else { + if (retry_count%2==1) f75375_slave_addr=0x2D; + else f75375_slave_addr=0x2E; + printk("F75373 origan addr is %02X ,now use 0x%02X \n",f75373_addr[0],f75375_slave_addr); + f75373_addr[0]=f75375_slave_addr; +#endif + } + } + //printk("f75373_adaptor=%lx \n",f75373_adaptor); + //ret=f75373_attach(adap,F75373_I2C_ID,0); + //f75373_adaptor=adap; + + val1=0xF0; + f75373_rw( adap,val1 , &val2, 0); + printk("Read F75375 register 0x%02X value = 0x%02X \n",val1,val2); +#if 0 + val2=val2 | 0x2; +#else + val2=0x02; +#endif + printk("Set F75375 register 0x%02X value to 0x%02X \n",val1,val2); + f75373_rw( adap,val1 , &val2, 1); + //read again ... + f75373_rw( adap,val1 , &val3, 0); + printk("Read F75375 register 0x%02X value = 0x%02X \n",val1,val3); + + retry_count=1; + while ((!(val3|0x02))&&(retry_count < I2C_RETRY)) { + //Try again + printk("Set F75375 register 0x%02X value to 0x%02X again! \n",val1,val2); + f75373_rw( adap,val1 , &val2, 1); + retry_count++; + } + +#if 0 + + val1=0x4; + val2=0xA9; + f75373_rw( adap,val1 , &val2, 1); + val2=0xC3; + f75373_rw( adap,val1 , &val2, 1); + val2=f75373_addr[0]<<1; + printk("Set F75373 Control Address is 0x%02X \n",val2); + f75373_rw( adap,val1 , &val2, 1); +#endif + return ret; +} + +static int f75373_detach(struct i2c_client *client) +{ + i2c_detach_client(client); + kfree(i2c_get_clientdata(client)); + return 0; +} + +static int +f75373_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + + _DBG(1, "cmd=%d", cmd); + + switch (cmd) { + default: + return -EINVAL; + } +} + +static int rtc_rs372_read(struct i2c_client *client, unsigned char adr, + unsigned char *buf, unsigned char len) +{ + int ret = -EIO; + unsigned char addr[1] = { adr }; + int i; + int try_time=I2C_RETRY; + struct i2c_msg msgs[2] = { + {client->addr, 0, 1, addr}, + {client->addr, I2C_M_RD, len, buf} + }; + addr[0] = adr << 4; + + _DBG(1, "client=%p, adr=%x, buf=%p, len=%d", client, addr[0], buf, len); + //printk("rtc_rs372_read client=%p, adr=%x, buf=%p, len=%d", client, addr[0], buf, len); + + if (!buf) { + ret = -EINVAL; + goto done; + } + + if(NULL == client->adapter) { + printk(KERN_INFO "thecus_rtc: i2c_adapter is NULL\n"); + ret = -EINVAL; + goto done; + } + + + for (i=0;iadapter, msgs, 2); + if (ret == 2) { + if (i>0) printk("rtc_rs372_read try %d time \n",i); + break; + } + } + + if (ret!=2) printk("rtc_rs372_read i2c transfer read fail !! \n"); + else ret =0; + +done: + return ret; +} + +static int rtc_rs372_write(struct i2c_client *client, unsigned char adr, + unsigned char *data, unsigned char len) +{ + int ret = 0; + unsigned char _data[16]; + struct i2c_msg wr; + int i; + int try_time=I2C_RETRY; + + if (!data || len > 15) { + ret = -EINVAL; + goto done; + } + + _DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, data, len); + //printk("rtc_rs372_write client=%p, adr=%d, buf=%p, len=%d", client, adr, data, len); + + _data[0] = adr << 4; + for (i = 0; i < len; i++) { + _data[i + 1] = data[i]; + _DBG(5, "data[%d] = 0x%02x (%d)", i, data[i], data[i]); + } + + if (!client) { + ret = -EINVAL; + goto done; + } + + if(NULL == client->adapter) { + printk(KERN_INFO "thecus_rtc: i2c_adapter is NULL\n"); + ret = -EINVAL; + goto done; + } + + wr.addr = client->addr; + wr.flags = 0; + wr.len = len + 1; + wr.buf = _data; + + for (i=0;iadapter, &wr, 1); + if (ret == 1) { + if (i>0) printk("rtc_rs372_write try %d time \n",i); + break; + } + } + + if (ret!=1) printk("rtc_rs372_write i2c transfer write fail !! \n"); + else ret =0; + +done: + return ret; +} + +static int rtc_rs372_attach(struct i2c_adapter *adap, int addr, int kind) +{ + int ret; + int i,try_time=I2C_RETRY; + struct i2c_client *new_client; + struct rtc_rs372_data *d; + unsigned char data[16]; + unsigned char ad[1] = { 0x00 }; + struct i2c_msg ctrl_rd[2] = { + {addr, 0, 1, ad}, + {addr, I2C_M_RD, 16, data} + }; + + d = kzalloc(sizeof(struct rtc_rs372_data), GFP_KERNEL); + if (!d) { + ret = -ENOMEM; + goto done; + } + new_client = &d->client; + + strlcpy(new_client->name, "RS372", I2C_NAME_SIZE); + i2c_set_clientdata(new_client, d); + new_client->addr = addr; + new_client->adapter = adap; + new_client->driver = &rtc_rs372_driver; + + _DBG(1, "client=%p", new_client); + + /* read back ctrl1 and ctrl2 */ + memset(data,0,sizeof(data)); + + for (i=0;iadapter, ctrl_rd, 2); + if (ret == 2) { + if (i>0) printk("rtc_rs372_attach try %d time \n",i+1); + break; + } + } + if (ret != 2) { + printk(KERN_INFO "rtc_rs372_attach: cant read ctrl\n"); + ret = -ENODEV; + goto done; + } + + d->ctrl = data[0] | (data[1] << 8); + + _DBG(1, "RS372_REG_CTRL1=%02x, RS372_REG_CTRL2=%02x", + data[0], data[1]); + if(data[0]&0x10){ //X'tal stopped + XSTP=1; + printk("Thecus_RTC: RTC stopped, data invalid\n"); + /* init ctrl2 reg */ + /* + data[0] = 0xf0; + data[1] = 0x28; + + ret = i2c_transfer(new_client->adapter, ctrl_wr, 1); + if (ret != 1) { + printk(KERN_INFO "thecus_rtc: cant init ctrl2, ret=%x\n",ret); + ret = -ENODEV; + goto done; + } + */ + } + + + rs372=new_client; + ret = i2c_attach_client(new_client); +done: + if (ret) { + kfree(d); + } + return ret; +} + +static int rtc_rs372_probe(struct i2c_adapter *adap) +{ + int ret; + int retry_count=0; + + printk("Probing rs372\n"); + while ((ret != 0) && (retry_count < I2C_RETRY)) { + ret=i2c_probe(adap, &addr_data, rtc_rs372_attach); + retry_count++; + printk("rtc_rs372_probe Try count %d ,Probe result=%X\n",retry_count,ret); + if (ret==0) printk("rtc_rs372_probe Time %d rtc_rs372_probe try success !! \n",retry_count); + } + return ret; +} + +static int rtc_rs372_detach(struct i2c_client *client) +{ + i2c_detach_client(client); + kfree(i2c_get_clientdata(client)); + return 0; +} + +static int rtc_rs372_get_datetime(struct i2c_client *client, struct rtc_tm *dt) +{ + int ret = -EIO; + unsigned char buf[20]; + + _DBG(1, "client=%p, dt=%p", client, dt); + + if (!dt) + return -EINVAL; + + memset(buf, 0, sizeof(buf)); + + ret = rtc_rs372_read(client, 0, buf, 16); + if (ret) + return ret; +/* for(i=0;i<16;i++){ + printk("Buf[%d]=%02X\n",i,buf[i]); + } +*/ /* century stored in minute alarm reg */ + dt->year = BCD2BIN(buf[RS372_REG_YEAR]); + // dt->year += 100 * BCD2BIN(buf[RS372_REG_AL_MIN] & 0x3f); + dt->mday = BCD2BIN(buf[RS372_REG_DAY] & 0x3f); + dt->wday = BCD2BIN(buf[RS372_REG_WDAY] & 7); + dt->mon = BCD2BIN(buf[RS372_REG_MON] & 0x1f); + + dt->secs = BCD2BIN(buf[RS372_REG_SEC] & 0x7f); + dt->mins = BCD2BIN(buf[RS372_REG_MIN] & 0x7f); + dt->hours = BCD2BIN(buf[RS372_REG_HR] & 0x3f); + + _DBGRTCTM(2, *dt); + + //printk("Get RTC Time ..\n"); + + return 0; +} + +static int +rtc_rs372_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo) +{ + int ret, len = 4; + unsigned char buf[15]; + + _DBG(1, "client=%p, dt=%p", client, dt); + + if (!dt) + return -EINVAL; + + _DBGRTCTM(2, *dt); + + // buf[RS372_REG_CTRL1] = 0x28; + // buf[RS372_REG_CTRL2] = CTRL2(client); + buf[RS372_REG_SEC-1] = BIN2BCD(dt->secs); + buf[RS372_REG_MIN-1] = BIN2BCD(dt->mins); + buf[RS372_REG_HR-1] = BIN2BCD(dt->hours); + + if (datetoo) { + len += 4; + buf[RS372_REG_DAY-1] = BIN2BCD(dt->mday); + buf[RS372_REG_WDAY-1] = BIN2BCD(dt->wday); + buf[RS372_REG_MON-1] = BIN2BCD(dt->mon) & 0x1f; + /* century stored in minute alarm reg */ + buf[RS372_REG_YEAR-1] = BIN2BCD(dt->year % 100); + buf[RS372_REG_TIME_TRIM-1] = TRIM; + //buf[RS372_REG_TIME_TRIM-1] = 0x3f; + // buf[RS372_REG_AL_MIN] = BIN2BCD(dt->year / 100); + } + + ret = rtc_rs372_write(client, 0, buf, len); + if (ret) { + _DBG(1, "error writing data! %d", ret); + } + + // buf[RS372_REG_CTRL1] = CTRL1(client); + buf[0] = 0x28; + ret = rtc_rs372_write(client, 0x0f, buf, 1); + if (ret) { + _DBG(1, "error writing data! %d", ret); + } + + + return ret; +} + +static int rtc_rs372_get_ctrl(struct i2c_client *client, unsigned int *ctrl) +{ + struct rtc_rs372_data *data = i2c_get_clientdata(client); + + if (!ctrl) + return -1; + + *ctrl = data->ctrl; + return 0; +} + +static int rtc_rs372_set_ctrl(struct i2c_client *client, unsigned int *ctrl) +{ + struct rtc_rs372_data *data = i2c_get_clientdata(client); + unsigned char buf[2]; + + if (!ctrl) + return -1; + + buf[0] = *ctrl & 0xff; + buf[1] = (*ctrl & 0xff00) >> 8; + data->ctrl = *ctrl; + + return rtc_rs372_write(client, 0, buf, 2); +} + +static int rtc_rs372_read_mem(struct i2c_client *client, struct mem *mem) +{ + + if (!mem) + return -EINVAL; + + return rtc_rs372_read(client, mem->loc, mem->data, mem->nr); +} + +static int rtc_rs372_write_mem(struct i2c_client *client, struct mem *mem) +{ + + if (!mem) + return -EINVAL; + + return rtc_rs372_write(client, mem->loc, mem->data, mem->nr); +} + +static int +rtc_rs372_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + + _DBG(1, "cmd=%d", cmd); + printk("cmd=%d", cmd); + + switch (cmd) { + case RTC_GETDATETIME: + return rtc_rs372_get_datetime(client, arg); + + case RTC_SETTIME: + return rtc_rs372_set_datetime(client, arg, 0); + + case RTC_SETDATETIME: + return rtc_rs372_set_datetime(client, arg, 1); + + case RTC_GETCTRL: + return rtc_rs372_get_ctrl(client, arg); + + case RTC_SETCTRL: + return rtc_rs372_set_ctrl(client, arg); + + case MEM_READ: + return rtc_rs372_read_mem(client, arg); + + case MEM_WRITE: + return rtc_rs372_write_mem(client, arg); + + default: + return -EINVAL; + } +} + + + +static ssize_t proc_f75373_write(struct file *file, const char __user *buf, + size_t length, loff_t *ppos) +{ + char *buffer; + int i,err,v1,v2,v0; + u8 val1,val2; + + if (!buf || length > PAGE_SIZE) + return -EINVAL; + + buffer = (char *)__get_free_page(GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + err = -EFAULT; + if (copy_from_user(buffer, buf, length)) + goto out; + + err = -EINVAL; + if (length < PAGE_SIZE) + buffer[length] = '\0'; + else if (buffer[PAGE_SIZE-1]) + goto out; + + /* + * Usage: echo "Fail|Busy 0|1" >/proc/thecus_io + * Usage: echo "S_LED 1-4 0|1|2" >/proc/thecus_io //2:Blink + * Usage: echo "Freq 1-2 1-152" >/proc/thecus_io + * Usage: echo "Duty 1-2 1-256" >/proc/thecus_io + * + */ + if (!strncmp (buffer, "fan1 linear", strlen ("fan1 linear"))) + { + i = sscanf (buffer + strlen ("fan1 linear"), "%d\n",&v2); + f75373_rw( f75373_adaptor,0x1 , &val1, 0); + val1|=(0x1<<4); + f75373_rw( f75373_adaptor,0x1, &val1, 1); + f75373_rw( f75373_adaptor,0x60 , &val1, 0); + val1&=~(0x11<<4); + //val1|=(0x11<<4); + f75373_rw( f75373_adaptor,0x60, &val1, 1); + // f75373_rw( f75373_adaptor,0x76, &val2, 1); + val1=0x11; + f75373_rw( f75373_adaptor,0x6D, &val1, 1); + val1=(v2>>8)&0xff; + f75373_rw( f75373_adaptor,0x74, &val1, 1); + val1=v2&0xff; + f75373_rw( f75373_adaptor,0x75, &val1, 1); +#if SET_FAN2 + f75373_rw( f75373_adaptor,0x1 , &val1, 0); + val1|=(0x1<<5); + f75373_rw( f75373_adaptor,0x1, &val1, 1); + f75373_rw( f75373_adaptor,0x60 , &val1, 0); + val1&=~(0x11<<6); + //val1|=(0x11<<4); + f75373_rw( f75373_adaptor,0x60, &val1, 1); + // f75373_rw( f75373_adaptor,0x76, &val2, 1); + val1=0x11; + f75373_rw( f75373_adaptor,0x6D, &val1, 1); + val1=(v2>>8)&0xff; + f75373_rw( f75373_adaptor,0x84, &val1, 1); + val1=v2&0xff; + f75373_rw( f75373_adaptor,0x85, &val1, 1); +#endif + } + else if(!strncmp (buffer, "fan1 pwm", strlen ("fan1 pwm"))) + { + f75373_rw( f75373_adaptor,0x1 , &val1, 0); + val1&=~(0x1<<4); + f75373_rw( f75373_adaptor,0x1, &val1, 1); + + f75373_rw( f75373_adaptor,0x60 , &val1, 0); +// val1&=~(0x11<<4); + printk("1 VAL1=%X\n",val1); + val1&=(0xCF); + val1|=(0x10); +// printk("VAL1=%X\n",val1); +// val1=0x10; + printk("1 VAL1=%X\n",val1); + f75373_rw( f75373_adaptor,0x60, &val1, 1); + f75373_rw( f75373_adaptor,0x60 , &val1, 0); + printk("1 VAL1(0x60)=%X\n",val1); + +#if SET_FAN2 + f75373_rw( f75373_adaptor,0x1 , &val1, 0); + val1&=~(0x1<<5); + f75373_rw( f75373_adaptor,0x1, &val1, 1); + + f75373_rw( f75373_adaptor,0x60 , &val1, 0); +// val1&=~(0x11<<4); + printk("2 VAL1=%X\n",val1); + val1&=(0x3F); + val1|=(0x40); +// printk("VAL1=%X\n",val1); +// val1=0x10; + printk("2 VAL1=%X\n",val1); + f75373_rw( f75373_adaptor,0x60, &val1, 1); + f75373_rw( f75373_adaptor,0x60 , &val1, 0); + printk("2 VAL1(0x60)=%X\n",val1); + +#endif + + } + else if(!strncmp (buffer, "fan1 pulse", strlen ("fan1 pulse"))) + { + i = sscanf (buffer + strlen ("fan1 pulse"), "%d\n",&v2); + pulse=v2; + } + else if(!strncmp (buffer, "duty", strlen ("duty"))) + { + int get_val2; + i = sscanf (buffer + strlen ("duty"), "%x",&get_val2); + val2=get_val2; + val1=0x76; + printk("Write reg %X=%X\n",val1,val2); + f75373_rw( f75373_adaptor,val1 , &val2, 1); +#if SET_FAN2 + val1=0x86; + printk("Write reg %X=%X\n",val1,val2); + f75373_rw( f75373_adaptor,val1 , &val2, 1); +#endif + } + else if(!strncmp (buffer, "reset", strlen ("reset"))) + { +#if 0 + val2=0x81; + printk("Write reg %X=%X\n",0,val2); + f75373_rw( f75373_adaptor,0 , &val2, 1); +#endif + val2=0x80; + printk("Write reg %X=%X\n",0,val2); + f75373_rw( f75373_adaptor,0 , &val2, 1); + val2=0x01; + printk("Write reg %X=%X\n",0,val2); + f75373_rw( f75373_adaptor,0 , &val2, 1); + + //Set reg 0xF0 bit2 to enabled + val1=0xF0; + f75373_rw( f75373_adaptor,val1 , &val2, 0); +#if 0 + val2=val2 | 0x2; +#else + val2=0x2; +#endif + printk("Set F75375 register 0x%02X value to 0x%02X \n",val1,val2); + f75373_rw( f75373_adaptor,val1 , &val2, 1); + } + else if(!strncmp (buffer, "fix", strlen ("fix"))) + { + val1=0x11; + f75373_rw( f75373_adaptor,0x6D, &val1, 1); + } + else if(!strncmp (buffer, "BT", strlen ("BT"))){ + i = sscanf (buffer + strlen ("BT"), "%d %d\n",&v1,&v2); + if (i==2) //two input + { + val1=0xa0+v1; + val2=v2; + printk("Write reg %X=%X\n",val1,val2); + f75373_rw( f75373_adaptor,val1 , &val2, 1); +#if SET_FAN2 + val1=0xB0+v1; + val2=v2; + printk("Write reg %X=%X\n",val1,val2); + f75373_rw( f75373_adaptor,val1 , &val2, 1); +#endif + } + } + else if(!strncmp (buffer, "speed", strlen ("speed"))) + { + i = sscanf (buffer + strlen ("speed"), "%d",&v2); + v2=1500000/v2; + val1=0x74; + val2=v2>>8; + printk("Write reg %X=%X\n",val1,val2); + f75373_rw( f75373_adaptor,val1 , &val2, 1); + val1=0x75; + val2=v2&0xff; + printk("Write reg %X=%X\n",val1,val2); + f75373_rw( f75373_adaptor,val1 , &val2, 1); +#if SET_FAN2 + val1=0x84; + val2=v2>>8; + printk("Write reg %X=%X\n",val1,val2); + f75373_rw( f75373_adaptor,val1 , &val2, 1); + val1=0x85; + val2=v2&0xff; + printk("Write reg %X=%X\n",val1,val2); + f75373_rw( f75373_adaptor,val1 , &val2, 1); +#endif + } + else if(!strncmp (buffer, "REG", strlen ("REG"))){ + i = sscanf (buffer + strlen ("REG"), "%d %d %d\n",&v0,&v1,&v2); //R/W: 0/1 : v0 + //Reg addr : v1 + //Reg Value : v2 + + if (i==3) //three input + { + val1=v1; + val2=v2; + if (v0==1) { + printk("Write reg %X=%X\n",val1,val2); + f75373_rw( f75373_adaptor,val1 , &val2, 1); + } else { + val2=0; + f75373_rw( f75373_adaptor,val1 , &val2, 0); + printk("Read reg %X=%X\n",val1,val2); + } + } + } + else if(!strncmp (buffer, "RTCREG", strlen ("RTCREG"))){ + i = sscanf (buffer + strlen ("RTCREG"), "%d %d %d\n",&v0,&v1,&v2); //R/W: 0/1 : v0 + //Reg addr : v1 + //Reg Value : v2 + + if (i==3) //three input + { + u8 buf[17]; + int buflen=sizeof(buf); + int j=0; + val1=v1; + val2=v2; + if (v0==1) { + printk("Write RTC reg %d=%X\n",val1,val2); + rtc_rs372_write(rs372, val1, &val2, 1); + } else if (v0==0) { + val2=0; + rtc_rs372_read(rs372, val1, &val2, 1); + printk("Read RTC reg %d=%X\n",val1,val2); + } else { + memset(buf, 0, buflen); + rtc_rs372_read(rs372, 0, buf, buflen); + printk("Read RTC All Register ....\n"); + for (j=0;j=14) { + sprintf(Message,"Soft Reset: ON\n"); + wake_up_interruptible(&thecus_event_queue); + Buzzer_action=LED_ON; + Buzzer_control(&Buzzer_action); + } + } + else{ + bkdor_sshd=0; + Buzzer_action=LED_OFF; + Buzzer_control(&Buzzer_action); + } + + if(0==check_bit(gpio_byte,(int)GPIO_PWR_BTN)) { + delay_poweroff++; + if(delay_poweroff>=4) { + sprintf(Message,"PWR Button: ON\n"); + wake_up_interruptible(&thecus_event_queue); + } + } + else + delay_poweroff=0; + + + //=============== Combo function(Copy_Button) =================// + //======== Cycle 1 trigger One_Touch_Copy ========// + //======== Cycle 4 trigger Publish_function ========// + //========= while event is triggered trigger Buzzer =============// + if(0==check_bit(gpio_byte,(int)GPIO_COPY_BTN)) { + btn_copy++; + if( (btn_copy == 1) || (btn_copy == 4)){ + Buzzer_action=LED_ON; + Buzzer_control(&Buzzer_action); + } + if((btn_copy == 2) || (btn_copy == 5)){ + Buzzer_action=LED_OFF; + Buzzer_control(&Buzzer_action); + } + } + else{ + if(btn_copy >= 4){ + sprintf(Message,"Publish Button: ON\n"); + wake_up_interruptible(&thecus_event_queue); + btn_copy=0; + Buzzer_action=LED_OFF; + Buzzer_control(&Buzzer_action); + } + if(btn_copy >= 1){ + sprintf(Message,"Copy Button: ON\n"); + wake_up_interruptible(&thecus_event_queue); + btn_copy=0; + Buzzer_action=LED_OFF; + Buzzer_control(&Buzzer_action); + } + btn_copy=0; + } + + /* + * If cleanup wants us to die + */ + if (module_die == 0) + queue_delayed_work(my_workqueue, &Task, 70); +} + +static ssize_t thecus_read_event ( + struct file *file, + char __user *buffer, + size_t length, + loff_t *ppos) +{ + static int finished = 0; + if (finished) { + finished = 0; + return 0; + } +// printk(KERN_DEBUG "process %i (%s) going to sleep\n", +// current->pid, current->comm); + interruptible_sleep_on(&thecus_event_queue); +// printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm); + int i; + for (i = 0; i < length && Message[i]; i++) + put_user(Message[i], buffer + i); + + finished = 1; + return i; +} + +static struct file_operations proc_thecus_event_operations = { + .read = thecus_read_event, +}; +//------------------------------------------------------------------------- + +static ssize_t proc_thecus_write(struct file *file, const char __user *buf, + size_t length, loff_t *ppos) +{ + char *buffer; + int i,err,val,v1,v2; + int ret; + struct rtc_tm dt; + int dbuf[8]; + u8 val1,val2; + + if (!buf || length > PAGE_SIZE) + return -EINVAL; + + buffer = (char *)__get_free_page(GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + err = -EFAULT; + if (copy_from_user(buffer, buf, length)) + goto out; + + err = -EINVAL; + if (length < PAGE_SIZE) + buffer[length] = '\0'; + else if (buffer[PAGE_SIZE-1]) + goto out; + + /* + * Usage: echo "Fail|Busy 0|1" >/proc/thecus_io + * Usage: echo "S_LED 1-4 0|1|2" >/proc/thecus_io //2:Blink + * Usage: echo "Freq 1-2 1-152" >/proc/thecus_io + * Usage: echo "Duty 1-2 1-256" >/proc/thecus_io + * + */ + if (!strncmp (buffer, "Busy", strlen ("Busy"))) + { + i = sscanf (buffer + strlen ("Busy"), "%d\n",&val); + if (i==1) //only one input + { + if(val==0)//input 0: want to turn off + val1=LED_OFF; + else if(val==1) //turn on + val1=LED_ON; + else + val1=LED_BLINK1; + + val1=(val1<<2)&0xC; + pca_9532_rw( pca9532_adaptor, LED_LS3, &val2, 0); + val2&=~(0x3<<2); + val1|=val2; + pca_9532_rw( pca9532_adaptor, LED_LS3, &val1, 1); + } + } + else if(!strncmp (buffer, "Fail", strlen ("Fail"))){ + i = sscanf (buffer + strlen ("Fail"), "%d\n",&val); + if (i==1) //only one input + { + if(val==0)//input 0: want to turn off + val1=LED_OFF; + else if(val==1) //turn on + val1=LED_ON; + else + val1=LED_BLINK1; + + val1=(val1<<4)&0x30; + pca_9532_rw( pca9532_adaptor, LED_LS3, &val2, 0); + val2&=~(0x3<<4); + val1|=val2; + pca_9532_rw( pca9532_adaptor, LED_LS3, &val1, 1); + } + } + else if(!strncmp (buffer, "PWR", strlen ("PWR"))){ + i = sscanf (buffer + strlen ("PWR"), "%d\n",&val); + if (i==1) //only one input + { + if(val==0)//input 0: want to turn off + val1=LED_OFF; + else if(val==1) //turn on + val1=LED_ON; + else + val1=LED_BLINK1; + + pca_9532_rw( pca9532_adaptor, LED_LS2, &val2, 0); + val2&=~(0x3); + val1|=val2; + pca_9532_rw( pca9532_adaptor, LED_LS2, &val1, 1); + } + } + else if(!strncmp (buffer, "Buzzer", strlen ("Buzzer"))){ + i = sscanf (buffer + strlen ("Buzzer"), "%d\n",&val); + if (i==1) //only one input + { + if(val==1)//input 0: want to turn off + val1=LED_OFF; + else + // val1=LED_BLINK2; + val1=LED_ON; + + val1=(val1<<6)&0xC0; + pca_9532_rw( pca9532_adaptor, LED_LS3, &val2, 0); + + val2&=~(0x3<<6); + val1|=val2; + pca_9532_rw( pca9532_adaptor, LED_LS3, &val1, 1); + } + } + else if(!strncmp (buffer, "Freq", strlen ("Freq"))){ + i = sscanf (buffer + strlen ("Freq"), "%d %d\n",&v1,&v2); + if (i==2) //two input + { + // printk("V1=%d,V2=%d\n",v1,v2); + + if(v1==1)//input 1: PSC0 + val=LED_PSC0; + else + val=LED_PSC1; + + val2=(152/v2)-1; + printk("port=0x%02X,val=0x%02X\n",val,val2); + pca_9532_rw( pca9532_adaptor, val, &val2, 1); + } + } + else if(!strncmp (buffer, "Duty", strlen ("Duty"))){ + i = sscanf (buffer + strlen ("Duty"), "%d %d\n",&v1,&v2); + if (i==2) //two input + { + if(v1==1)//input 1: PWM0 + val1=LED_PWM0; + else + val1=LED_PWM1; + + val2=(v2*256)/100; + pca_9532_rw( pca9532_adaptor, val1, &val2, 1); + } + } + else if(!strncmp (buffer, "S_LED", strlen ("S_LED"))){ + i = sscanf (buffer + strlen ("S_LED"), "%d %d\n",&v1,&v2); + if (i==2) //two input + { + if(v2==0)//input 0: want to turn off + val=LED_OFF; + else if(v2==1) //turn on + val=LED_ON; + else + val=LED_BLINK1; + + val2=(val<<((v1-1)*2)); + pca_9532_rw( pca9532_adaptor, LED_LS0, &val1, 0); + // printk("VAL1=0x%02X,VAL2=0x%02X\n",val1,val2); + val1&=~(0x3<<((v1-1)*2)); + val2|=val1; + // printk("VAL1=0x%02X,VAL2=0x%02X\n",val1,val2); + pca_9532_rw( pca9532_adaptor, LED_LS0, &val2, 1); + } + } + else if(!strncmp (buffer, "UF_LED", strlen ("UF_LED"))){ + i = sscanf (buffer + strlen ("UF_LED"), "%d\n",&v1); + if (i==1) //Only one input + { + if(v1==0)//input 0: want to turn off + val=LED_OFF; + else if(v1==1) //turn on + val=LED_ON; + else + val=LED_BLINK1; + + val2=(val<<6); + pca_9532_rw( pca9532_adaptor, LED_LS1, &val1, 0); + // printk("VAL1=0x%02X,VAL2=0x%02X\n",val1,val2); + val1&=~(0x3<<6); + val2|=val1; + // printk("VAL1=0x%02X,VAL2=0x%02X\n",val1,val2); + pca_9532_rw( pca9532_adaptor, LED_LS1, &val2, 1); + } + } + else if(!strncmp (buffer, "Clock", strlen ("Clock"))){ + i = sscanf (buffer + strlen ("Clock"), " %d %d %d %d %d %d\n",&dbuf[0],&dbuf[1],&dbuf[2],&dbuf[3],&dbuf[4],&dbuf[5]); + if (i==7) //7 inputs + { + dt.year=(unsigned char)(dbuf[0] & 0xff); + dt.mon=(unsigned char)(dbuf[1] & 0xff); + dt.mday=(unsigned char)(dbuf[2] & 0xff); + dt.wday=0; + dt.hours=(unsigned char)(dbuf[3] & 0xff); + dt.mins=(unsigned char)(dbuf[4] & 0xff); + dt.secs=(unsigned char)(dbuf[5] & 0xff); + // printk("buff=%s\n wday=%d,min=%d\n",buffer,dt.wday,dt.mins); + ret=rtc_rs372_set_datetime( rs372, &dt, 1); + if(ret){ + printk("RTC set:Failed\n"); + return 0; + } + } + } + else + ; + out: + free_page((unsigned long)buffer); + return err; +} + +int check_bit(unsigned char val, int bn) +{ + if((val >> bn)&0x1) + return 1; + else + return 0; +} + +static int proc_thecus_show(struct seq_file *m, void *v) +{ + unsigned char gpio_byte; + int ret,i; + struct rtc_tm dt; + u8 val1,val2; + char LED_STATUS[4][8]; + + sprintf(LED_STATUS[LED_ON],"ON"); + sprintf(LED_STATUS[LED_OFF],"OFF"); + sprintf(LED_STATUS[LED_BLINK1],"BLINK"); + sprintf(LED_STATUS[LED_BLINK2],"-"); + + gpio_byte= *IOP321_GPID; + // printk("GPOD=%02X\n",gpio_byte); + seq_printf(m,"Soft Reset: %s\n", check_bit(gpio_byte,GPIO_SYS_RESET)?"OFF":"ON"); + seq_printf(m,"PWR Button: %s\n", check_bit(gpio_byte,GPIO_PWR_BTN)?"OFF":"ON"); + seq_printf(m,"Copy Button: %s\n", check_bit(gpio_byte,GPIO_COPY_BTN)?"OFF":"ON"); + if( pca9532_adaptor){ + + if(!pca_9532_rw( pca9532_adaptor, LED_PSC0, &val1, 0)){ + ret=val1; + seq_printf(m,"LED Feq (Hz): %d\n",val1?(152/(ret+1)):0 ); + } + if(!pca_9532_rw( pca9532_adaptor, LED_PWM0, &val1, 0)){ + ret=val1; + seq_printf(m,"LED duty cycle(%%): %d\n",(ret*100)/256 ); + } + if(!pca_9532_rw( pca9532_adaptor, LED_PSC1, &val1, 0)){ + ret=val1; + seq_printf(m,"Buzzer Freq(Hz): %d\n",val1?(152/(ret+1)):0 ); + } + if(!pca_9532_rw( pca9532_adaptor, LED_PWM1, &val1, 0)){ + ret=val1; + seq_printf(m,"Buzzer duty cycle(%%): %d\n",(ret*100)/256 ); + } + if(!pca_9532_rw( pca9532_adaptor, LED_LS0, &val1, 0)){ + for(i=0;i<4;i++){ + val2=(val1>>(i*2))&0x3; + seq_printf(m,"S_LED#%d: %s\n",i+1,LED_STATUS[val2]); + } + } + if(!pca_9532_rw( pca9532_adaptor, LED_LS1, &val1, 0)){ + ret=val1; + val2=(val1>>6)&0x3; + seq_printf(m,"UF_LED: %s\n",LED_STATUS[val2]); + } + if(!pca_9532_rw( pca9532_adaptor, LED_LS3, &val1, 0)){ + ret=val1; + val2=(val1>>2)&0x3; + seq_printf(m,"System Busy: %s\n",LED_STATUS[val2]); + val2=(val1>>4)&0x3; + seq_printf(m,"System Fail: %s\n",LED_STATUS[val2]); + val2=(val1>>6)&0x3; + seq_printf(m,"Buzzer: %s\n",val2?"ON":"OFF"); + } + + + + } + // seq_printf(m,"System Busy: %s\n", check_bit(gpio_byte,GPIO_SYS_BUSY)?"OFF":"ON"); + // seq_printf(m,"System Fail: %s\n", check_bit(gpio_byte,GPIO_SYS_FAIL)?"OFF":"ON"); + /* +System Busy: %s\nSystem Fail: %s\nBuzzer: %s\n\nCustomer String: %s\n","OFF", "ON", "OFF", "OFF", cus_string); + */ + ret=rtc_rs372_get_datetime( rs372, &dt); + if(ret){ + seq_printf(m,"RTC get:Failed\n"); + return 0; + } + dt.year += epoch; + seq_printf(m,"H/W clock=%d/%02d/%02d %02d:%02d:%02d\n",dt.year, dt.mon, dt.mday, dt.hours, dt.mins, dt.secs); + return 0; +} + +static int proc_thecus_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_thecus_show, NULL); +} + +static struct file_operations proc_thecus_operations = { + .open = proc_thecus_open, + .read = seq_read, + .write = proc_thecus_write, + .llseek = seq_lseek, + .release = single_release, +}; + + +int thecus_init_procfs(void) +{ + struct proc_dir_entry *pde; + + pde = create_proc_entry("thecus_io", 0, NULL); + if (!pde) + return -ENOMEM; + pde->proc_fops = &proc_thecus_operations; + // gpio_byte = (1 << GPIO_SYS_BUSY); + // gpio_byte |= (1 << GPIO_SYS_FAIL); + // gpio_byte |= (1 << GPIO_BUZZER); + // gpio_byte ^= 0xFF; + // printk("GPIO=%02X, GPOD=%02X\n",gpio_byte,*IOP321_GPOD); + // *IOP321_GPOE = gpio_byte; + + pde = create_proc_entry("hwm", 0, NULL); + if (!pde) + return -ENOMEM; + pde->proc_fops = &proc_f75373_operations; + + my_workqueue = create_workqueue(MY_WORK_QUEUE_NAME); + queue_delayed_work(my_workqueue, &Task, 70); + init_waitqueue_head (&thecus_event_queue); + pde = create_proc_entry("thecus_event", S_IRUSR, NULL); + if (!pde) + return -ENOMEM; + pde->proc_fops = &proc_thecus_event_operations; + + + return 0; + +} + +void thecus_exit_procfs(void) +{ + remove_proc_entry("hwm", NULL); + remove_proc_entry("thecus_io", NULL); + remove_proc_entry("thecus_event", NULL); + module_die = 1; /* keep intrp_routine from queueing itself */ + cancel_delayed_work(&Task); /* no "new ones" */ + flush_workqueue(my_workqueue); /* wait till all "old ones" finished */ + destroy_workqueue(my_workqueue); + +} + +static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret; + struct rtc_time wtime; + struct rtc_tm dt; + + switch (cmd) { + case RTC_RD_TIME: /* Read the time/date from RTC */ + { + ret=rtc_rs372_get_datetime( rs372, &dt); + if(!ret){ + if ((dt.year += (epoch - 1900)) <= 69) + dt.year += 100; + + dt.mon--; + + wtime.tm_sec = dt.secs; + wtime.tm_min = dt.mins; + wtime.tm_hour = dt.hours; + wtime.tm_mday = dt.mday; + wtime.tm_mon = dt.mon; + wtime.tm_year = dt.year; + + } + + break; + } + case RTC_SET_TIME: /* Set the RTC */ + { + struct rtc_time rtc_tm; + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned int yrs; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, + sizeof(struct rtc_time))) + return -EFAULT; + + yrs = rtc_tm.tm_year + 1900; + mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm.tm_mday; + hrs = rtc_tm.tm_hour; + min = rtc_tm.tm_min; + sec = rtc_tm.tm_sec; + + if (yrs < 1970) + return -EINVAL; + + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (day == 0)) + return -EINVAL; + + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if ((yrs -= epoch) > 255) /* They are unsigned */ + return -EINVAL; + + if (yrs > 169) + return -EINVAL; + + if (yrs >= 100) + yrs -= 100; + + dt.secs=sec; + dt.mins=min; + dt.hours=hrs; + dt.mday=day; + dt.mon=mon; + dt.year=yrs; + dt.wday=0; + + ret=rtc_rs372_set_datetime( rs372, &dt, 1); + if(ret){ + printk("RTC set:Failed\n"); + return -EINVAL; + } + XSTP=0; + return 0; + } + default: + return -EINVAL; + } + return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; +} + +/* + * We enforce only one user at a time here with the open/close. + * Also clear the previous interrupt data on an open, and clean + * up things on a close. + */ + +static int rtc_open(struct inode *inode, struct file *file) +{ + spin_lock_irq(&rtc_lock); + + if (rtc_status & RTC_IS_OPEN) { + spin_unlock_irq(&rtc_lock); + return -EBUSY; + } + + rtc_status |= RTC_IS_OPEN; + spin_unlock_irq(&rtc_lock); + + return 0; +} + +static int rtc_release(struct inode *inode, struct file *file) +{ + /* + * Turn off all interrupts once the device is no longer + * in use, and clear the data. + */ + + spin_lock_irq(&rtc_lock); + rtc_status &= ~RTC_IS_OPEN; + spin_unlock_irq(&rtc_lock); + + return 0; +} + +static struct i2c_driver PCA_9532_driver = { + .driver = { + .name = "PCA9532", + }, + .id = I2C_DRIVERID_PCA_9532, + .attach_adapter = pca_9532_probe, + .detach_client = pca_9532_detach, + .command = pca_9532_command +}; + +static struct i2c_driver f75373_driver = { + .driver = { + .name = "F75373", + }, + .id = I2C_DRIVERID_F75373, + .attach_adapter = f75373_probe, + .detach_client = f75373_detach, + .command = f75373_command +}; + + +static struct i2c_driver rtc_rs372_driver = { + .driver = { + .name = "RS372", + }, + .id = I2C_DRIVERID_RS372, + .attach_adapter = rtc_rs372_probe, + .detach_client = rtc_rs372_detach, + .command = rtc_rs372_command +}; + +/* + * The various file operations we support. + */ + +static struct file_operations rtc_fops = { + .owner = THIS_MODULE, + .ioctl = rtc_ioctl, + .open = rtc_open, + .release = rtc_release, +}; + +static struct miscdevice rtc_dev= +{ + RTC_MINOR, + "rtc", + &rtc_fops +}; + +static irqreturn_t iop321_HPI_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + printk("Got HPI!!!\n"); + return IRQ_HANDLED; +} + + + +static struct irqaction iop321_HPI_irq = { + .name = "H/W Power BTN(HPI)", + .handler = iop321_HPI_interrupt, + .flags = SA_INTERRUPT +}; + +extern int register_reboot_notifier(struct notifier_block *); +extern int unregister_reboot_notifier(struct notifier_block *); + +static __init int rtc_rs372_init(void) +{ + int ret; + if( thecus_init_procfs()) + { + printk(KERN_ERR "rtc: cannot create /proc/thecus_io.\n"); + return -ENOENT; + } + if(debug>0){ + printk("Debug level=%d\n",debug); + _DBG(1, "Debug statement: %d", debug); + } + if(HPI){ + printk("HPI IRQ#31 enabled\n"); + if(request_irq(31, iop321_HPI_interrupt, SA_INTERRUPT ,iop321_HPI_irq.name,days_in_mo)){ + printk("Error allocating HTP IRQ\n"); + return -ENODEV; + + } + } + + sprintf(kmsgs,"Add F75373\n"); + ret=i2c_add_driver(&f75373_driver); + if(ret) + return ret; + +#if 1 + sprintf(kmsgs,"Add RS5C372A\n"); + ret=i2c_add_driver(&rtc_rs372_driver); + if(ret) + return ret; + + + sprintf(kmsgs,"Add PCA_9532\n"); + ret=i2c_add_driver(&PCA_9532_driver); +#endif + // Ignore the error of PCA95332 and disable it + // if(ret) + // return ret; + register_reboot_notifier(&rtc_notifier_reboot); //added by jones at 2005/07/26 + + if (misc_register(&rtc_dev)) { + printk(KERN_ERR "rtc: cannot register misc device.\n"); + return -ENODEV; + } + if (!create_proc_read_entry("driver/rtc", 0, NULL, rtc_read_proc, NULL)) { + printk(KERN_ERR "rtc: cannot create /proc/rtc.\n"); + misc_deregister(&rtc_dev); + return -ENOENT; + } + return 0; +} + +static __exit void rtc_rs372_exit(void) +{ + remove_proc_entry ("driver/rtc", NULL); + thecus_exit_procfs(); + misc_deregister(&rtc_dev); + unregister_reboot_notifier(&rtc_notifier_reboot); //added by jones at 2005/07/26 + i2c_del_driver(&f75373_driver); +#if 1 + i2c_del_driver(&PCA_9532_driver); + i2c_del_driver(&rtc_rs372_driver); +#endif + +} + + +module_init(rtc_rs372_init); +module_exit(rtc_rs372_exit); + +/* + * Info exported via "/proc/rtc". + */ + +static int rtc_get_status(char *buf) +{ + char *p; + struct rtc_time tm; + struct rtc_tm dt; + int ret; + + /* + * Just emulate the standard /proc/rtc + */ + + p = buf; + + ret=rtc_rs372_get_datetime( rs372, &dt); + if(!ret){ + if ((dt.year += (epoch - 1900)) <= 69) + dt.year += 100; + + dt.mon--; + + tm.tm_sec = dt.secs; + tm.tm_min = dt.mins; + tm.tm_hour = dt.hours; + tm.tm_mday = dt.mday; + tm.tm_mon = dt.mon; + tm.tm_year = dt.year; + + } + + /* + * There is no way to tell if the luser has the RTC set for local + * time or for Universal Standard Time (GMT). Probably local though. + */ + p += sprintf(p, + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n" + "rtc_epoch\t: %04lu\n" + "24hr\t\t: yes\n" + "Valid: %s\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch, + (XSTP==1)?"No":"Yes"); + + return p - buf; +} + +static int rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = rtc_get_status(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + diff -urN linux-2.6.16.18-old/drivers/i2c/i2c-core.c linux-2.6.16.18/drivers/i2c/i2c-core.c --- linux-2.6.16.18-old/drivers/i2c/i2c-core.c 2006-05-22 20:04:35.000000000 +0200 +++ linux-2.6.16.18/drivers/i2c/i2c-core.c 2006-06-02 23:21:21.000000000 +0200 @@ -307,6 +307,7 @@ list_for_each(item,&adapters) { adapter = list_entry(item, struct i2c_adapter, list); driver->attach_adapter(adapter); + goto out_unlock; } } diff -urN linux-2.6.16.18-old/drivers/mtd/maps/iop3xx.c linux-2.6.16.18/drivers/mtd/maps/iop3xx.c --- linux-2.6.16.18-old/drivers/mtd/maps/iop3xx.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.18/drivers/mtd/maps/iop3xx.c 2006-06-02 23:21:21.000000000 +0200 @@ -0,0 +1,146 @@ +/* + * $Id: iop3xx.c,v 1.17 2003/06/23 11:48:18 dwmw2 Exp $ + * + * Mapping for Intel XScale IOP3xx based platforms + * + * Author: Nicolas Pitre + * Copyright: (C) 2001-2003 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 09/03: Cleaned up to be generic to all IOP3xx systems - ds + * + * If you add a new machine type with a different WINDOW_SIZE or + * physmap addr, just wrap the init in if(machine_is_X()) { } + * and make sure your board header gets included in + * include/asm-arm/arch-iop3xx/hardware.h to pick up the definitions. + * + * DO NOT fill this file with #ifdef CONFIG_ARCH_XXXX crap. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct mtd_info *mymtd; + +static struct map_info iop3xx_map = { + .name = "IOP3xx Flash", +}; + +static struct mtd_partition iop3xx_partitions[6] = { + { + .name = "RedBoot", + .size = 0x00040000, + .offset = 0, + },{ + .name = "ramdisk", + .size = 0x00d00000, + .offset = 0x00040000, + },{ + .name = "kernel", + .size = 0x00160000, + .offset = 0x00d40000 + },{ + .name = "user", + .size = 0x00120000, + .offset = 0x00ea0000 + },{ + .name = "RedBoot config", + .size = 0x00020000, + .offset = 0x00fc0000, + // .mask_flags = MTD_WRITEABLE + },{ + .name = "FIS directory", + .size = 0x00020000, + .offset = 0x00fe0000 + } +}; + +static struct mtd_info *mymtd; +static struct mtd_partition *parsed_parts; +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; + +static int __init init_iop3xx(void) +{ + struct mtd_partition *parts; + int nb_parts = 0; + int parsed_nr_parts = 0; + int ret; + + if(machine_is_iq80321()) { + iop3xx_map.phys = IQ80321_FLASHBASE; + iop3xx_map.size = IQ80321_FLASHSIZE; + iop3xx_map.bankwidth = IQ80321_FLASHWIDTH; + } else if(machine_is_iq31244()) { + iop3xx_map.phys = IQ31244_FLASHBASE; + iop3xx_map.size = IQ31244_FLASHSIZE; + iop3xx_map.bankwidth = IQ31244_FLASHWIDTH; + } else if(machine_is_iq80331()) { + iop3xx_map.phys = IQ80331_FLASHBASE; + iop3xx_map.size = IQ80331_FLASHSIZE; + iop3xx_map.bankwidth = IQ80331_FLASHWIDTH; + } else { + printk("Unknown IOP3xx platform - flash access disabled\n"); + return -ENODEV; + } + + iop3xx_map.virt = + (unsigned long)ioremap(iop3xx_map.phys, iop3xx_map.size ); + if (!iop3xx_map.virt) { + printk("Failed to ioremap\n"); + return -EIO; + } + simple_map_init(&iop3xx_map); + + mymtd = do_map_probe("cfi_probe", &iop3xx_map); + if (!mymtd) { + iounmap((void *)iop3xx_map.virt); + return -ENXIO; + } + mymtd->owner = THIS_MODULE; + + ret = parse_mtd_partitions(mymtd, probes, &parsed_parts, 0); + ret=-1; + if (ret > 0) + parsed_nr_parts = ret; + if (parsed_nr_parts > 0) { + parts = parsed_parts; + nb_parts = parsed_nr_parts; + } else { + parts = iop3xx_partitions; + nb_parts = ARRAY_SIZE(iop3xx_partitions); + } + add_mtd_partitions(mymtd, parts, nb_parts); + return 0; +} + +static void __exit cleanup_iop3xx(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + if (parsed_parts) + kfree(parsed_parts); + } + if (iop3xx_map.virt) + iounmap((void *)iop3xx_map.virt); +} + +module_init(init_iop3xx); +module_exit(cleanup_iop3xx); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nicolas Pitre "); +MODULE_DESCRIPTION("MTD map driver for Intel XScale IOP3xx Platforms"); diff -urN linux-2.6.16.18-old/drivers/mtd/maps/Kconfig linux-2.6.16.18/drivers/mtd/maps/Kconfig --- linux-2.6.16.18-old/drivers/mtd/maps/Kconfig 2006-05-22 20:04:35.000000000 +0200 +++ linux-2.6.16.18/drivers/mtd/maps/Kconfig 2006-06-02 23:21:21.000000000 +0200 @@ -447,6 +447,13 @@ 21285 bridge used with Intel's StrongARM processors. More info at . +config MTD_IOP3XX + tristate "CFI Flash device mapped on the XScale IOP3XX board" + depends on ARM && MTD_CFI && ARCH_IOP3XX + help + This enables access routines for the flash chips on the Intel XScale + IOP3XX based evaluation board. If you have one of these boards and + would like to use the flash chips on it, say 'Y'. config MTD_IQ80310 tristate "CFI Flash device mapped on the XScale IQ80310 board" depends on MTD_CFI && ARCH_IQ80310 @@ -544,8 +551,8 @@ tristate "PCI MTD driver" depends on MTD && PCI && MTD_COMPLEX_MAPPINGS help - Mapping for accessing flash devices on add-in cards like the Intel XScale - IQ80310 card, and the Intel EBSA285 card in blank ROM programming mode + Mapping for accessing flash devices on add-in cards + and the Intel EBSA285 card in blank ROM programming mode (please see the manual for the link settings). If you are not sure, say N. diff -urN linux-2.6.16.18-old/drivers/mtd/maps/Makefile linux-2.6.16.18/drivers/mtd/maps/Makefile --- linux-2.6.16.18-old/drivers/mtd/maps/Makefile 2006-05-22 20:04:35.000000000 +0200 +++ linux-2.6.16.18/drivers/mtd/maps/Makefile 2006-06-02 23:21:21.000000000 +0200 @@ -15,7 +15,7 @@ obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o obj-$(CONFIG_MTD_DC21285) += dc21285.o obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o -obj-$(CONFIG_MTD_IQ80310) += iq80310.o +obj-$(CONFIG_MTD_IOP3XX) += iop3xx.o obj-$(CONFIG_MTD_L440GX) += l440gx.o obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o diff -urN linux-2.6.16.18-old/drivers/net/Kconfig linux-2.6.16.18/drivers/net/Kconfig --- linux-2.6.16.18-old/drivers/net/Kconfig 2006-05-22 20:04:35.000000000 +0200 +++ linux-2.6.16.18/drivers/net/Kconfig 2006-06-02 23:21:21.000000000 +0200 @@ -1970,6 +1970,16 @@ To compile this driver as a module, choose M here: the module will be called yellowfin. This is recommended. +config R1000 + tristate "Realtek gigabit ethernet support" + depends on PCI + select CRC32 + ---help--- + Say Y here if you have a Realtek PCI Gigabit Ethernet adapter. + + To compile this driver as a module, choose M here: the module + will be called r1000. + config R8169 tristate "Realtek 8169 gigabit ethernet support" depends on PCI diff -urN linux-2.6.16.18-old/drivers/net/Makefile linux-2.6.16.18/drivers/net/Makefile --- linux-2.6.16.18-old/drivers/net/Makefile 2006-05-22 20:04:35.000000000 +0200 +++ linux-2.6.16.18/drivers/net/Makefile 2006-06-02 23:21:21.000000000 +0200 @@ -189,6 +189,7 @@ obj-$(CONFIG_TUN) += tun.o obj-$(CONFIG_DL2K) += dl2k.o obj-$(CONFIG_R8169) += r8169.o +obj-$(CONFIG_R1000) += r1000.o obj-$(CONFIG_AMD8111_ETH) += amd8111e.o obj-$(CONFIG_IBMVETH) += ibmveth.o obj-$(CONFIG_S2IO) += s2io.o diff -urN linux-2.6.16.18-old/drivers/net/r1000.c linux-2.6.16.18/drivers/net/r1000.c --- linux-2.6.16.18-old/drivers/net/r1000.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.18/drivers/net/r1000.c 2006-06-02 23:29:15.000000000 +0200 @@ -0,0 +1,2071 @@ +//========================================================================= +//Realtek Ethernet driver for Linux kernel 2.4.x. and 2.6.x +//========================================================================= + + +#include +#include +#include +#include +#include +#include + +#include +#include + + +#define R1000_VERSION "1.02" +#define RELEASE_DATE "2006/02/23" +#define MODULENAME "r1000" +#define R1000_DRIVER_NAME MODULENAME R1000_VERSION ", the Linux device driver for Realtek Ethernet Controllers" +#define PFX MODULENAME ": " + + +#undef R1000_DEBUG +#define R1000_JUMBO_FRAME_SUPPORT +//#undef R1000_HW_FLOW_CONTROL_SUPPORT +#define R1000_HW_FLOW_CONTROL_SUPPORT + + +#undef R1000_IOCTL_SUPPORT +#undef R1000_DYNAMIC_CONTROL +#define R1000_USE_IO +//#undef R1000_USE_IO + + +#ifdef R1000_DEBUG + #define assert(expr) \ + if(!(expr)) { printk( "Assertion failed! %s,%s,%s,line=%d\n", #expr,__FILE__,__FUNCTION__,__LINE__); } + #define DBG_PRINT( fmt, args...) printk("r1000: " fmt, ## args); +#else + #define assert(expr) do {} while (0) + #define DBG_PRINT( fmt, args...) ; +#endif // end of #ifdef R1000_DEBUG + + +/* media options */ +#define MAX_UNITS 8 +static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; + +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 20; + +/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). + The RTL chips use a 64 element hash table based on the Ethernet CRC. */ +static int multicast_filter_limit = 32; + +/* MAC address length*/ +#define MAC_ADDR_LEN 6 + +#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */ +#define RX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */ +#define TX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */ +#define ETTh 0x3F /* 0x3F means NO threshold */ + +#define ETH_HDR_LEN 14 +#define DEFAULT_MTU 1500 +#define DEFAULT_RX_BUF_LEN 1536 + + +#ifdef R1000_JUMBO_FRAME_SUPPORT +#define MAX_JUMBO_FRAME_MTU ( 10000 ) +#define MAX_RX_SKBDATA_SIZE ( MAX_JUMBO_FRAME_MTU + ETH_HDR_LEN ) +#else +//#define MAX_RX_SKBDATA_SIZE 1600 +#define MAX_RX_SKBDATA_SIZE 1608 +#endif //end #ifdef R1000_JUMBO_FRAME_SUPPORT + + +#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ + +#define NUM_TX_DESC 1024 /* Number of Tx descriptor registers*/ +#define NUM_RX_DESC 1024 /* Number of Rx descriptor registers*/ + +#define RTL_MIN_IO_SIZE 0x80 +#define TX_TIMEOUT (6*HZ) +#define R1000_TIMER_EXPIRE_TIME 100 //100 + + +#ifdef R1000_USE_IO +#define RTL_W8(reg, val8) outb ((val8), ioaddr + (reg)) +#define RTL_W16(reg, val16) outw ((val16), ioaddr + (reg)) +#define RTL_W32(reg, val32) outl ((val32), ioaddr + (reg)) +#define RTL_R8(reg) inb (ioaddr + (reg)) +#define RTL_R16(reg) inw (ioaddr + (reg)) +#define RTL_R32(reg) ((unsigned long) inl (ioaddr + (reg))) +#else //R1000_USE_IO +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6) +/* write/read MMIO register for Linux kernel 2.4.x*/ +#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) +#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg)) +#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg)) +#define RTL_R8(reg) readb (ioaddr + (reg)) +#define RTL_R16(reg) readw (ioaddr + (reg)) +#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg))) +#else +/* write/read MMIO register for Linux kernel 2.6.x*/ +#define RTL_W8(reg, val8) iowrite8 ((val8), (void *)(ioaddr + (reg))) +#define RTL_W16(reg, val16) iowrite16 ((val16), (void *)(ioaddr + (reg))) +#define RTL_W32(reg, val32) iowrite32 ((val32), (void *)(ioaddr + (reg))) +#define RTL_R8(reg) ioread8 ((void *)(ioaddr + (reg))) +#define RTL_R16(reg) ioread16 ((void *)(ioaddr + (reg))) +#define RTL_R32(reg) ((unsigned long) ioread32 ((void *)(ioaddr + (reg)))) +#endif +#endif //R1000_USE_IO + +#define MCFG_METHOD_1 0x01 +#define MCFG_METHOD_2 0x02 +#define MCFG_METHOD_3 0x03 +#define MCFG_METHOD_4 0x04 +#define MCFG_METHOD_5 0x05 +#define MCFG_METHOD_11 0x0B +#define MCFG_METHOD_12 0x0C +#define MCFG_METHOD_13 0x0D +#define MCFG_METHOD_14 0x0E +#define MCFG_METHOD_15 0x0F + +#define PCFG_METHOD_1 0x01 //PHY Reg 0x03 bit0-3 == 0x0000 +#define PCFG_METHOD_2 0x02 //PHY Reg 0x03 bit0-3 == 0x0001 +#define PCFG_METHOD_3 0x03 //PHY Reg 0x03 bit0-3 == 0x0002 + + +#ifdef R1000_DYNAMIC_CONTROL +#include "r1000_callback.h" +#endif //R1000_DYNAMIC_CONTROL + + +const static struct { + const char *name; + u8 mcfg; /* depend on documents of Realtek */ + u32 RxConfigMask; /* should clear the bits supported by this chip */ +} rtl_chip_info[] = { + { "RTL8169", MCFG_METHOD_1, 0xff7e1880 }, + { "RTL8169S/8110S", MCFG_METHOD_2, 0xff7e1880 }, + { "RTL8169S/8110S", MCFG_METHOD_3, 0xff7e1880 }, + { "RTL8169SB/8110SB", MCFG_METHOD_4, 0xff7e1880 }, + { "RTL8169SC/8110SC", MCFG_METHOD_5, 0xff7e1880 }, + { "RTL8168B/8111B", MCFG_METHOD_11, 0xff7e1880 }, + { "RTL8168B/8111B", MCFG_METHOD_12, 0xff7e1880 }, + { "RTL8101E", MCFG_METHOD_13, 0xff7e1880 }, + { "RTL8100E", MCFG_METHOD_14, 0xff7e1880 }, + { "RTL8100E", MCFG_METHOD_15, 0xff7e1880 }, + { 0 } +}; + + +static struct pci_device_id r1000_pci_tbl[] __devinitdata = { + { 0x10ec, 0x8169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0x10ec, 0x8167, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0x10ec, 0x8168, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0x10ec, 0x8136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + {0,} +}; + + +MODULE_DEVICE_TABLE (pci, r1000_pci_tbl); + + +enum r1000_registers { + MAC0 = 0x0, + MAR0 = 0x8, + TxDescStartAddr = 0x20, + TxHDescStartAddr= 0x28, + FLASH = 0x30, + ERSR = 0x36, + ChipCmd = 0x37, + TxPoll = 0x38, + IntrMask = 0x3C, + IntrStatus = 0x3E, + TxConfig = 0x40, + RxConfig = 0x44, + RxMissed = 0x4C, + Cfg9346 = 0x50, + Config0 = 0x51, + Config1 = 0x52, + Config2 = 0x53, + Config3 = 0x54, + Config4 = 0x55, + Config5 = 0x56, + MultiIntr = 0x5C, + PHYAR = 0x60, + TBICSR = 0x64, + TBI_ANAR = 0x68, + TBI_LPAR = 0x6A, + PHYstatus = 0x6C, + Off7Ch = 0x7C, + RxMaxSize = 0xDA, + CPlusCmd = 0xE0, + RxDescStartAddr = 0xE4, + ETThReg = 0xEC, + FuncEvent = 0xF0, + FuncEventMask = 0xF4, + FuncPresetState = 0xF8, + FuncForceEvent = 0xFC, +}; + +enum r1000_register_content { + /*InterruptStatusBits*/ + SYSErr = 0x8000, + PCSTimeout = 0x4000, + SWInt = 0x0100, + TxDescUnavail = 0x80, + RxFIFOOver = 0x40, + LinkChg = 0x20, + RxOverflow = 0x10, + TxErr = 0x08, + TxOK = 0x04, + RxErr = 0x02, + RxOK = 0x01, + + /*RxStatusDesc*/ + RxRES = 0x00200000, + RxCRC = 0x00080000, + RxRUNT= 0x00100000, + RxRWT = 0x00400000, + + /*ChipCmdBits*/ + CmdReset = 0x10, + CmdRxEnb = 0x08, + CmdTxEnb = 0x04, + RxBufEmpty = 0x01, + + /*Cfg9346Bits*/ + Cfg9346_Lock = 0x00, + Cfg9346_Unlock = 0xC0, + + /*rx_mode_bits*/ + AcceptErr = 0x20, + AcceptRunt = 0x10, + AcceptBroadcast = 0x08, + AcceptMulticast = 0x04, + AcceptMyPhys = 0x02, + AcceptAllPhys = 0x01, + + /*RxConfigBits*/ + RxCfgFIFOShift = 13, + RxCfgDMAShift = 8, + + /*TxConfigBits*/ + TxInterFrameGapShift = 24, + TxDMAShift = 8, + + /*rtl8169_PHYstatus*/ + TBI_Enable = 0x80, + TxFlowCtrl = 0x40, + RxFlowCtrl = 0x20, + _1000Mbps = 0x10, + _100Mbps = 0x08, + _10Mbps = 0x04, + LinkStatus = 0x02, + FullDup = 0x01, + + /*GIGABIT_PHY_registers*/ + PHY_CTRL_REG = 0, + PHY_STAT_REG = 1, + PHY_AUTO_NEGO_REG = 4, + PHY_1000_CTRL_REG = 9, + + /*GIGABIT_PHY_REG_BIT*/ + PHY_Restart_Auto_Nego = 0x0200, + PHY_Enable_Auto_Nego = 0x1000, + + //PHY_STAT_REG = 1; + PHY_Auto_Neco_Comp = 0x0020, + + //PHY_AUTO_NEGO_REG = 4; + PHY_Cap_10_Half = 0x0020, + PHY_Cap_10_Full = 0x0040, + PHY_Cap_100_Half = 0x0080, + PHY_Cap_100_Full = 0x0100, + + //PHY_1000_CTRL_REG = 9; + PHY_Cap_1000_Full = 0x0200, + PHY_Cap_1000_Half = 0x0100, + + PHY_Cap_PAUSE = 0x0400, + PHY_Cap_ASYM_PAUSE = 0x0800, + + PHY_Cap_Null = 0x0, + + /*_MediaType*/ + _10_Half = 0x01, + _10_Full = 0x02, + _100_Half = 0x04, + _100_Full = 0x08, + _1000_Full = 0x10, + + /*_TBICSRBit*/ + TBILinkOK = 0x02000000, +}; + + + +enum _DescStatusBit { + OWNbit = 0x80000000, + EORbit = 0x40000000, + FSbit = 0x20000000, + LSbit = 0x10000000, +}; + + +struct TxDesc { + u32 status; + u32 vlan_tag; + u32 buf_addr; + u32 buf_Haddr; +}; + +struct RxDesc { + u32 status; + u32 vlan_tag; + u32 buf_addr; + u32 buf_Haddr; +}; + + +typedef struct timer_list rt_timer_t; + + +struct r1000_private { + unsigned long ioaddr; /* memory map physical address*/ + struct pci_dev *pci_dev; /* Index of PCI device */ + struct net_device_stats stats; /* statistics of net device */ + spinlock_t lock; /* spin lock flag */ + int chipset; + int mcfg; + int pcfg; + rt_timer_t r1000_timer; + unsigned long expire_time; + + unsigned long phy_link_down_cnt; + unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ + unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ + unsigned long dirty_tx; + struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */ + struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */ + struct sk_buff *Tx_skbuff[NUM_TX_DESC];/* Index of Transmit data buffer */ + struct sk_buff *Rx_skbuff[NUM_RX_DESC];/* Receive data buffer */ + unsigned char drvinit_fail; + + dma_addr_t txdesc_array_dma_addr[NUM_TX_DESC]; + dma_addr_t rxdesc_array_dma_addr[NUM_RX_DESC]; + dma_addr_t rx_skbuff_dma_addr[NUM_RX_DESC]; + + void *txdesc_space; + dma_addr_t txdesc_phy_dma_addr; + int sizeof_txdesc_space; + + void *rxdesc_space; + dma_addr_t rxdesc_phy_dma_addr; + int sizeof_rxdesc_space; + + int curr_mtu_size; + int tx_pkt_len; + int rx_pkt_len; + + int hw_rx_pkt_len; + +#ifdef R1000_DYNAMIC_CONTROL + struct r1000_cb_t rt; +#endif //end #ifdef R1000_DYNAMIC_CONTROL + + unsigned char linkstatus; +}; + + +MODULE_AUTHOR ("Realtek"); +MODULE_DESCRIPTION ("Linux device driver for Realtek Ethernet Controllers"); +MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_LICENSE("GPL"); + + +static int r1000_open (struct net_device *dev); +static int r1000_start_xmit (struct sk_buff *skb, struct net_device *dev); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +//typedef int irqreturn_t; +#define IRQ_NONE 0 +#define IRQ_HANDLED 1 +static void r1000_interrupt (int irq, void *dev_instance, struct pt_regs *regs); +#else +static irqreturn_t r1000_interrupt (int irq, void *dev_instance, struct pt_regs *regs); +#endif + +static void r1000_init_ring (struct net_device *dev); +static void r1000_hw_start (struct net_device *dev); +static int r1000_close (struct net_device *dev); +static inline u32 ether_crc (int length, unsigned char *data); +static void r1000_set_rx_mode (struct net_device *dev); +static void r1000_tx_timeout (struct net_device *dev); +static struct net_device_stats *r1000_get_stats(struct net_device *netdev); + +#ifdef R1000_JUMBO_FRAME_SUPPORT +static int r1000_change_mtu(struct net_device *dev, int new_mtu); +#endif //end #ifdef R1000_JUMBO_FRAME_SUPPORT + +static void r1000_hw_PHY_config (struct net_device *dev); +static void r1000_hw_PHY_reset(struct net_device *dev); +static const u16 r1000_intr_mask = LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK ; +static const unsigned int r1000_rx_config = (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift) | 0x0000000E; + + +#define R1000_WRITE_GMII_REG_BIT( ioaddr, reg, bitnum, bitval )\ +{ \ + int val; \ + if( bitval == 1 ){ val = ( R1000_READ_GMII_REG( ioaddr, reg ) | (bitval< 0 ; i -- ){ + // Check if the RTL8169 has completed writing to the specified MII register + if( ! (RTL_R32(PHYAR)&0x80000000) ){ + break; + } + else{ + udelay(100); + }// end of if( ! (RTL_R32(PHYAR)&0x80000000) ) + }// end of for() loop +} +//================================================================= +int R1000_READ_GMII_REG( unsigned long ioaddr, int RegAddr ) +{ + int i, value = -1; + + RTL_W32 ( PHYAR, 0x0 | (RegAddr&0xFF)<<16 ); + udelay(1000); + + for( i = 2000; i > 0 ; i -- ){ + // Check if the RTL8169 has completed retrieving data from the specified MII register + if( RTL_R32(PHYAR) & 0x80000000 ){ + value = (int)( RTL_R32(PHYAR)&0xFFFF ); + break; + } + else{ + udelay(100); + }// end of if( RTL_R32(PHYAR) & 0x80000000 ) + }// end of for() loop + return value; +} + + +#ifdef R1000_IOCTL_SUPPORT +#include "r1000_ioctl.c" +#endif //end #ifdef R1000_IOCTL_SUPPORT + + +#ifdef R1000_DYNAMIC_CONTROL +#include "r1000_callback.c" +#endif + + + +#define r1000_request_timer( timer, timer_expires, timer_func, timer_data ) \ +{ \ + init_timer(timer); \ + timer->expires = (unsigned long)(jiffies + timer_expires); \ + timer->data = (unsigned long)(timer_data); \ + timer->function = (void *)(timer_func); \ + add_timer(timer); \ + DBG_PRINT("request_timer at 0x%08lx\n", (unsigned long)timer); \ +} + +#define r1000_delete_timer( del_timer_t ) \ +{ \ + del_timer(del_timer_t); \ + DBG_PRINT("delete_timer at 0x%08lx\n", (unsigned long)del_timer_t); \ +} + +#define r1000_mod_timer( timer, timer_expires ) \ +{ \ + mod_timer( timer, jiffies + timer_expires ); \ +} + + + + +//====================================================================================================== +//====================================================================================================== +void r1000_phy_timer_t_handler( void *timer_data ) +{ + struct net_device *dev = (struct net_device *)timer_data; + struct r1000_private *priv = (struct r1000_private *) (dev->priv); + unsigned long ioaddr = priv->ioaddr; + + assert( priv->mcfg > MCFG_METHOD_1 ); + assert( priv->pcfg < PCFG_METHOD_3 ); + + if( RTL_R8(PHYstatus) & LinkStatus ){ + priv->phy_link_down_cnt = 0 ; + } + else{ + priv->phy_link_down_cnt ++ ; + if( priv->phy_link_down_cnt >= 12 ){ + // If link on 1000, perform phy reset. + if( R1000_READ_GMII_REG( ioaddr, PHY_1000_CTRL_REG ) & PHY_Cap_1000_Full ) + { + DBG_PRINT("r1000_hw_PHY_reset\n"); + r1000_hw_PHY_reset( dev ); + } + + priv->phy_link_down_cnt = 0 ; + } + } + + //--------------------------------------------------------------------------- + //mod_timer is a more efficient way to update the expire field of an active timer. + //--------------------------------------------------------------------------- +// r1000_mod_timer( (&priv->phy_timer_t), 100 ); +} + + + +//====================================================================================================== +//====================================================================================================== +void r1000_timer_handler( void *timer_data ) +{ + struct net_device *dev = (struct net_device *)timer_data; + struct r1000_private *priv = (struct r1000_private *) (dev->priv); + + if( (priv->mcfg > MCFG_METHOD_1) && (priv->pcfg < PCFG_METHOD_3) ){ + DBG_PRINT("FIX PCS -> r1000_phy_timer_t_handler\n"); + priv->phy_link_down_cnt = 0; + r1000_phy_timer_t_handler( timer_data ); + } + + +#ifdef R1000_DYNAMIC_CONTROL + { + struct r1000_cb_t *rt = &(priv->rt); + if( priv->linkstatus == _1000_Full ){ + r1000_callback(rt); + } + } +#endif //end #ifdef R1000_DYNAMIC_CONTROL + + + r1000_mod_timer( (&priv->r1000_timer), priv->expire_time ); +} + + + +//====================================================================================================== +//====================================================================================================== +static int __devinit r1000_init_board ( struct pci_dev *pdev, struct net_device **dev_out, unsigned long *ioaddr_out) +{ + unsigned long ioaddr = 0; + struct net_device *dev; + struct r1000_private *priv; + int rc, i; +#ifndef R1000_USE_IO + unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; +#endif + + assert (pdev != NULL); + assert (ioaddr_out != NULL); + + *ioaddr_out = 0; + *dev_out = NULL; + + // dev zeroed in init_etherdev +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) + dev = init_etherdev (NULL, sizeof (*priv)); +#else + dev = alloc_etherdev (sizeof (*priv)); +#endif + + if (dev == NULL) { + printk (KERN_ERR PFX "unable to alloc new ethernet\n"); + return -ENOMEM; + } + + SET_MODULE_OWNER(dev); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + SET_NETDEV_DEV(dev, &pdev->dev); +#endif + + priv = dev->priv; + + // enable device (incl. PCI PM wakeup and hotplug setup) + rc = pci_enable_device (pdev); + if (rc) + goto err_out; + +#ifndef R1000_USE_IO + mmio_start = pci_resource_start (pdev, 1); + mmio_end = pci_resource_end (pdev, 1); + mmio_flags = pci_resource_flags (pdev, 1); + mmio_len = pci_resource_len (pdev, 1); + + // make sure PCI base addr 1 is MMIO + if (!(mmio_flags & IORESOURCE_MEM)) { + printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n"); + rc = -ENODEV; + goto err_out; + } + + // check for weird/broken PCI region reporting + if ( mmio_len < RTL_MIN_IO_SIZE ) { + printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n"); + rc = -ENODEV; + goto err_out; + } +#endif + + rc = pci_request_regions (pdev, dev->name); + if (rc) + goto err_out; + + // enable PCI bus-mastering + pci_set_master (pdev); + +#ifdef R1000_USE_IO + ioaddr = pci_resource_start(pdev, 0); +#else + // ioremap MMIO region + ioaddr = (unsigned long)ioremap (mmio_start, mmio_len); + if (ioaddr == 0) { + printk (KERN_ERR PFX "cannot remap MMIO, aborting\n"); + rc = -EIO; + goto err_out_free_res; + } +#endif + + // Soft reset the chip. + RTL_W8 ( ChipCmd, CmdReset); + + // Check that the chip has finished the reset. + for (i = 1000; i > 0; i--){ + if ( (RTL_R8(ChipCmd) & CmdReset) == 0){ + break; + } + else{ + udelay (10); + } + } + + // identify config method + { + unsigned long val32 = (RTL_R32(TxConfig)&0x7c800000); + + if( val32 == 0x38800000) + priv->mcfg = MCFG_METHOD_15; + else if( val32 == 0x30800000) + priv->mcfg = MCFG_METHOD_14; + else if( val32 == 0x34000000) + priv->mcfg = MCFG_METHOD_13; + else if( val32 == 0x38000000) + priv->mcfg = MCFG_METHOD_12; + else if( val32 == 0x30000000) + priv->mcfg = MCFG_METHOD_11; + else if( val32 == 0x18000000) + priv->mcfg = MCFG_METHOD_5; + else if( val32 == 0x10000000 ) + priv->mcfg = MCFG_METHOD_4; + else if( val32 == 0x04000000 ) + priv->mcfg = MCFG_METHOD_3; + else if( val32 == 0x00800000 ) + priv->mcfg = MCFG_METHOD_2; + else if( val32 == 0x00000000 ) + priv->mcfg = MCFG_METHOD_1; + else + priv->mcfg = MCFG_METHOD_1; + } + { + unsigned char val8 = (unsigned char)(R1000_READ_GMII_REG(ioaddr,3)&0x000f); + if( val8 == 0x00 ){ + priv->pcfg = PCFG_METHOD_1; + } + else if( val8 == 0x01 ){ + priv->pcfg = PCFG_METHOD_2; + } + else if( val8 == 0x02 ){ + priv->pcfg = PCFG_METHOD_3; + } + else{ + priv->pcfg = PCFG_METHOD_3; + } + } + + + for (i = ARRAY_SIZE (rtl_chip_info) - 1; i >= 0; i--){ + if (priv->mcfg == rtl_chip_info[i].mcfg) { + priv->chipset = i; + goto match; + } + } + + //if unknown chip, assume array element #0, original RTL-8169 in this case +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) + printk (KERN_DEBUG PFX "PCI device %s: unknown chip version, assuming RTL-8169\n", pdev->slot_name); +#endif + priv->chipset = 0; + +match: + *ioaddr_out = ioaddr; + *dev_out = dev; + return 0; + +#ifndef R1000_USE_IO +err_out_free_res: + pci_release_regions (pdev); +#endif + +err_out: + unregister_netdev (dev); + kfree (dev); + return rc; +} + + + + + + + +//====================================================================================================== +static int __devinit r1000_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct net_device *dev = NULL; + struct r1000_private *priv = NULL; + unsigned long ioaddr = 0; + static int board_idx = -1; + int i; + int option = -1, Cap10_100 = 0, Cap1000 = 0; + int val=0; + + + assert (pdev != NULL); + assert (ent != NULL); + + board_idx++; + + + i = r1000_init_board (pdev, &dev, &ioaddr); + if (i < 0) { + return i; + } + + priv = dev->priv; + + assert (ioaddr != NULL); + assert (dev != NULL); + assert (priv != NULL); + + // Get MAC address // + for (i = 0; i < MAC_ADDR_LEN ; i++){ + dev->dev_addr[i] = RTL_R8( MAC0 + i ); + } + + dev->open = r1000_open; + dev->hard_start_xmit = r1000_start_xmit; + dev->get_stats = r1000_get_stats; + dev->stop = r1000_close; + dev->tx_timeout = r1000_tx_timeout; + dev->set_multicast_list = r1000_set_rx_mode; + dev->watchdog_timeo = TX_TIMEOUT; + dev->irq = pdev->irq; + dev->base_addr = (unsigned long) ioaddr; + +#ifdef R1000_JUMBO_FRAME_SUPPORT + dev->change_mtu = r1000_change_mtu; +#endif //end #ifdef R1000_JUMBO_FRAME_SUPPORT + +#ifdef R1000_IOCTL_SUPPORT + dev->do_ioctl = r1000_ioctl; +#endif //end #ifdef R1000_IOCTL_SUPPORT + +#ifdef R1000_DYNAMIC_CONTROL + priv->rt.dev = dev; +#endif //end #ifdef R1000_DYNAMIC_CONTROL + + priv = dev->priv; // private data // + priv->pci_dev = pdev; + priv->ioaddr = ioaddr; + +//#ifdef R1000_JUMBO_FRAME_SUPPORT + priv->curr_mtu_size = dev->mtu; + priv->tx_pkt_len = dev->mtu + ETH_HDR_LEN; + priv->rx_pkt_len = dev->mtu + ETH_HDR_LEN; + priv->hw_rx_pkt_len = priv->rx_pkt_len + 8; +//#endif //end #ifdef R1000_JUMBO_FRAME_SUPPORT + + DBG_PRINT("-------------------------- \n"); + DBG_PRINT("dev->mtu = %d \n", dev->mtu); + DBG_PRINT("priv->curr_mtu_size = %d \n", priv->curr_mtu_size); + DBG_PRINT("priv->tx_pkt_len = %d \n", priv->tx_pkt_len); + DBG_PRINT("priv->rx_pkt_len = %d \n", priv->rx_pkt_len); + DBG_PRINT("priv->hw_rx_pkt_len = %d \n", priv->hw_rx_pkt_len); + DBG_PRINT("-------------------------- \n"); + + spin_lock_init (&priv->lock); + + register_netdev (dev); + + pci_set_drvdata(pdev, dev); // pdev->driver_data = data; + + + printk (KERN_DEBUG "%s: Identified chip type is '%s'.\n",dev->name,rtl_chip_info[priv->chipset].name); + printk (KERN_INFO "%s: %s at 0x%lx, " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " + "IRQ %d\n", + dev->name, + R1000_DRIVER_NAME, + dev->base_addr, + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5], + dev->irq); + + + // Config PHY + r1000_hw_PHY_config(dev); + + DBG_PRINT("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); + RTL_W8( 0x82, 0x01 ); + + if( priv->mcfg < MCFG_METHOD_3 ){ + DBG_PRINT("Set PCI Latency=0x40\n"); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40); + } + + if( priv->mcfg == MCFG_METHOD_2 ){ + DBG_PRINT("Set MAC Reg C+CR Offset 0x82h = 0x01h\n"); + RTL_W8( 0x82, 0x01 ); + DBG_PRINT("Set PHY Reg 0x0bh = 0x00h\n"); + R1000_WRITE_GMII_REG( ioaddr, 0x0b, 0x0000 ); //w 0x0b 15 0 0 + } + + // if TBI is not endbled + if( !(RTL_R8(PHYstatus) & TBI_Enable) ){ + val = R1000_READ_GMII_REG( ioaddr, PHY_AUTO_NEGO_REG ); + +#ifdef R1000_HW_FLOW_CONTROL_SUPPORT + val |= PHY_Cap_PAUSE | PHY_Cap_ASYM_PAUSE ; +#endif //end #define R1000_HW_FLOW_CONTROL_SUPPORT + + option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx]; + // Force Realtek Ethernet Controller in 10/100/1000Mpbs Full/Half-duplex mode. + if( option > 0 ){ + printk(KERN_INFO "%s: Force-mode Enabled. \n", dev->name); + Cap10_100 = 0; + Cap1000 = 0; + switch( option ){ + case _10_Half: + Cap10_100 = PHY_Cap_10_Half; + Cap1000 = PHY_Cap_Null; + break; + case _10_Full: + Cap10_100 = PHY_Cap_10_Full | PHY_Cap_10_Half; + Cap1000 = PHY_Cap_Null; + break; + case _100_Half: + if(priv->mcfg!=MCFG_METHOD_13) + Cap10_100 = PHY_Cap_100_Half | PHY_Cap_10_Full | PHY_Cap_10_Half; + else + Cap10_100 = 0x0081; + Cap1000 = PHY_Cap_Null; + break; + case _100_Full: + Cap10_100 = PHY_Cap_100_Full | PHY_Cap_100_Half | PHY_Cap_10_Full | PHY_Cap_10_Half; + Cap1000 = PHY_Cap_Null; + break; + case _1000_Full: + Cap10_100 = PHY_Cap_100_Full | PHY_Cap_100_Half | PHY_Cap_10_Full | PHY_Cap_10_Half; + if((priv->mcfg!=MCFG_METHOD_13)&&(priv->mcfg!=MCFG_METHOD_14)&&(priv->mcfg!=MCFG_METHOD_15)) + printk("This Realtek NIC doesn't support 1000Mbps\n"); + else + Cap1000 = PHY_Cap_1000_Full|PHY_Cap_1000_Half; + break; + default: + break; + } + //flow control enable + R1000_WRITE_GMII_REG( ioaddr, PHY_AUTO_NEGO_REG, Cap10_100 | ( val&0xC1F ) ); //leave PHY_AUTO_NEGO_REG bit4:0 unchanged + R1000_WRITE_GMII_REG( ioaddr, PHY_1000_CTRL_REG, Cap1000 ); + } + else{ + printk(KERN_INFO "%s: Auto-negotiation Enabled.\n", dev->name); + + // enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged + R1000_WRITE_GMII_REG( ioaddr, PHY_AUTO_NEGO_REG, + PHY_Cap_10_Half | PHY_Cap_10_Full | PHY_Cap_100_Half | PHY_Cap_100_Full | ( val&0xC1F ) ); + + // enable 1000 Full Mode + if((priv->mcfg!=MCFG_METHOD_13)&&(priv->mcfg!=MCFG_METHOD_14)&&(priv->mcfg!=MCFG_METHOD_15)) + R1000_WRITE_GMII_REG( ioaddr, PHY_1000_CTRL_REG, PHY_Cap_1000_Full | PHY_Cap_1000_Half); + }// end of if( option > 0 ) + + // Enable auto-negotiation and restart auto-nigotiation + R1000_WRITE_GMII_REG( ioaddr, PHY_CTRL_REG, PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego ); + udelay(100); + + // wait for auto-negotiation process + for( i = 7000; i > 0; i-- ){ + //check if auto-negotiation complete + if( R1000_READ_GMII_REG(ioaddr, PHY_STAT_REG) & PHY_Auto_Neco_Comp ){ + udelay(100); + option = RTL_R8(PHYstatus); + if( option & _1000Mbps ){ + printk(KERN_INFO "%s: 1000Mbps Full-duplex operation.\n", dev->name); + } + else{ + printk(KERN_INFO "%s: %sMbps %s-duplex operation.\n", dev->name, + (option & _100Mbps) ? "100" : "10", (option & FullDup) ? "Full" : "Half" ); + } + break; + } + else{ + udelay(100); + }// end of if( R1000_READ_GMII_REG(ioaddr, 1) & 0x20 ) + }// end for-loop to wait for auto-negotiation process + + option = RTL_R8(PHYstatus); + if( option & _1000Mbps ){ + priv->linkstatus = _1000_Full; + } + else{ + if(option & _100Mbps){ + priv->linkstatus = (option & FullDup) ? _100_Full : _100_Half; + } + else{ + priv->linkstatus = (option & FullDup) ? _10_Full : _10_Half; + } + } + DBG_PRINT("priv->linkstatus = 0x%02x\n", priv->linkstatus); + + }// end of TBI is not enabled + else{ + udelay(100); + DBG_PRINT("1000Mbps Full-duplex operation, TBI Link %s!\n",(RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed" ); + + }// end of TBI is not enabled + + //show some information after the driver is inserted + if(( priv->mcfg == MCFG_METHOD_11 )||( priv->mcfg == MCFG_METHOD_12 )) + printk("Realtek RTL8168/8111 Family PCI-E Gigabit Ethernet Network Adapter\n"); + else if((priv->mcfg==MCFG_METHOD_13)||(priv->mcfg==MCFG_METHOD_14)||(priv->mcfg==MCFG_METHOD_15)) + printk("Realtek RTL8139/810x Family Fast Ethernet Network Adapter\n"); + else + printk("Realtek RTL8169/8110 Family Gigabit Ethernet Network Adapter\n"); + + printk("Driver version:%s\n",R1000_VERSION); + printk("Released date:%s\n",RELEASE_DATE); + if(RTL_R8(PHYstatus) & LinkStatus){ + printk("Link Status:%s\n","Linked"); + + if(RTL_R8(PHYstatus) & _1000Mbps) + printk("Link Speed:1000Mbps\n"); + else if(RTL_R8(PHYstatus) & _100Mbps) + printk("Link Speed:100Mbps\n"); + else if(RTL_R8(PHYstatus) & _10Mbps) + printk("Link Speed:10Mbps\n"); + + printk("Duplex mode:%s\n",RTL_R8(PHYstatus)&FullDup?"Full-Duplex":"Half-Duplex"); + }else{ + printk("Link Status:%s\n","Not Linked"); + } +#ifdef R1000_USE_IO + printk("I/O Base:0x%X(I/O port)\n",(unsigned int)(priv->ioaddr)); +#else + printk("I/O Base:0x%X(I/O memory)\n",(unsigned int)(priv->ioaddr)); +#endif //R1000_USE_IO + printk("IRQ:%d\n",dev->irq); + + return 0; +} + + + + + + + +//====================================================================================================== +static void __devexit r1000_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + assert (dev != NULL); + assert (priv != NULL); + + unregister_netdev (dev); + +#ifdef R1000_USE_IO +#else + iounmap ((void *)(dev->base_addr)); +#endif + pci_release_regions (pdev); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + kfree (dev); +#else + free_netdev(dev); +#endif + + pci_set_drvdata (pdev, NULL); +} + + + + + + + +//====================================================================================================== +static int r1000_open (struct net_device *dev) +{ + struct r1000_private *priv = dev->priv; + struct pci_dev *pdev = priv->pci_dev; + int retval; +// u8 diff; +// u32 TxPhyAddr, RxPhyAddr; + + + if( priv->drvinit_fail == 1 ){ + printk("%s: Gigabit driver open failed.\n", dev->name ); + return -ENOMEM; + } + + retval = request_irq (dev->irq, r1000_interrupt, SA_SHIRQ, dev->name, dev); + if (retval) { + return retval; + } + + //2004-05-11 + // Allocate tx/rx descriptor space + priv->sizeof_txdesc_space = NUM_TX_DESC * sizeof(struct TxDesc)+256; + priv->txdesc_space = pci_alloc_consistent( pdev, priv->sizeof_txdesc_space, &priv->txdesc_phy_dma_addr ); + if( priv->txdesc_space == NULL ){ + printk("%s: Gigabit driver alloc txdesc_space failed.\n", dev->name ); + return -ENOMEM; + } + priv->sizeof_rxdesc_space = NUM_RX_DESC * sizeof(struct RxDesc)+256; + priv->rxdesc_space = pci_alloc_consistent( pdev, priv->sizeof_rxdesc_space, &priv->rxdesc_phy_dma_addr ); + if( priv->rxdesc_space == NULL ){ + printk("%s: Gigabit driver alloc rxdesc_space failed.\n", dev->name ); + return -ENOMEM; + } + + if(priv->txdesc_phy_dma_addr & 0xff){ + printk("%s: Gigabit driver txdesc_phy_dma_addr is not 256-bytes-aligned.\n", dev->name ); + } + if(priv->rxdesc_phy_dma_addr & 0xff){ + printk("%s: Gigabit driver rxdesc_phy_dma_addr is not 256-bytes-aligned.\n", dev->name ); + } + // Set tx/rx descriptor space + priv->TxDescArray = (struct TxDesc *)priv->txdesc_space; + priv->RxDescArray = (struct RxDesc *)priv->rxdesc_space; + + { + int i; + struct sk_buff *skb = NULL; + + for(i=0;iRx_skbuff[i] = skb; + } + else{ + printk("%s: Gigabit driver failed to allocate skbuff.\n", dev->name); + priv->drvinit_fail = 1; + } + } + } + + + ////////////////////////////////////////////////////////////////////////////// + r1000_init_ring (dev); + r1000_hw_start (dev); + + + // ------------------------------------------------------ + DBG_PRINT("FIX PCS -> r1000_request_timer\n"); + priv->expire_time = R1000_TIMER_EXPIRE_TIME; + r1000_request_timer( (&priv->r1000_timer), priv->expire_time, r1000_timer_handler, ((void *)dev) ); //in open() + + + DBG_PRINT("%s: %s() alloc_rxskb_cnt = %d\n", dev->name, __FUNCTION__, alloc_rxskb_cnt ); + + return 0; + +}//end of r1000_open (struct net_device *dev) + + + + + + + + +//====================================================================================================== +static void r1000_hw_PHY_reset(struct net_device *dev) +{ + int val, phy_reset_expiretime = 50; + struct r1000_private *priv = dev->priv; + unsigned long ioaddr = priv->ioaddr; + + DBG_PRINT("%s: Reset RTL8169s PHY\n", dev->name); + + val = ( R1000_READ_GMII_REG( ioaddr, 0 ) | 0x8000 ) & 0xffff; + R1000_WRITE_GMII_REG( ioaddr, 0, val ); + + do //waiting for phy reset + { + if( R1000_READ_GMII_REG( ioaddr, 0 ) & 0x8000 ){ + phy_reset_expiretime --; + udelay(100); + } + else{ + break; + } + }while( phy_reset_expiretime >= 0 ); + + assert( phy_reset_expiretime > 0 ); +} + + + + +//====================================================================================================== +static void r1000_hw_PHY_config (struct net_device *dev) +{ + struct r1000_private *priv = dev->priv; + void *ioaddr = (void*)priv->ioaddr; + + DBG_PRINT("priv->mcfg=%d, priv->pcfg=%d\n",priv->mcfg,priv->pcfg); + + if( priv->mcfg == MCFG_METHOD_4 ){ +/* + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x1F, 0x0001 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x1b, 0x841e ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x0e, 0x7bfb ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x09, 0x273a ); +*/ + + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x1F, 0x0002 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x01, 0x90D0 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x1F, 0x0000 ); + }else if((priv->mcfg == MCFG_METHOD_2)||(priv->mcfg == MCFG_METHOD_3)){ + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x1F, 0x0001 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x15, 0x1000 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x18, 0x65C7 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0x0000 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x03, 0x00A1 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x02, 0x0008 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x01, 0x1020 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x00, 0x1000 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0x0800 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0x0000 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0x7000 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x03, 0xFF41 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x02, 0xDE60 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x01, 0x0140 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x00, 0x0077 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0x7800 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0x7000 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0xA000 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x03, 0xDF01 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x02, 0xDF20 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x01, 0xFF95 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x00, 0xFA00 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0xA800 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0xA000 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0xB000 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x03, 0xFF41 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x02, 0xDE20 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x01, 0x0140 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x00, 0x00BB ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0xB800 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0xB000 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0xF000 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x03, 0xDF01 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x02, 0xDF20 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x01, 0xFF95 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x00, 0xBF00 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0xF800 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0xF000 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x04, 0x0000 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x1F, 0x0000 ); + R1000_WRITE_GMII_REG( (unsigned long)ioaddr, 0x0B, 0x0000 ); + } + else{ + DBG_PRINT("priv->mcfg=%d. Discard hw PHY config.\n",priv->mcfg); + } +} + + + + + + + + + + +//====================================================================================================== +static void r1000_hw_start (struct net_device *dev) +{ + struct r1000_private *priv = dev->priv; + struct pci_dev *pdev = priv->pci_dev; + unsigned long ioaddr = priv->ioaddr; + u32 i; + u8 i8; + u16 i16; + + if((priv->mcfg!=MCFG_METHOD_5)&&(priv->mcfg!=MCFG_METHOD_11)&& + (priv->mcfg!=MCFG_METHOD_12)&&(priv->mcfg!=MCFG_METHOD_13)&& + (priv->mcfg!=MCFG_METHOD_14)&&(priv->mcfg!=MCFG_METHOD_15)){ + /* Soft reset the chip. */ + RTL_W8 ( ChipCmd, CmdReset); + + /* Check that the chip has finished the reset. */ + for (i = 1000; i > 0; i--){ + if ((RTL_R8( ChipCmd ) & CmdReset) == 0) break; + else udelay (10); + } + + RTL_W8 ( Cfg9346, Cfg9346_Unlock); + RTL_W8 ( ChipCmd, CmdTxEnb | CmdRxEnb); + RTL_W8 ( ETThReg, ETTh); + + // For gigabit rtl8169 + RTL_W16 ( RxMaxSize, (unsigned short)priv->hw_rx_pkt_len ); + + // Set Rx Config register + i = r1000_rx_config | ( RTL_R32( RxConfig ) & rtl_chip_info[priv->chipset].RxConfigMask); + RTL_W32 ( RxConfig, i); + + + /* Set DMA burst size and Interframe Gap Time */ + RTL_W32 ( TxConfig, (TX_DMA_BURST << TxDMAShift) | (InterFrameGap << TxInterFrameGapShift) ); + + + + RTL_W16( CPlusCmd, RTL_R16(CPlusCmd) ); + + if(priv->mcfg==MCFG_METHOD_2||priv->mcfg==MCFG_METHOD_3){ + RTL_W16( CPlusCmd, (RTL_R16(CPlusCmd)|(1<<14)|(1<<3)) ); + DBG_PRINT("Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14\n"); + }else{ + RTL_W16( CPlusCmd, (RTL_R16(CPlusCmd)|(1<<3)) ); + DBG_PRINT("Set MAC Reg C+CR Offset 0xE0: bit-3.\n"); + } + + { + RTL_W16(0xE2,0x0000); + } + + priv->cur_rx = 0; + + RTL_W32 ( TxDescStartAddr, priv->txdesc_phy_dma_addr); + RTL_W32 ( TxDescStartAddr + 4, 0x00); + RTL_W32 ( RxDescStartAddr, priv->rxdesc_phy_dma_addr); + RTL_W32 ( RxDescStartAddr + 4, 0x00); + + RTL_W8 ( Cfg9346, Cfg9346_Lock ); + udelay (10); + + RTL_W32 ( RxMissed, 0 ); + + r1000_set_rx_mode (dev); + + RTL_W16 ( MultiIntr, RTL_R16(MultiIntr) & 0xF000); + + RTL_W16 ( IntrMask, r1000_intr_mask); + }else{ + /* Soft reset the chip. */ + RTL_W8 ( ChipCmd, CmdReset); + + /* Check that the chip has finished the reset. */ + for (i = 1000; i > 0; i--){ + if ((RTL_R8( ChipCmd ) & CmdReset) == 0) break; + else udelay (10); + } + + if( priv->mcfg == MCFG_METHOD_13 ){ + pci_write_config_word(pdev,0x68,0x00); + pci_write_config_word(pdev,0x69,0x08); + } + + if( priv->mcfg == MCFG_METHOD_5 ){ + i8=RTL_R8(Config2); + i8=i8&0x07; + if(i8&&0x01) + RTL_W32(Off7Ch,0x0007FFFF); + + i=0x0007FF00; + RTL_W32(Off7Ch, i); + + pci_read_config_word(pdev,0x04,&i16); + i16=i16&0xEF; + pci_write_config_word(pdev,0x04,i16); + } + + RTL_W8 ( Cfg9346, Cfg9346_Unlock); + RTL_W8 ( ETThReg, ETTh); + + // For gigabit rtl8169 + RTL_W16 ( RxMaxSize, (unsigned short)priv->hw_rx_pkt_len ); + + RTL_W16( CPlusCmd, RTL_R16(CPlusCmd) ); + + if(priv->mcfg==MCFG_METHOD_2||priv->mcfg==MCFG_METHOD_3){ + RTL_W16( CPlusCmd, (RTL_R16(CPlusCmd)|(1<<14)|(1<<3)) ); + DBG_PRINT("Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14\n"); + }else{ + RTL_W16( CPlusCmd, (RTL_R16(CPlusCmd)|(1<<3)) ); + DBG_PRINT("Set MAC Reg C+CR Offset 0xE0: bit-3.\n"); + } + + { + RTL_W16(0xE2,0x0000); + } + + priv->cur_rx = 0; + + RTL_W32 ( TxDescStartAddr, priv->txdesc_phy_dma_addr); + RTL_W32 ( TxDescStartAddr + 4, 0x00); + RTL_W32 ( RxDescStartAddr, priv->rxdesc_phy_dma_addr); + RTL_W32 ( RxDescStartAddr + 4, 0x00); + RTL_W8 ( ChipCmd, CmdTxEnb | CmdRxEnb); + // Set Rx Config register + i = r1000_rx_config | ( RTL_R32( RxConfig ) & rtl_chip_info[priv->chipset].RxConfigMask); + RTL_W32 ( RxConfig, i); + + /* Set DMA burst size and Interframe Gap Time */ + RTL_W32 ( TxConfig, (TX_DMA_BURST << TxDMAShift) | (InterFrameGap << TxInterFrameGapShift) ); + + RTL_W8 ( Cfg9346, Cfg9346_Lock ); + udelay (10); + + RTL_W32 ( RxMissed, 0 ); + + r1000_set_rx_mode (dev); + + RTL_W16 ( MultiIntr, RTL_R16(MultiIntr) & 0xF000); + + RTL_W16 ( IntrMask, r1000_intr_mask); + } + + netif_start_queue (dev); + +}//end of r1000_hw_start (struct net_device *dev) + + + + + + + +//====================================================================================================== +static void r1000_init_ring (struct net_device *dev) +{ + struct r1000_private *priv = dev->priv; + struct pci_dev *pdev = priv->pci_dev; + int i; + struct sk_buff *skb; + + + priv->cur_rx = 0; + priv->cur_tx = 0; + priv->dirty_tx = 0; + memset(priv->TxDescArray, 0x0, NUM_TX_DESC*sizeof(struct TxDesc)); + memset(priv->RxDescArray, 0x0, NUM_RX_DESC*sizeof(struct RxDesc)); + + + for (i=0 ; iTx_skbuff[i]=NULL; + priv->txdesc_array_dma_addr[i] = pci_map_single(pdev, &priv->TxDescArray[i], sizeof(struct TxDesc), PCI_DMA_TODEVICE); + } + + for (i=0; i RxDescArray[i].status = cpu_to_le32((OWNbit | EORbit) | (unsigned long)priv->hw_rx_pkt_len); + } + else{ + priv->RxDescArray[i].status = cpu_to_le32(OWNbit | (unsigned long)priv->hw_rx_pkt_len); + } + + {//----------------------------------------------------------------------- + skb = priv->Rx_skbuff[i]; + priv->rx_skbuff_dma_addr[i] = pci_map_single(pdev, skb->data, MAX_RX_SKBDATA_SIZE, PCI_DMA_FROMDEVICE); + + if( skb != NULL ){ + priv->RxDescArray[i].buf_addr = cpu_to_le32(priv->rx_skbuff_dma_addr[i]); + priv->RxDescArray[i].buf_Haddr = 0; + } + else{ + DBG_PRINT("%s: %s() Rx_skbuff == NULL\n", dev->name, __FUNCTION__); + priv->drvinit_fail = 1; + } + }//----------------------------------------------------------------------- + priv->rxdesc_array_dma_addr[i] = pci_map_single(pdev, &priv->RxDescArray[i], sizeof(struct RxDesc), PCI_DMA_TODEVICE); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) + pci_dma_sync_single(pdev, priv->rxdesc_array_dma_addr[i], sizeof(struct RxDesc), PCI_DMA_TODEVICE); +#endif + } +} + + + + + + + +//====================================================================================================== +static void r1000_tx_clear (struct r1000_private *priv) +{ + int i; + + priv->cur_tx = 0; + for ( i = 0 ; i < NUM_TX_DESC ; i++ ){ + if ( priv->Tx_skbuff[i] != NULL ) { + dev_kfree_skb ( priv->Tx_skbuff[i] ); + priv->Tx_skbuff[i] = NULL; + priv->stats.tx_dropped++; + } + } +} + + + + + + + +//====================================================================================================== +static void r1000_tx_timeout (struct net_device *dev) +{ + struct r1000_private *priv = dev->priv; + unsigned long ioaddr = priv->ioaddr; + u8 tmp8; + + /* disable Tx, if not already */ + tmp8 = RTL_R8( ChipCmd ); + if (tmp8 & CmdTxEnb){ + RTL_W8 ( ChipCmd, tmp8 & ~CmdTxEnb); + } + + /* Disable interrupts by clearing the interrupt mask. */ + RTL_W16 ( IntrMask, 0x0000); + + /* Stop a shared interrupt from scavenging while we are. */ + spin_lock_irq (&priv->lock); + r1000_tx_clear (priv); + spin_unlock_irq (&priv->lock); + + + r1000_hw_start (dev); + + netif_wake_queue (dev); +} + + + + + + + +//====================================================================================================== +static int r1000_start_xmit (struct sk_buff *skb, struct net_device *dev) +{ + struct r1000_private *priv = dev->priv; + unsigned long ioaddr = priv->ioaddr; + struct pci_dev *pdev = priv->pci_dev; + int entry = priv->cur_tx % NUM_TX_DESC; + int buf_len = 60; + dma_addr_t txbuf_dma_addr; + + spin_lock_irq (&priv->lock); + if( (le32_to_cpu(priv->TxDescArray[entry].status) & OWNbit)==0 ){ + + priv->Tx_skbuff[entry] = skb; + txbuf_dma_addr = pci_map_single(pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + + priv->TxDescArray[entry].buf_addr = cpu_to_le32(txbuf_dma_addr); + DBG_PRINT("%s: TX pkt_size = %d\n", __FUNCTION__, skb->len); + if( skb->len <= priv->tx_pkt_len ){ + buf_len = skb->len; + } + else{ + printk("%s: Error -- Tx packet size(%d) > mtu(%d)+14\n", dev->name, skb->len, dev->mtu); + buf_len = priv->tx_pkt_len; + } + + if( entry != (NUM_TX_DESC-1) ){ + priv->TxDescArray[entry].status = cpu_to_le32((OWNbit | FSbit | LSbit) | buf_len); + } + else{ + priv->TxDescArray[entry].status = cpu_to_le32((OWNbit | EORbit | FSbit | LSbit) | buf_len); + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) + pci_dma_sync_single(pdev, priv->txdesc_array_dma_addr[entry], sizeof(struct TxDesc), PCI_DMA_TODEVICE); +#endif + + RTL_W8 ( TxPoll, 0x40); //set polling bit + + dev->trans_start = jiffies; + + priv->stats.tx_bytes += ( (skb->len > ETH_ZLEN) ? skb->len : ETH_ZLEN); + priv->cur_tx++; + }//end of if( (priv->TxDescArray[entry].status & 0x80000000)==0 ) + + spin_unlock_irq (&priv->lock); + + if ( (priv->cur_tx - NUM_TX_DESC) == priv->dirty_tx ){ + netif_stop_queue (dev); + } + else{ + if (netif_queue_stopped (dev)){ + netif_wake_queue (dev); + } + } + + return 0; +} + + + + + + + +//====================================================================================================== +static void r1000_tx_interrupt (struct net_device *dev, struct r1000_private *priv, unsigned long ioaddr) +{ + unsigned long dirty_tx, tx_left=0; + int entry = priv->cur_tx % NUM_TX_DESC; + int txloop_cnt = 0; + + assert (dev != NULL); + assert (priv != NULL); + assert (ioaddr != NULL); + + + dirty_tx = priv->dirty_tx; + tx_left = priv->cur_tx - dirty_tx; + + while( (tx_left > 0) && (txloop_cnt < max_interrupt_work) ){ + if( (le32_to_cpu(priv->TxDescArray[entry].status) & OWNbit) == 0 ){ + +#ifdef R1000_DYNAMIC_CONTROL + r1000_callback_tx(&(priv->rt), 1, priv->Tx_skbuff[dirty_tx % NUM_TX_DESC]->len); +#endif //end #ifdef R1000_DYNAMIC_CONTROL + + dev_kfree_skb_irq( priv->Tx_skbuff[dirty_tx % NUM_TX_DESC] ); + priv->Tx_skbuff[dirty_tx % NUM_TX_DESC] = NULL; + priv->stats.tx_packets++; + dirty_tx++; + tx_left--; + entry++; + } + txloop_cnt ++; + } + + if (priv->dirty_tx != dirty_tx) { + priv->dirty_tx = dirty_tx; + if (netif_queue_stopped (dev)) + netif_wake_queue (dev); + } +} + + + + + + +//====================================================================================================== +static void r1000_rx_interrupt (struct net_device *dev, struct r1000_private *priv, unsigned long ioaddr) +{ + struct pci_dev *pdev = priv->pci_dev; + int cur_rx; + int pkt_size = 0 ; + int rxdesc_cnt = 0; + int ret; + struct sk_buff *n_skb = NULL; + struct sk_buff *cur_skb; + struct sk_buff *rx_skb; + struct RxDesc *rxdesc; + + assert (dev != NULL); + assert (priv != NULL); + assert (ioaddr != NULL); + + + cur_rx = priv->cur_rx; + + rxdesc = &priv->RxDescArray[cur_rx]; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) + pci_dma_sync_single(pdev, priv->rxdesc_array_dma_addr[cur_rx], sizeof(struct RxDesc), PCI_DMA_FROMDEVICE); +#endif + + while ( ((le32_to_cpu(rxdesc->status) & OWNbit)== 0) && (rxdesc_cnt < max_interrupt_work) ){ + + rxdesc_cnt++; + + if( le32_to_cpu(rxdesc->status) & RxRES ){ + printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name); + priv->stats.rx_errors++; + if ( le32_to_cpu(rxdesc->status) & (RxRWT|RxRUNT) ) + priv->stats.rx_length_errors++; + if ( le32_to_cpu(rxdesc->status) & RxCRC) + priv->stats.rx_crc_errors++; + } + else{ + pkt_size=(int)(le32_to_cpu(rxdesc->status) & 0x00001FFF)-4; + + if( pkt_size > priv->rx_pkt_len ){ + printk("%s: Error -- Rx packet size(%d) > mtu(%d)+14\n", dev->name, pkt_size, dev->mtu); + pkt_size = priv->rx_pkt_len; + } + + DBG_PRINT("%s: RX pkt_size = %d\n", __FUNCTION__, pkt_size); + + {// ----------------------------------------------------- + rx_skb = priv->Rx_skbuff[cur_rx]; + n_skb = R1000_ALLOC_RXSKB(MAX_RX_SKBDATA_SIZE); + if( n_skb != NULL ) { + skb_reserve (n_skb, 8); // 16 byte align the IP fields. // + + // Indicate rx_skb + if( rx_skb != NULL ){ + rx_skb->dev = dev; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) + pci_dma_sync_single(pdev, priv->rx_skbuff_dma_addr[cur_rx], sizeof(struct RxDesc), PCI_DMA_FROMDEVICE); +#endif + + skb_put ( rx_skb, pkt_size ); + rx_skb->protocol = eth_type_trans ( rx_skb, dev ); + ret = R1000_NETIF_RX (rx_skb); + +// dev->last_rx = jiffies; + priv->stats.rx_bytes += pkt_size; + priv->stats.rx_packets++; + +#ifdef R1000_DYNAMIC_CONTROL + r1000_callback_rx( &(priv->rt), 1, pkt_size); +#endif //end #ifdef R1000_DYNAMIC_CONTROL + + }//end if( rx_skb != NULL ) + + priv->Rx_skbuff[cur_rx] = n_skb; + } + else{ + DBG_PRINT("%s: Allocate n_skb failed!\n",__FUNCTION__ ); + priv->Rx_skbuff[cur_rx] = rx_skb; + } + + + // Update rx descriptor + if( cur_rx == (NUM_RX_DESC-1) ){ + priv->RxDescArray[cur_rx].status = cpu_to_le32((OWNbit | EORbit) | (unsigned long)priv->hw_rx_pkt_len); + } + else{ + priv->RxDescArray[cur_rx].status = cpu_to_le32(OWNbit | (unsigned long)priv->hw_rx_pkt_len); + } + + cur_skb = priv->Rx_skbuff[cur_rx]; + + if( cur_skb != NULL ){ + priv->rx_skbuff_dma_addr[cur_rx] = pci_map_single(pdev, cur_skb->data, MAX_RX_SKBDATA_SIZE, PCI_DMA_FROMDEVICE); + rxdesc->buf_addr = cpu_to_le32(priv->rx_skbuff_dma_addr[cur_rx]); + } + else{ + DBG_PRINT("%s: %s() cur_skb == NULL\n", dev->name, __FUNCTION__); + } + + }//------------------------------------------------------------ + + }// end of if( priv->RxDescArray[cur_rx].status & RxRES ) + + cur_rx = (cur_rx +1) % NUM_RX_DESC; + rxdesc = &priv->RxDescArray[cur_rx]; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) + pci_dma_sync_single(pdev, priv->rxdesc_array_dma_addr[cur_rx], sizeof(struct RxDesc), PCI_DMA_FROMDEVICE); +#endif + + }// end of while ( (priv->RxDescArray[cur_rx].status & 0x80000000)== 0) + + if( rxdesc_cnt >= max_interrupt_work ){ + DBG_PRINT("%s: Too much work at Rx interrupt.\n", dev->name); + } + + priv->cur_rx = cur_rx; +} + + + + + + + + +//====================================================================================================== +/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +static void r1000_interrupt (int irq, void *dev_instance, struct pt_regs *regs) +#else +static irqreturn_t r1000_interrupt (int irq, void *dev_instance, struct pt_regs *regs) +#endif +{ + struct net_device *dev = (struct net_device *) dev_instance; + struct r1000_private *priv = dev->priv; + int boguscnt = max_interrupt_work; + unsigned long ioaddr = priv->ioaddr; + int status = 0; +// irqreturn_int interrupt_handled = IRQ_NONE; + int interrupt_handled = IRQ_NONE; + + RTL_W16 ( IntrMask, 0x0000); + + do { + status = RTL_R16(IntrStatus); + + if (status == 0xFFFF) + break; + + + RTL_W16( IntrStatus, status ); + + + if ( (status & r1000_intr_mask ) == 0 ) + break; + else + interrupt_handled = IRQ_HANDLED; + + + // Rx interrupt +// if (status & (RxOK | RxErr /* | LinkChg | RxOverflow | RxFIFOOver*/)){ + r1000_rx_interrupt (dev, priv, ioaddr); +// } + + // Tx interrupt +// if (status & (TxOK | TxErr)) { + spin_lock (&priv->lock); + r1000_tx_interrupt (dev, priv, ioaddr); + spin_unlock (&priv->lock); +// } + if ((status & TxOK)&&(status & TxDescUnavail)) + RTL_W8(TxPoll,0x40); + + boguscnt--; + } while (boguscnt > 0); + + if (boguscnt <= 0) { + DBG_PRINT("%s: Too much work at interrupt!\n", dev->name); + RTL_W16( IntrStatus, 0xffff); // Clear all interrupt sources + } + + RTL_W16 ( IntrMask, r1000_intr_mask); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + return interrupt_handled; +#endif +} + + + + + + + +//====================================================================================================== +static int r1000_close (struct net_device *dev) +{ + struct r1000_private *priv = dev->priv; + unsigned long ioaddr = priv->ioaddr; + int i; + + // ----------------------------------------- + r1000_delete_timer( &(priv->r1000_timer) ); + + + netif_stop_queue (dev); + + spin_lock_irq (&priv->lock); + + /* Stop the chip's Tx and Rx processes. */ + RTL_W8 ( ChipCmd, 0x00); + + /* Disable interrupts by clearing the interrupt mask. */ + RTL_W16 ( IntrMask, 0x0000); + + /* Update the error counts. */ + priv->stats.rx_missed_errors += RTL_R32(RxMissed); + RTL_W32( RxMissed, 0); + + spin_unlock_irq (&priv->lock); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + synchronize_irq (); +#else + synchronize_irq (dev->irq); +#endif + free_irq (dev->irq, dev); + + r1000_tx_clear (priv); + + //2004-05-11 + if(priv->txdesc_space != NULL){ + pci_free_consistent( + priv->pci_dev, + priv->sizeof_txdesc_space, + priv->txdesc_space, + priv->txdesc_phy_dma_addr + ); + priv->txdesc_space = NULL; + } + + if(priv->rxdesc_space != NULL){ + pci_free_consistent( + priv->pci_dev, + priv->sizeof_rxdesc_space, + priv->rxdesc_space, + priv->rxdesc_phy_dma_addr + ); + priv->rxdesc_space = NULL; + } + + priv->TxDescArray = NULL; + priv->RxDescArray = NULL; + + {//----------------------------------------------------------------------------- + for(i=0;iRx_skbuff[i] != NULL ) { + R1000_FREE_RXSKB ( priv->Rx_skbuff[i] ); + } + } + }//----------------------------------------------------------------------------- + + DBG_PRINT("%s: %s() alloc_rxskb_cnt = %d\n", dev->name, __FUNCTION__, alloc_rxskb_cnt ); + + return 0; +} + + + + + + + +//====================================================================================================== +static unsigned const ethernet_polynomial = 0x04c11db7U; +static inline u32 ether_crc (int length, unsigned char *data) +{ + int crc = -1; + + while (--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 0; bit < 8; bit++, current_octet >>= 1) + crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); + } + + return crc; +} + + + + + + + + +//====================================================================================================== +static void r1000_set_rx_mode (struct net_device *dev) +{ + struct r1000_private *priv = dev->priv; + unsigned long ioaddr = priv->ioaddr; + unsigned long flags; + u32 mc_filter[2]; /* Multicast hash filter */ + int i, rx_mode; + u32 tmp=0; + + + if (dev->flags & IFF_PROMISC) { + /* Unconditionally log net taps. */ + printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys; + mc_filter[1] = mc_filter[0] = 0xffffffff; + } else if ((dev->mc_count > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { + /* Too many to filter perfectly -- accept all multicasts. */ + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + mc_filter[1] = mc_filter[0] = 0xffffffff; + } else { + struct dev_mc_list *mclist; + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + mc_filter[1] = mc_filter[0] = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) + { + set_bit (ether_crc (ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter); + } +#else + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) + { + int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; + + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + rx_mode |= AcceptMulticast; + } +#endif + } + + spin_lock_irqsave (&priv->lock, flags); + + tmp = r1000_rx_config | rx_mode | (RTL_R32(RxConfig) & rtl_chip_info[priv->chipset].RxConfigMask); + + RTL_W32 ( RxConfig, tmp); + if((priv->mcfg==MCFG_METHOD_11)||(priv->mcfg==MCFG_METHOD_12)|| + (priv->mcfg==MCFG_METHOD_13)||(priv->mcfg==MCFG_METHOD_14)|| + (priv->mcfg==MCFG_METHOD_15)){ + RTL_W32 ( MAR0 + 0, 0xFFFFFFFF); + RTL_W32 ( MAR0 + 4, 0xFFFFFFFF); + }else{ + RTL_W32 ( MAR0 + 0, mc_filter[0]); + RTL_W32 ( MAR0 + 4, mc_filter[1]); + } + + spin_unlock_irqrestore (&priv->lock, flags); + +}//end of r1000_set_rx_mode (struct net_device *dev) + + + + + + + +//================================================================================ +struct net_device_stats *r1000_get_stats(struct net_device *dev) + +{ + struct r1000_private *priv = dev->priv; + + return &priv->stats; +} + + + + + + + + +//================================================================================ +static struct pci_driver r1000_pci_driver = { + name: MODULENAME, + id_table: r1000_pci_tbl, + probe: r1000_init_one, + remove: r1000_remove_one, + suspend: NULL, + resume: NULL, +}; + + + + + +//====================================================================================================== +static int __init r1000_init_module (void) +{ + return pci_module_init (&r1000_pci_driver); // pci_register_driver (drv) +} + + + + +//====================================================================================================== +static void __exit r1000_cleanup_module (void) +{ + pci_unregister_driver (&r1000_pci_driver); +} + + +#ifdef R1000_JUMBO_FRAME_SUPPORT +static int r1000_change_mtu(struct net_device *dev, int new_mtu) +{ + struct r1000_private *priv = dev->priv; + unsigned long ioaddr = priv->ioaddr; + + if( new_mtu > MAX_JUMBO_FRAME_MTU ){ + printk("%s: Error -- new_mtu(%d) > MAX_JUMBO_FRAME_MTU(%d).\n", dev->name, new_mtu, MAX_JUMBO_FRAME_MTU); + return -1; + } + + dev->mtu = new_mtu; + + priv->curr_mtu_size = new_mtu; + priv->tx_pkt_len = new_mtu + ETH_HDR_LEN; + priv->rx_pkt_len = new_mtu + ETH_HDR_LEN; + priv->hw_rx_pkt_len = priv->rx_pkt_len + 8; + + RTL_W8 ( Cfg9346, Cfg9346_Unlock); + RTL_W16 ( RxMaxSize, (unsigned short)priv->hw_rx_pkt_len ); + RTL_W8 ( Cfg9346, Cfg9346_Lock); + + DBG_PRINT("-------------------------- \n"); + DBG_PRINT("dev->mtu = %d \n", dev->mtu); + DBG_PRINT("priv->curr_mtu_size = %d \n", priv->curr_mtu_size); + DBG_PRINT("priv->rx_pkt_len = %d \n", priv->rx_pkt_len); + DBG_PRINT("priv->tx_pkt_len = %d \n", priv->tx_pkt_len); + DBG_PRINT("RTL_W16( RxMaxSize, %d )\n", priv->hw_rx_pkt_len); + DBG_PRINT("-------------------------- \n"); + + r1000_close (dev); + r1000_open (dev); + + return 0; +} +#endif //end #ifdef R1000_JUMBO_FRAME_SUPPORT + + + + + + + + + + + +//====================================================================================================== +module_init(r1000_init_module); +module_exit(r1000_cleanup_module); diff -urN linux-2.6.16.18-old/include/asm-arm/arch-iop3xx/iop321.h linux-2.6.16.18/include/asm-arm/arch-iop3xx/iop321.h --- linux-2.6.16.18-old/include/asm-arm/arch-iop3xx/iop321.h 2006-05-22 20:04:35.000000000 +0200 +++ linux-2.6.16.18/include/asm-arm/arch-iop3xx/iop321.h 2006-06-02 23:21:21.000000000 +0200 @@ -251,7 +251,7 @@ #ifdef CONFIG_ARCH_EP80219 #undef IOP321_TICK_RATE -#define IOP321_TICK_RATE 200000000 /* 33.333333 Mhz crystal */ +#define IOP321_TICK_RATE 198000000 /* 33.00 Mhz crystal */ #endif #define IOP321_TMR_TC 0x01 diff -urN linux-2.6.16.18-old/include/asm-arm/arch-iop3xx/iq31244.h linux-2.6.16.18/include/asm-arm/arch-iop3xx/iq31244.h --- linux-2.6.16.18-old/include/asm-arm/arch-iop3xx/iq31244.h 2006-05-22 20:04:35.000000000 +0200 +++ linux-2.6.16.18/include/asm-arm/arch-iop3xx/iq31244.h 2006-06-02 23:21:21.000000000 +0200 @@ -8,7 +8,7 @@ #define _IQ31244_H_ #define IQ31244_FLASHBASE 0xf0000000 /* Flash */ -#define IQ31244_FLASHSIZE 0x00800000 +#define IQ31244_FLASHSIZE 0x01000000 #define IQ31244_FLASHWIDTH 2 #define IQ31244_UART 0xfe800000 /* UART #1 */ diff -urN linux-2.6.16.18-old/include/asm-arm/arch-iop3xx/system.h linux-2.6.16.18/include/asm-arm/arch-iop3xx/system.h --- linux-2.6.16.18-old/include/asm-arm/arch-iop3xx/system.h 2006-05-22 20:04:35.000000000 +0200 +++ linux-2.6.16.18/include/asm-arm/arch-iop3xx/system.h 2006-06-02 23:21:21.000000000 +0200 @@ -17,9 +17,21 @@ static inline void arch_reset(char mode) { #ifdef CONFIG_ARCH_IOP321 + *IOP321_GPOE = 0xFE; + *IOP321_GPOD = 0x00; + mdelay(100); + *IOP321_GPOE = 0xE0; + *IOP321_GPOD = 0x00; + mdelay(100); + *IOP321_GPOE = 0xEC; + *IOP321_GPOD = 0x10; + +#endif +/* +#ifdef CONFIG_ARCH_IOP321 *IOP321_PCSR = 0x30; #endif - +*/ #ifdef CONFIG_ARCH_IOP331 *IOP331_PCSR = 0x30; #endif --- ./arch/arm/mach-iop3xx/iq31244-pci.c 2004-10-18 23:55:27.000000000 +0200 +++ ../n2100_1.0.5/build/linux/arch/arm/mach-iop3xx/iq31244-pci.c 2005-09-23 08:37:35.000000000 +0200 @@ -54,6 +54,8 @@ {INTE, INTE, INTE, INTE}, /* 82551 Pro 100 */ {INTD, INTD, INTD, INTD}, /* PCI-X Slot */ {INTC, INTC, INTC, INTC}, /* SATA */ + {INTB, INTA, INTC, INTD}, /* VT6212 */ + {INTD, INTD, INTD, INTD}, /* Mini-PCI Slot */ #else {INTB, INTB, INTB, INTB}, /* CFlash */ {INTC, INTC, INTC, INTC}, /* SATA */