📄 eeprom.c
字号:
case 0: file->f_pos = offset; break; case 1: file->f_pos += offset; break; case 2: file->f_pos = eeprom.size - offset; break; default: return -EINVAL; } /* truncate position */ if (file->f_pos < 0) { file->f_pos = 0; return(-EOVERFLOW); } if (file->f_pos >= eeprom.size) { file->f_pos = eeprom.size - 1; return(-EOVERFLOW); } return ( file->f_pos );}/* Reads data from eeprom. */static int eeprom_read_buf(loff_t addr, char * buf, int count){ struct file f; f.f_pos = addr; return eeprom_read(&f, buf, count, &addr);}/* Reads data from eeprom. */static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t *off){ int read=0; unsigned long p = file->f_pos; unsigned char page; if(p >= eeprom.size) /* Address i 0 - (size-1) */ { return -EFAULT; } while(eeprom.busy) { interruptible_sleep_on(&eeprom.wait_q); /* bail out if we get interrupted */ if (signal_pending(current)) return -EINTR; } eeprom.busy++; page = (unsigned char) (p >> 8); if(!eeprom_address(p)) { printk(KERN_INFO "%s: Read failed to address the eeprom: " "0x%08X (%i) page: %i\n", eeprom_name, (int)p, (int)p, page); i2c_stop(); /* don't forget to wake them up */ eeprom.busy--; wake_up_interruptible(&eeprom.wait_q); return -EFAULT; } if( (p + count) > eeprom.size) { /* truncate count */ count = eeprom.size - p; } /* stop dummy write op and initiate the read op */ i2c_start(); /* special case for small eeproms */ if(eeprom.size < EEPROM_16KB) { i2c_outbyte( eeprom.select_cmd | 1 | (page << 1) ); } /* go on with the actual read */ read = read_from_eeprom( buf, count); if(read > 0) { file->f_pos += read; } eeprom.busy--; wake_up_interruptible(&eeprom.wait_q); return read;}/* Writes data to eeprom. */static int eeprom_write_buf(loff_t addr, const char * buf, int count){ struct file f; f.f_pos = addr; return eeprom_write(&f, buf, count, &addr);}/* Writes data to eeprom. */static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, loff_t *off){ int i, written, restart=1; unsigned long p; if (verify_area(VERIFY_READ, buf, count)) { return -EFAULT; } while(eeprom.busy) { interruptible_sleep_on(&eeprom.wait_q); /* bail out if we get interrupted */ if (signal_pending(current)) return -EINTR; } eeprom.busy++; for(i = 0; (i < EEPROM_RETRIES) && (restart > 0); i++) { restart = 0; written = 0; p = file->f_pos; while( (written < count) && (p < eeprom.size)) { /* address the eeprom */ if(!eeprom_address(p)) { printk(KERN_INFO "%s: Write failed to address the eeprom: " "0x%08X (%i) \n", eeprom_name, (int)p, (int)p); i2c_stop(); /* don't forget to wake them up */ eeprom.busy--; wake_up_interruptible(&eeprom.wait_q); return -EFAULT; }#ifdef EEPROM_ADAPTIVE_TIMING /* Adaptive algorithm to adjust timing */ if (eeprom.retry_cnt_addr > 0) { /* To Low now */ D(printk(">D=%i d=%i\n", eeprom.usec_delay_writecycles, eeprom.usec_delay_step)); if (eeprom.usec_delay_step < 4) { eeprom.usec_delay_step++; eeprom.usec_delay_writecycles += eeprom.usec_delay_step; } else { if (eeprom.adapt_state > 0) { /* To Low before */ eeprom.usec_delay_step *= 2; if (eeprom.usec_delay_step > 2) { eeprom.usec_delay_step--; } eeprom.usec_delay_writecycles += eeprom.usec_delay_step; } else if (eeprom.adapt_state < 0) { /* To High before (toggle dir) */ eeprom.usec_delay_writecycles += eeprom.usec_delay_step; if (eeprom.usec_delay_step > 1) { eeprom.usec_delay_step /= 2; eeprom.usec_delay_step--; } } } eeprom.adapt_state = 1; } else { /* To High (or good) now */ D(printk("<D=%i d=%i\n", eeprom.usec_delay_writecycles, eeprom.usec_delay_step)); if (eeprom.adapt_state < 0) { /* To High before */ if (eeprom.usec_delay_step > 1) { eeprom.usec_delay_step *= 2; eeprom.usec_delay_step--; if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step) { eeprom.usec_delay_writecycles -= eeprom.usec_delay_step; } } } else if (eeprom.adapt_state > 0) { /* To Low before (toggle dir) */ if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step) { eeprom.usec_delay_writecycles -= eeprom.usec_delay_step; } if (eeprom.usec_delay_step > 1) { eeprom.usec_delay_step /= 2; eeprom.usec_delay_step--; } eeprom.adapt_state = -1; } if (eeprom.adapt_state > -100) { eeprom.adapt_state--; } else { /* Restart adaption */ D(printk("#Restart\n")); eeprom.usec_delay_step++; } }#endif /* EEPROM_ADAPTIVE_TIMING */ /* write until we hit a page boundary or count */ do { i2c_outbyte(buf[written]); if(!i2c_getack()) { restart=1; printk(KERN_INFO "%s: write error, retrying. %d\n", eeprom_name, i); i2c_stop(); break; } written++; p++; } while( written < count && ( p % eeprom.sequential_write_pagesize )); /* end write cycle */ i2c_stop(); i2c_delay(eeprom.usec_delay_writecycles); } /* while */ } /* for */ eeprom.busy--; wake_up_interruptible(&eeprom.wait_q); if (written == 0 && file->f_pos >= eeprom.size){ return -ENOSPC; } file->f_pos += written; return written;}/* Closes the device. */static int eeprom_close(struct inode * inode, struct file * file){ /* do nothing for now */ return 0;}/* Sets the current address of the eeprom. */static int eeprom_address(unsigned long addr){ int i; unsigned char page, offset; page = (unsigned char) (addr >> 8); offset = (unsigned char) addr; for(i = 0; i < EEPROM_RETRIES; i++) { /* start a dummy write for addressing */ i2c_start(); if(eeprom.size == EEPROM_16KB) { i2c_outbyte( eeprom.select_cmd ); i2c_getack(); i2c_outbyte(page); } else { i2c_outbyte( eeprom.select_cmd | (page << 1) ); } if(!i2c_getack()) { /* retry */ i2c_stop(); /* Must have a delay here.. 500 works, >50, 100->works 5th time*/ i2c_delay(MAX_WRITEDELAY_US / EEPROM_RETRIES * i); /* The chip needs up to 10 ms from write stop to next start */ } else { i2c_outbyte(offset); if(!i2c_getack()) { /* retry */ i2c_stop(); } else break; } } eeprom.retry_cnt_addr = i; D(printk("%i\n", eeprom.retry_cnt_addr)); if(eeprom.retry_cnt_addr == EEPROM_RETRIES) { /* failed */ return 0; } return 1;}/* Reads from current address. */static int read_from_eeprom(char * buf, int count){ int i, read=0; for(i = 0; i < EEPROM_RETRIES; i++) { if(eeprom.size == EEPROM_16KB) { i2c_outbyte( eeprom.select_cmd | 1 ); } if(i2c_getack()) { break; } } if(i == EEPROM_RETRIES) { printk(KERN_INFO "%s: failed to read from eeprom\n", eeprom_name); i2c_stop(); return -EFAULT; } while( (read < count)) { if (put_user(i2c_inbyte(), &buf[read++])) { i2c_stop(); return -EFAULT; } /* * make sure we don't ack last byte or you will get very strange * results! */ if(read < count) { i2c_sendack(); } } /* stop the operation */ i2c_stop(); return read;}/* Disables write protection if applicable. */#define DBP_SAVE(x)#define ax_printf printkstatic void eeprom_disable_write_protect(void){ /* Disable write protect */ if (eeprom.size == EEPROM_8KB) { /* Step 1 Set WEL = 1 (write 00000010 to address 1FFFh */ i2c_start(); i2c_outbyte(0xbe); if(!i2c_getack()) { DBP_SAVE(ax_printf("Get ack returns false\n")); } i2c_outbyte(0xFF); if(!i2c_getack()) { DBP_SAVE(ax_printf("Get ack returns false 2\n")); } i2c_outbyte(0x02); if(!i2c_getack()) { DBP_SAVE(ax_printf("Get ack returns false 3\n")); } i2c_stop(); i2c_delay(1000); /* Step 2 Set RWEL = 1 (write 00000110 to address 1FFFh */ i2c_start(); i2c_outbyte(0xbe); if(!i2c_getack()) { DBP_SAVE(ax_printf("Get ack returns false 55\n")); } i2c_outbyte(0xFF); if(!i2c_getack()) { DBP_SAVE(ax_printf("Get ack returns false 52\n")); } i2c_outbyte(0x06); if(!i2c_getack()) { DBP_SAVE(ax_printf("Get ack returns false 53\n")); } i2c_stop(); /* Step 3 Set BP1, BP0, and/or WPEN bits (write 00000110 to address 1FFFh */ i2c_start(); i2c_outbyte(0xbe); if(!i2c_getack()) { DBP_SAVE(ax_printf("Get ack returns false 56\n")); } i2c_outbyte(0xFF); if(!i2c_getack()) { DBP_SAVE(ax_printf("Get ack returns false 57\n")); } i2c_outbyte(0x06); if(!i2c_getack()) { DBP_SAVE(ax_printf("Get ack returns false 58\n")); } i2c_stop(); /* Write protect disabled */ }}module_init(eeprom_init);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -