📄 eepromdriver.c
字号:
#ifndef __KERNEL__#define __KERNEL__#endif#ifndef MODULE#define MODULE#endif#include <linux/config.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/module.h>#include <asm/irq.h> //disable && enable irq#include <asm/uaccess.h>//copy_from_user | to_user#include <linux/ioctl.h>#include <linux/fs.h> /* everything... */#include <asm/io.h>#include <linux/ioport.h>//ioremap#include <linux/sched.h>//wait_queue#include <linux/wait.h>#include <linux/mm.h>#include <linux/slab.h> //kmalloc#include <linux/interrupt.h>#include <linux/cdev.h>#include <linux/delay.h>#include <linux/time.h>#define DRIVER_VERSION "v1.0"MODULE_LICENSE("Dual BSD/GPL");#define INT8U unsigned char#define INT32U unsigned int#define INT32 signed int#define SMBUS_BASE 0x56fffff0volatile unsigned char *smbase_addr = NULL;#define SMBus_CLH (*((volatile INT8U *) smbase_addr+1))#define SMBus_CLL (*((volatile INT8U *) smbase_addr))#define SMBus_CON (*((volatile INT8U *) smbase_addr+2))#define SMBus_CMD (*((volatile INT8U *) smbase_addr+4))#define SMBus_TXR (*((volatile INT8U *) smbase_addr+3))#define SMBus_RXR (*((volatile INT8U *) smbase_addr+3))#define SMBus_STS (*((volatile INT8U *) smbase_addr+4))#define READ 0#define WRITE 1int eeprom_major = -1;struct eeprom_addr_string{ INT32U addr; INT32U num; //每一条目包含的字符数 char string[20]; //eeprom芯片AT24C02,256Byte。前16Byte用于存放mac //后240byte用于存放固件的ascii码 //固件版本每16byte作为一个条目,最多支持15个条目 //每个条目最大16个字符};void SMBus_Init(INT8U CLH,INT8U CLL);INT8U SMBus_SendStr(INT8U sla, INT8U suba, INT8U *s, INT8U no);INT8U SMBus_RecvStr(INT8U sla, INT8U suba, INT8U *s, INT8U no);void SMBus_Init(INT8U CLH,INT8U CLL){ SMBus_CLH = CLH; SMBus_CLL = CLL; SMBus_CON = 0xc0; // Enable SMBus and Interrupt Output}static int eeprom_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long argv){ struct eeprom_addr_string ras,was; memset (&ras,0,sizeof(struct eeprom_addr_string)); memset (&was,0,sizeof(struct eeprom_addr_string)); switch ( cmd ) //每次调用读写一个条目,最大16Byte { case WRITE: copy_from_user(&was,(void *)argv,sizeof(struct eeprom_addr_string)); printk("WRITE:addr:%x,num:%x,string:%s\n",was.addr,was.num,was.string); if ( was.num <= 8 ) SMBus_SendStr(0xa0, was.addr, was.string, was.num); else if ( 8 < was.num && was.num <= 16 ) {// printk("KERN:was.num:%d\n",was.num); SMBus_SendStr(0xa0, was.addr, &was.string[0], 8); mdelay(100); SMBus_SendStr(0xa0, was.addr+8, &was.string[8], was.num-8); } else { printk("Error:was.num=%d\n",was.num); return -1; } break; case READ: copy_from_user(&ras,(void *)argv,sizeof(struct eeprom_addr_string)); printk("READ:addr:%x,num:%x,string:%s\n",ras.addr,ras.num,ras.string); if ( ras.num <= 8 ) SMBus_RecvStr(0xa0, ras.addr, ras.string, ras.num); else if ( 8 < ras.num && ras.num <= 16 ) {// printk("KERN:ras.num:%d\n",ras.num); SMBus_RecvStr(0xa0, ras.addr, &ras.string[0], 8); mdelay(100); SMBus_RecvStr(0xa0, ras.addr+8, &ras.string[8], ras.num-8); } else { printk("Error:ras.num=%d\n",ras.num); return -1; }// printk("KERN:string:%s\n",ras.string); copy_to_user((void *)argv,&ras,sizeof(struct eeprom_addr_string)); break; default: printk("cmd error\n"); return -1; } return 0;}INT8U SMBus_SendStr(INT8U sla, INT8U suba, INT8U *s, INT8U no){ INT8U sla_ack, i; SMBus_TXR = sla; SMBus_CMD = 0x90; while ((SMBus_STS & 0x01) != 0x01); SMBus_CMD = 0x01; sla_ack = SMBus_STS & 0x80; if (sla_ack != 0x00) { return 0; } SMBus_TXR = suba; SMBus_CMD = 0x10; while ((SMBus_STS & 0x01) != 0x01); SMBus_CMD = 0x01; sla_ack = SMBus_STS & 0x80; if (sla_ack != 0x00) { return 0; } for (i = 0; i < no - 1; i++) { SMBus_TXR = *s; SMBus_CMD = 0x10; while ((SMBus_STS & 0x01) != 0x01); SMBus_CMD = 0x01; sla_ack = SMBus_STS & 0x80; if (sla_ack != 0x00) { return 0; } s++; } SMBus_TXR = *s; SMBus_CMD = 0x50; while ((SMBus_STS & 0x01) != 0x01); SMBus_CMD = 0x01; sla_ack = SMBus_STS & 0x80; if (sla_ack != 0x00) { return 0; } return 1;}INT8U SMBus_RecvStr(INT8U sla, INT8U suba, INT8U *s, INT8U no){ INT8U sla_ack, i; SMBus_TXR = sla; SMBus_CMD = 0x90; while ((SMBus_STS & 0x01) != 0x01); SMBus_CMD = 0x01; sla_ack = SMBus_STS & 0x80; if (sla_ack != 0x00) { return 0; } SMBus_TXR = suba; SMBus_CMD = 0x10; while ((SMBus_STS & 0x01) != 0x01); SMBus_CMD = 0x01; sla_ack = SMBus_STS & 0x80; if (sla_ack != 0x00) { return 0; } SMBus_TXR = sla + 1; SMBus_CMD = 0x90; while ((SMBus_STS & 0x01) != 0x01); SMBus_CMD = 0x01; sla_ack = SMBus_STS & 0x80; if (sla_ack != 0x00) { return 0; } for (i = 0; i < no - 1; i++) { SMBus_CMD = 0x20; while ((SMBus_STS & 0x01) != 0x01); SMBus_CMD = 0x01; if (sla_ack != 0x00) { return 0; } *s = SMBus_RXR; s++; } SMBus_CMD = 0x68; while ((SMBus_STS & 0x01) != 0x01); SMBus_CMD = 0x01; *s = SMBus_RXR; return(1);}struct file_operations eeprom_fops = { .owner = THIS_MODULE, .ioctl = eeprom_ioctl,};static int __init eeprom_init(void){ smbase_addr=(volatile unsigned char *)ioremap_nocache(SMBUS_BASE,5); eeprom_major = register_chrdev(231, "eeprom", &eeprom_fops); printk("eeprom_major:%d\n",eeprom_major); SMBus_Init(0x01, 0x00); printk("Hello EEPROM!\n"); return 0;}static void __exit eeprom_exit(void){ unregister_chrdev(eeprom_major, "eeprom"); iounmap((void *)smbase_addr); printk("Bye EEPROM.\n");}module_init(eeprom_init);module_exit(eeprom_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -