免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1302 | 回复: 0
打印 上一主题 下一主题

Driver Writer如何读DATASHEET(总结BBS文章) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-06-01 12:35 |只看该作者 |倒序浏览
首先明确, 我们写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
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/58463/showart_1951134.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP