Chinaunix首页 | 论坛 | 博客
  • 博客访问: 207106
  • 博文数量: 58
  • 博客积分: 1420
  • 博客等级: 上尉
  • 技术积分: 662
  • 用 户 组: 普通用户
  • 注册时间: 2008-01-01 11:56
文章分类

全部博文(58)

文章存档

2009年(50)

2008年(8)

我的朋友

分类: LINUX

2009-06-01 12:35:11

首先明确, 我们写driver 一个主要的动作就是 control register , 所以怎么样在driver
里面control register 这个时候就要查datasheet 了,我们写driver 的人只要严格按照
datasheet的steps就好了,

比如我举个例子: 对于intel 的 8255x lan controller (就是网卡控制芯片,也就是
微机原理书上的接口电路,用来连接总线和实际的网卡设备) ,kernel里面的code 就是
drivers/net/e100

比如对于这个功能: 如何determine EEPROM size , 我们要在driver里面实现 ,
就必须到datasheet里面查 , 下面就是 如何determine EEPROM size 的 描述:

6.3.4.2 Software Determination of EEPROM Size
To determine the size of the EEPROM, software may use the following steps.
Note: This algorithm will only work if the EEPROM drives a dummy zero to EEDO after
receiving the
complete address field.
1. Activate the EEPROM by writing a 1 to the EECS bit.
2. Write the read opcode, including the start bit (110b), one bit at a time starting
with the most
significant bit (1):
a. Write the opcode bit to the EEDI bit.
b. Write a 1 to EESK bit and wait the minimum SK high time.
c. Write a 0 to EESK bit and wait the minimum SK low time.
d. Repeat steps 2.a through 2.c for the next two opcode bits.
3. Write the address field, one bit at a time, keeping track of the number of bits
shifted in, starting
with the most significant bit.
a. Write the address bit to the EEDI bit.
b. Write a 1 to the EESK bit and wait the minimum SK high time.
c. Write a 0 to the EESK bit and wait the minimum SK low time.
d. Read the EEDO bit, looking for the dummy 0 bit.
e. Repeat steps 3.a through 3.d until the EEDO bit equals 0. The number of loop
iterations
performed is the number of bits in the address field.
4. Read a 16-bit word from the EEPROM one bit at a time, starting with the most
significant bit,
to complete the transaction (but discard the output).
a. Write a 1 to the EESK bit then wait the minimum SK high time.
b. Read a data bit from the EEDO bit.
c. Write a 0 to the EESK bit then wait the minimum SK low time.
d. Repeat steps 4.a through 4.c an additional 15 times.
e. De-activate the EEPROM by writing a 0 to the EECS bit.

然后我们才可以实现我们的driver , 仔细对照 才可以成功control register


e100_eeprom.c 里面的一个函数:

//------------------------------------------------------------------------------------

----

// Procedure: e100_eeprom_size

//

// Description: This routine determines the size of the EEPROM. This value should be

// checked for validity - ie. is it too big or too small. The size

returned

// is then passed to the read/write functions.

//

// Returns:

// Size of the eeprom, or zero if an error occurred

//------------------------------------------------------------------------------------

----

u16

e100_eeprom_size(struct e100_private *adapter)

{

u16 x, size = 1; // must be one to accumulate a product



// if we've already stored this data, read from memory

if (adapter->eeprom_size) {

return adapter->eeprom_size;

}

// otherwise, read from the eeprom

// Set EEPROM semaphore.

if (adapter->rev_id >= D102_REV_ID) {

if (!eeprom_set_semaphore(adapter))

return 0;

}

// enable the eeprom by setting EECS.

x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));

x &= ~(EEDI | EEDO | EESK);

x |= EECS;

writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));



// write the read opcode

shift_out_bits(adapter, EEPROM_READ_OPCODE, 3);



// experiment to discover the size of the eeprom. request register zero

// and wait for the eeprom to tell us it has accepted the entire address.

x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));

do {

size *= 2; // each bit of address doubles eeprom size

x |= EEDO; // set bit to detect "dummy zero"

x &= ~EEDI; // address consists of all zeros



writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));

readw(&(adapter->scb->scb_status));

udelay(EEPROM_STALL_TIME);//udaly (4)

raise_clock(adapter, &x);

lower_clock(adapter, &x);



// check for "dummy zero"

x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));

if (size > EEPROM_MAX_WORD_SIZE) {

size = 0;

break;

}

} while (x & EEDO);



// read in the value requested

(void) shift_in_bits(adapter);

e100_eeprom_cleanup(adapter);



// Clear EEPROM Semaphore.

if (adapter->rev_id >= D102_REV_ID) {

eeprom_reset_semaphore(adapter);

}



return size;




}

另外 ,你要control EEPROM的寄存器, 就要找到 register的地址 ,
找datasheet 有这样的一段:(不好意思 ,粘贴pdf 上的表格不行啊)
Upper Word (D31:D16) Lower Word (D15:D0) Offset
SCB Command Word SCB Status Word Base + 0h
SCB General Pointer Base + 4h
PORT Base + 8h
EEPROM Control Register Reserved Base + Ch

在datasheet中 :是这样定义的:
Figure 12. EEPROM Control Register

23 22 21 20 19 18 17 16

X X X X EEDO EEDI EECS EESK



当我们在学习 别人的driver的时候, 发现 在定义寄存器地址的时候都是这样定义的:

比如:

#define EN_TRNF 0x10 /* Enable turnoff */

#define EEDO 0x08 /* EEPROM data out */

#define EEDI 0x04 /* EEPROM data in (set for writing data) */

#define EECS 0x02 /* EEPROM chip select (1=hi, 0=lo) */

#define EESK 0x01 /* EEPROM shift clock (1=hi, 0=lo) */



我们看出来 , 如果从0开始排 , EEDO EEDI EECS EESK

0x08 0x04 0x02 0x01

所以就对应上了 。



// enable the eeprom by setting EECS. 把EECS 置为1

x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));



x &= ~(EEDI | EEDO | EESK); //把这三位都置为 0 ,EECS不动 ,

//0x8 | 0x4 | 0x1 , 1101 ,

x |= EECS; // 把EECS的位置为 1

writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));


从上面可以看出 , kernel里面的driver 写的多好啊 ! 一目了然 。


读datasheet 还是要针对一个你目前正在作的案子 , 死盯住一个datasheet ,把它看懂 。

我现在就一直在看 usb方面的, uhci ehci , 这些在debug的时候都要用到,还有就是
GL880和VT6212L的datasheet ,

比如:
在我们的板子上原来有个 bug , 只要插上usb harddisk ,往里面copy file ,
console就输入出 fatal error , 然后file system read-only 的错误

It looks that PCI has problems . I doubt that whether the usb chip has been attached
tightly to the PCI bus or not , maybe ,their connection is loose,result in transaction
error .


FYI ,
when copy the file into USB Harddisk , some error messages will pop up ,  
ehci_hcd 00:01.2: fatal error
Unable to handle kernel NULL pointer dereference at virtual address 00000000
it is printed by a sheet of code

/* unrequested/ignored: Port Change Detect, Frame List Rollover */

dbg_status (ehci, "irq", status); // print the status of USBSTS Register

....................................

/* PCI errors [4.15.2.4] */

if (unlikely ((status & STS_FATAL) != 0)) { //STS_FATAL : 1<<4

ehci_err (ehci, "fatal error
"); //will print "ehci_hcd 00:01.2: fatal error"





...........................................

// ----------------------------------STS_FATAL Define

-----------------------------------

/* USBSTS: offset 0x04 */

u32 status;

#define STS_ASS (1<<15) /* Async Schedule Status */

#define STS_PSS (1<<14) /* Periodic Schedule Status */

#define STS_RECL (1<<13) /* Reclamation */

#define STS_HALT (1<<12) /* Not running (any reason) */

/* some bits reserved */

/* these STS_* flags are also intr_enable bits (USBINTR) */

#define STS_IAA (1<<5) /* Interrupted on async advance */

#define STS_FATAL (1<<4) /* such as some PCI access errors */

#define STS_FLR (1<<3) /* frame list rolled over */

#define STS_PCD (1<<2) /* port change detect */

#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */

#define STS_INT (1<<0) /* "normal" completion (short, ...) */



//

--------------------------------------------------------------------------------------







I find EHCI 1.0 datasheet(VT6212L declare that he is compliant with Enhanced Host

Controller Interface Specification Revision 1.0)



there is some info about STS_FATAL in 2.3.2 USBSTS USB Status Register of Page 31



bit 4

Host System Error . R/WC. The Host Controller sets this bit to 1 when a serious

error

occurs during a host system access involving the Host Controller module. In a PCI

system, conditions that set this bit to 1 include PCI Parity error, PCI Master Abort,

and

PCI Target Abort. When this error occurs, the Host Controller clears the Run/Stop bit

in

the Command register to prevent further execution of the scheduled TDs.

这样的话, 我们基本可以定位问题, 知道问题出在了哪里 。、
阅读(4393) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~