⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eeprom.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*!******************************************************************************!*!  Implements an interface for i2c compatible eeproms to run under linux.*!  Supports 2k, 8k(?) and 16k. Uses adaptive timing adjustents by*!  Johan.Adolfsson@axis.com*!*!  Probing results:*!    8k or not is detected (the assumes 2k or 16k)*!    2k or 16k detected using test reads and writes.*!*!------------------------------------------------------------------------*!  HISTORY*!*!  DATE          NAME              CHANGES*!  ----          ----              -------*!  Aug  28 1999  Edgar Iglesias    Initial Version*!  Aug  31 1999  Edgar Iglesias    Allow simultaneous users.*!  Sep  03 1999  Edgar Iglesias    Updated probe.*!  Sep  03 1999  Edgar Iglesias    Added bail-out stuff if we get interrupted*!                                  in the spin-lock.*!*!  $Log: eeprom.c,v $*!  Revision 1.10  2003/09/11 07:29:48  starvik*!  Merge of Linux 2.6.0-test5*!*!  Revision 1.9  2003/07/04 08:27:37  starvik*!  Merge of Linux 2.5.74*!*!  Revision 1.8  2003/04/09 05:20:47  starvik*!  Merge of Linux 2.5.67*!*!  Revision 1.6  2003/02/10 07:19:28  starvik*!  Removed misplaced ;*!*!  Revision 1.5  2002/12/11 13:13:57  starvik*!  Added arch/ to v10 specific includes*!  Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)*!*!  Revision 1.4  2002/11/20 11:56:10  starvik*!  Merge of Linux 2.5.48*!*!  Revision 1.3  2002/11/18 13:16:06  starvik*!  Linux 2.5 port of latest 2.4 drivers*!*!  Revision 1.8  2001/06/15 13:24:29  jonashg*!  * Added verification of pointers from userspace in read and write.*!  * Made busy counter volatile.*!  * Added define for inital write delay.*!  * Removed warnings by using loff_t instead of unsigned long.*!*!  Revision 1.7  2001/06/14 15:26:54  jonashg*!  Removed test because condition is always true.*!*!  Revision 1.6  2001/06/14 15:18:20  jonashg*!  Kb -> kB (makes quite a difference if you don't know if you have 2k or 16k).*!*!  Revision 1.5  2001/06/14 14:39:51  jonashg*!  Forgot to use name when registering the driver.*!*!  Revision 1.4  2001/06/14 14:35:47  jonashg*!  * Gave driver a name and used it in printk's.*!  * Cleanup.*!*!  Revision 1.3  2001/03/19 16:04:46  markusl*!  Fixed init of fops struct*!*!  Revision 1.2  2001/03/19 10:35:07  markusl*!  2.4 port of eeprom driver*!*!  Revision 1.8  2000/05/18 10:42:25  edgar*!  Make sure to end write cycle on _every_ write*!*!  Revision 1.7  2000/01/17 17:41:01  johana*!  Adjusted probing and return -ENOSPC when writing outside EEPROM*!*!  Revision 1.6  2000/01/17 15:50:36  johana*!  Added adaptive timing adjustments and fixed autoprobing for 2k and 16k(?)*!  EEPROMs*!*!  Revision 1.5  1999/09/03 15:07:37  edgar*!  Added bail-out check to the spinlock*!*!  Revision 1.4  1999/09/03 12:11:17  bjornw*!  Proper atomicity (need to use spinlocks, not if's). users -> busy.*!*!*!        (c) 1999 Axis Communications AB, Lund, Sweden*!*****************************************************************************/#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include "i2c.h"#define D(x) /* If we should use adaptive timing or not: *///#define EEPROM_ADAPTIVE_TIMING      #define EEPROM_MAJOR_NR 122  /* use a LOCAL/EXPERIMENTAL major for now */#define EEPROM_MINOR_NR 0/* Empirical sane initial value of the delay, the value will be adapted to * what the chip needs when using EEPROM_ADAPTIVE_TIMING. */#define INITIAL_WRITEDELAY_US 4000#define MAX_WRITEDELAY_US 10000 /* 10 ms according to spec for 2KB EEPROM *//* This one defines how many times to try when eeprom fails. */#define EEPROM_RETRIES 10#define EEPROM_2KB (2 * 1024)/*#define EEPROM_4KB (4 * 1024)*/ /* Exists but not used in Axis products */#define EEPROM_8KB (8 * 1024 - 1 ) /* Last byte has write protection bit */#define EEPROM_16KB (16 * 1024)#define i2c_delay(x) udelay(x)/* *  This structure describes the attached eeprom chip. *  The values are probed for. */struct eeprom_type{  unsigned long size;  unsigned long sequential_write_pagesize;  unsigned char select_cmd;  unsigned long usec_delay_writecycles; /* Min time between write cycles					   (up to 10ms for some models) */  unsigned long usec_delay_step; /* For adaptive algorithm */  int adapt_state; /* 1 = To high , 0 = Even, -1 = To low */    /* this one is to keep the read/write operations atomic */  wait_queue_head_t wait_q;  volatile int busy;  int retry_cnt_addr; /* Used to keep track of number of retries for                         adaptive timing adjustments */  int retry_cnt_read;};static int  eeprom_open(struct inode * inode, struct file * file);static loff_t  eeprom_lseek(struct file * file, loff_t offset, int orig);static ssize_t  eeprom_read(struct file * file, char * buf, size_t count,                            loff_t *off);static ssize_t  eeprom_write(struct file * file, const char * buf, size_t count,                             loff_t *off);static int eeprom_close(struct inode * inode, struct file * file);static int  eeprom_address(unsigned long addr);static int  read_from_eeprom(char * buf, int count);static int eeprom_write_buf(loff_t addr, const char * buf, int count);static int eeprom_read_buf(loff_t addr, char * buf, int count);static void eeprom_disable_write_protect(void);static const char eeprom_name[] = "eeprom";/* chip description */static struct eeprom_type eeprom;/* This is the exported file-operations structure for this device. */struct file_operations eeprom_fops ={  .llseek  = eeprom_lseek,  .read    = eeprom_read,  .write   = eeprom_write,  .open    = eeprom_open,  .release = eeprom_close};/* eeprom init call. Probes for different eeprom models. */int __init eeprom_init(void){  init_waitqueue_head(&eeprom.wait_q);  eeprom.busy = 0;#ifdef CONFIG_ETRAX_I2C_EEPROM_PROBE#define EETEXT "Found"#else#define EETEXT "Assuming"#endif  if (register_chrdev(EEPROM_MAJOR_NR, eeprom_name, &eeprom_fops))  {    printk(KERN_INFO "%s: unable to get major %d for eeprom device\n",           eeprom_name, EEPROM_MAJOR_NR);    return -1;  }    printk("EEPROM char device v0.3, (c) 2000 Axis Communications AB\n");  /*   *  Note: Most of this probing method was taken from the printserver (5470e)   *        codebase. It did not contain a way of finding the 16kB chips   *        (M24128 or variants). The method used here might not work   *        for all models. If you encounter problems the easiest way   *        is probably to define your model within #ifdef's, and hard-   *        code it.   */  eeprom.size = 0;  eeprom.usec_delay_writecycles = INITIAL_WRITEDELAY_US;  eeprom.usec_delay_step = 128;  eeprom.adapt_state = 0;  #ifdef CONFIG_ETRAX_I2C_EEPROM_PROBE  i2c_start();  i2c_outbyte(0x80);  if(!i2c_getack())  {    /* It's not 8k.. */    int success = 0;    unsigned char buf_2k_start[16];        /* Im not sure this will work... :) */    /* assume 2kB, if failure go for 16kB */    /* Test with 16kB settings.. */    /* If it's a 2kB EEPROM and we address it outside it's range     * it will mirror the address space:     * 1. We read two locations (that are mirrored),      *    if the content differs * it's a 16kB EEPROM.     * 2. if it doesn't differ - write different value to one of the locations,     *    check the other - if content still is the same it's a 2k EEPROM,     *    restore original data.     */#define LOC1 8#define LOC2 (0x1fb) /*1fb, 3ed, 5df, 7d1 */   /* 2k settings */      i2c_stop();    eeprom.size = EEPROM_2KB;    eeprom.select_cmd = 0xA0;       eeprom.sequential_write_pagesize = 16;    if( eeprom_read_buf( 0, buf_2k_start, 16 ) == 16 )    {      D(printk("2k start: '%16.16s'\n", buf_2k_start));    }    else    {      printk(KERN_INFO "%s: Failed to read in 2k mode!\n", eeprom_name);      }        /* 16k settings */    eeprom.size = EEPROM_16KB;    eeprom.select_cmd = 0xA0;       eeprom.sequential_write_pagesize = 64;    {      unsigned char loc1[4], loc2[4], tmp[4];      if( eeprom_read_buf(LOC2, loc2, 4) == 4)      {        if( eeprom_read_buf(LOC1, loc1, 4) == 4)        {          D(printk("0 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n",                    LOC1, loc1, LOC2, loc2));#if 0          if (memcmp(loc1, loc2, 4) != 0 )          {            /* It's 16k */            printk(KERN_INFO "%s: 16k detected in step 1\n", eeprom_name);            eeprom.size = EEPROM_16KB;                 success = 1;          }          else#endif          {            /* Do step 2 check */            /* Invert value */            loc1[0] = ~loc1[0];            if (eeprom_write_buf(LOC1, loc1, 1) == 1)            {              /* If 2k EEPROM this write will actually write 10 bytes               * from pos 0               */              D(printk("1 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n",                        LOC1, loc1, LOC2, loc2));              if( eeprom_read_buf(LOC1, tmp, 4) == 4)              {                D(printk("2 loc1: (%i) '%4.4s' tmp '%4.4s'\n",                          LOC1, loc1, tmp));                if (memcmp(loc1, tmp, 4) != 0 )                {                  printk(KERN_INFO "%s: read and write differs! Not 16kB\n",                         eeprom_name);                  loc1[0] = ~loc1[0];                                    if (eeprom_write_buf(LOC1, loc1, 1) == 1)                  {                    success = 1;                  }                  else                  {                    printk(KERN_INFO "%s: Restore 2k failed during probe,"                           " EEPROM might be corrupt!\n", eeprom_name);                                      }                  i2c_stop();                  /* Go to 2k mode and write original data */                  eeprom.size = EEPROM_2KB;                  eeprom.select_cmd = 0xA0;                     eeprom.sequential_write_pagesize = 16;                  if( eeprom_write_buf(0, buf_2k_start, 16) == 16)                  {                  }                  else                  {                    printk(KERN_INFO "%s: Failed to write back 2k start!\n",                           eeprom_name);                  }                                    eeprom.size = EEPROM_2KB;                }              }                              if(!success)              {                if( eeprom_read_buf(LOC2, loc2, 1) == 1)                {                  D(printk("0 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n",                            LOC1, loc1, LOC2, loc2));                  if (memcmp(loc1, loc2, 4) == 0 )                  {                    /* Data the same, must be mirrored -> 2k */                    /* Restore data */                    printk(KERN_INFO "%s: 2k detected in step 2\n", eeprom_name);                    loc1[0] = ~loc1[0];                    if (eeprom_write_buf(LOC1, loc1, 1) == 1)                    {                      success = 1;                    }                    else                    {                      printk(KERN_INFO "%s: Restore 2k failed during probe,"                             " EEPROM might be corrupt!\n", eeprom_name);                                          }                                        eeprom.size = EEPROM_2KB;                       }                  else                  {                    printk(KERN_INFO "%s: 16k detected in step 2\n",                           eeprom_name);                    loc1[0] = ~loc1[0];                    /* Data differs, assume 16k */                    /* Restore data */                    if (eeprom_write_buf(LOC1, loc1, 1) == 1)                    {                      success = 1;                    }                    else                    {                      printk(KERN_INFO "%s: Restore 16k failed during probe,"                             " EEPROM might be corrupt!\n", eeprom_name);                    }                                        eeprom.size = EEPROM_16KB;                  }                }              }            }          } /* read LOC1 */        } /* address LOC1 */        if (!success)        {          printk(KERN_INFO "%s: Probing failed!, using 2KB!\n", eeprom_name);          eeprom.size = EEPROM_2KB;                       }      } /* read */    }  }  else  {    i2c_outbyte(0x00);    if(!i2c_getack())    {      /* No 8k */      eeprom.size = EEPROM_2KB;    }    else    {      i2c_start();      i2c_outbyte(0x81);      if (!i2c_getack())      {        eeprom.size = EEPROM_2KB;      }      else      {        /* It's a 8kB */        i2c_inbyte();        eeprom.size = EEPROM_8KB;      }    }  }  i2c_stop();#elif defined(CONFIG_ETRAX_I2C_EEPROM_16KB)  eeprom.size = EEPROM_16KB;#elif defined(CONFIG_ETRAX_I2C_EEPROM_8KB)  eeprom.size = EEPROM_8KB;#elif defined(CONFIG_ETRAX_I2C_EEPROM_2KB)  eeprom.size = EEPROM_2KB;#endif  switch(eeprom.size)  {   case (EEPROM_2KB):     printk("%s: " EETEXT " i2c compatible 2kB eeprom.\n", eeprom_name);     eeprom.sequential_write_pagesize = 16;     eeprom.select_cmd = 0xA0;     break;   case (EEPROM_8KB):     printk("%s: " EETEXT " i2c compatible 8kB eeprom.\n", eeprom_name);     eeprom.sequential_write_pagesize = 16;     eeprom.select_cmd = 0x80;     break;   case (EEPROM_16KB):     printk("%s: " EETEXT " i2c compatible 16kB eeprom.\n", eeprom_name);     eeprom.sequential_write_pagesize = 64;     eeprom.select_cmd = 0xA0;          break;   default:     eeprom.size = 0;     printk("%s: Did not find a supported eeprom\n", eeprom_name);     break;  }    eeprom_disable_write_protect();  return 0;}/* Opens the device. */static int eeprom_open(struct inode * inode, struct file * file){  if(MINOR(inode->i_rdev) != EEPROM_MINOR_NR)     return -ENXIO;  if(MAJOR(inode->i_rdev) != EEPROM_MAJOR_NR)     return -ENXIO;  if( eeprom.size > 0 )  {    /* OK */    return 0;  }  /* No EEprom found */  return -EFAULT;}/* Changes the current file position. */static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig){/* *  orig 0: position from begning of eeprom *  orig 1: relative from current position *  orig 2: position from last eeprom address */    switch (orig)  {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -