📄 i2c-tomega8.c
字号:
/* i2c-tomega8.c - i2c-bus driver, comunicate to mega8 MCU Written by Richard R.Zhang This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <linux/config.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/slab.h>#include <linux/version.h>#if LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0)#include <linux/smp_lock.h>#endif /* LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) */#ifdef CONFIG_DEVFS_FS#include <linux/devfs_fs_kernel.h>#endif/* If you want debugging uncomment: *//* #define DEBUG */#include <linux/init.h>#include <asm/uaccess.h>#include <linux/i2c.h>#include <linux/poll.h>#include <linux/delay.h>#include "dbg_msg.h"#include "i2c-tomega8.h"#include "cmd_kbd_mouse.h"/* debug macros */#undef DEBUG//#define DEBUG#ifdef DEBUG#define DPRINTK( x... ) printk("mcu: " ##x)#else#define DPRINTK( x... )#endifstatic void mega8_device_request (int devtype);static void mega8_device_release (int devtype);static int i2c_mega8_slvRcv( char *buf, int len, int begin);static int i2c_mega8_attach_adapter(struct i2c_adapter *adap);static int i2c_mega8_detach_client(struct i2c_client *client);static int i2c_mega8_command(struct i2c_client *client, unsigned int cmd, void *arg);static int __init i2c_mega8_init(void);static void i2c_mega8_cleanup(void);#define I2CDEV_ADAPS_MAX I2C_ADAP_MAXstatic struct i2c_adapter *i2cdev_adaps[I2CDEV_ADAPS_MAX];#ifdef CONFIG_DEVFS_FSstatic devfs_handle_t devfs_handle = NULL;#endifstatic struct i2c_driver i2c_mega8_driver = { name: "I2C Mega8 Driver", id: I2C_DRIVERID_I2CDEV, flags: I2C_DF_DUMMY, attach_adapter: i2c_mega8_attach_adapter, detach_client: i2c_mega8_detach_client, command: i2c_mega8_command,/* inc_use: NULL, dec_use: NULL, */};static struct i2c_client mega8_client = { name: "I2C Mega8", id: 1, flags: 0, addr: MEGA8_I2CADDRESS, adapter: NULL, driver: &i2c_mega8_driver, slvRecvNotify: i2c_mega8_slvRcv, };#ifdef CONFIG_I2C_MEGA8_MATRIX_KEYBOARD/***************************//* Mega8 Keyboard Driver Start *//***************************/static void mega8_kbd_raw (I2C_kbd *kbdcode);static ssize_t mega8_kbd_read (struct file *file, unsigned char *buf, size_t count, // +- modify loff_t *offset);static ssize_t mega8_kbd_write (struct file *file, const unsigned char *buf, size_t count, //+-modify loff_t *offset);static int mega8_kbd_open (struct inode *inode, struct file *file);static int mega8_kbd_release (struct inode *inode, struct file *file);static unsigned int mega8_kbd_poll(struct file *filp, struct poll_table_struct *wait);#define KBD_MINOR 10#define KBD_NAME "Mega8 Kbd"#define KEY_NULL 0#define KEY_DOWN 0x0#define KEY_UP 0x0080#define MAX_KBD_BUF 16 /* how many do we want to buffer */typedef unsigned char KBD_RET;typedef struct { unsigned int kbdmode; /*KEYSTATUS_UP KEYSTATUS_DOWN and KEYSTATUS_REPEAT*/ KBD_RET buf[MAX_KBD_BUF]; /* protect against overrun */ unsigned int head, tail; /* head and tail for queued events */ wait_queue_head_t wq; spinlock_t lock; unsigned short key;} KBD_DEV;static int kbdmajor=0;static KBD_DEV kbddev;#ifdef CONFIG_DEVFS_FSstatic devfs_handle_t kbd_devfs_handle;#endif#define BUF_HEAD (kbddev.buf[kbddev.head])#define BUF_TAIL (kbddev.buf[kbddev.tail])#define INCBUF(x,mod) ((++(x)) & ((mod) - 1))static struct file_operations mega8_kbd_fops = { owner: THIS_MODULE, read: mega8_kbd_read, write: mega8_kbd_write, open: mega8_kbd_open, release: mega8_kbd_release, poll: mega8_kbd_poll,};typedef struct{ unsigned short keyraw; unsigned short map2;}struct_KeyMap;static struct_KeyMap keycode_raw2map[]={/*F1*/ {0x30, 0x3b},/*F2*/ {0x28, 0x3c},/*F3*/ {0x20, 0x3d},/*F4*/ {0x18, 0x3e},/*F5*/ {0x10, 0x3f},/*F6*/ {0x08, 0x40},/*F7*/ {0x2f, 0x41},/*F8*/ {0x27, 0x42},/*F9*/ {0x1f, 0x43},/*F10*/ {0x17, 0x44},/*F11*/ {0x0f, 0x57},/*F12*/ {0x07, 0x58},/*1*/ {0x32, 0x02},/*2*/ {0x2a, 0x03},/*3*/ {0x22, 0x04},/*4*/ {0x35, 0x05},/*5*/ {0x2d, 0x06},/*6*/ {0x25, 0x07},/*7*/ {0x36, 0x08},/*8*/ {0x2e, 0x09},/*9*/ {0x26, 0x0a},/*0*/ {0x29, 0x0b},/*.*/ {0x31, 0x53},/*+*/ {0x19, 0x4e},/*-*/ {0x1a, 0x4a},/***/ {0x1d, 0x37},/* / */ {0x1e, 0xe035},/*=*/ {0x21, 0x0d},/*up*/ {0x0a, 0xe048},/*dwn*/ {0x09, 0xe050},/*lft*/ {0x11, 0xe04b},/*rgt*/ {0x01, 0xe04d},/*pgu*/ {0x16, 0xe049},/*pgd*/ {0x15, 0xe051},/*entr*/ {0x0d, 0x1c},/*BKSP*/ {0x0e, 0x0e},/*ESC*/ {0X06, 0X01},};static unsigned short keycode_map[64];#if 0={0x0000, 0x0000, 0x0000, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, /* 0 - 7 */0x003b, 0x0000, 0x0000, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, /* 8 - 15 */0x0041, 0x0008, 0x0000, 0x000a, 0x0035, 0xe049, 0x000e, 0x0001, /* 16 - 23 */0x0009, 0x0005, 0x0000, 0x0007, 0x0037, 0xe051, 0x001c, 0x0000, /* 24 - 31 */0x0006, 0x0002, 0x0000, 0x0004, 0x000c, 0x0000, 0xe048, 0x0000, /* 32 - 39 */0x0003, 0x0034, 0x0000, 0x000d, 0x004e, 0xe04b, 0xe050, 0xe04d, /* 40 - 47 */0x000b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 48 - 50 */};#endif#define CODE_MAP_SIZE (sizeof(keycode_map) / sizeof(unsigned short))static int mega8_kbd_convert (unsigned char originkey){ unsigned char pure = originkey & 0x7f; unsigned short act = (originkey & 0x80) ? KEY_DOWN : KEY_UP; if ( pure > CODE_MAP_SIZE) return -1; kbddev.key= keycode_map[pure] | act; DPRINTK ("key code :%x\t%x\n",originkey,kbddev.key); return 0;}static void mega8_kbd_raw (I2C_kbd *kbdcode){ int need = 1, empty; unsigned char *pcode =(unsigned char *)&(kbddev.key); if (!kbdcode) return; if (mega8_kbd_convert (kbdcode->key) < 0) return ; if (kbddev.key & 0xf000){ need = 2; } DPRINTK ("driver->code:0x%x\n", kbddev.key); if (kbddev.head > kbddev.tail) empty = MAX_KBD_BUF - (kbddev.head - kbddev.tail); else if (kbddev.head < kbddev.tail) empty = MAX_KBD_BUF - (kbddev.head + MAX_KBD_BUF - kbddev.tail); else empty = MAX_KBD_BUF; DPRINTK ("need:%d\tempty:%d\n", need, empty); if ( empty < need ) return; DPRINTK ("push L:%x\n", pcode[0]); DPRINTK ("push H:%x\n", pcode[1]); if (kbddev.key & 0xf000){ BUF_HEAD = pcode[1]; kbddev.head = INCBUF(kbddev.head, MAX_KBD_BUF); } BUF_HEAD = pcode[0]; kbddev.head = INCBUF(kbddev.head, MAX_KBD_BUF); DPRINTK ("head:%d\ttail:%d\n", kbddev.head, kbddev.tail); wake_up_interruptible(&(kbddev.wq));}static KBD_RET kbdRead(void){ KBD_RET kbd_ret; spin_lock_irq(&(kbddev.lock)); kbd_ret= BUF_TAIL; kbddev.tail = INCBUF(kbddev.tail, MAX_KBD_BUF); spin_unlock_irq(&(kbddev.lock)); return kbd_ret;}static unsigned int mega8_kbd_poll(struct file *filp, struct poll_table_struct *wait){ poll_wait(filp, &(kbddev.wq), wait); return (kbddev.head == kbddev.tail) ? 0 : (POLLIN | POLLRDNORM); }static ssize_t mega8_kbd_read (struct file *file, unsigned char *buf, size_t count, loff_t *offset){ KBD_RET kbd_ret;retry: if (kbddev.head != kbddev.tail) { kbd_ret = kbdRead(); copy_to_user(buf, (char *)&kbd_ret, sizeof(KBD_RET)); return sizeof(KBD_RET); } else { if (file->f_flags & O_NONBLOCK) return -EAGAIN; interruptible_sleep_on(&(kbddev.wq)); if (signal_pending(current)) return -ERESTARTSYS; goto retry; } return sizeof(KBD_RET);}static ssize_t mega8_kbd_write (struct file *file, const unsigned char *buf, size_t count, loff_t *offset){ return -1;}static int mega8_kbd_release (struct inode *inode, struct file *file){ mega8_device_release (DTYPE_MKEYB); return 0;}static int mega8_kbd_open (struct inode *inode, struct file *file){/* if (!mega8_kbd_client->adapter) return -ENODEV; if (mega8_kbd_client->adapter->inc_use) mega8_kbd_client->adapter->inc_use (mega8_kbd_client->adapter);*/ kbddev.head = kbddev.tail = 0; kbddev.kbdmode= KEY_NULL; init_waitqueue_head(&(kbddev.wq)); DPRINTK( "opened\n"); mega8_device_request (DTYPE_MKEYB); return 0;}#ifdef CONFIG_DEVFS_FSstatic devfs_handle_t mega8_kbd_init (devfs_handle_t i2c_root)#elsestatic int mega8_kbd_init ()#endif{ int ret, i; for(i=0;i<sizeof(keycode_raw2map)/sizeof(keycode_raw2map[0]);i++){ keycode_map[keycode_raw2map[i].keyraw]=keycode_raw2map[i].map2; }#ifdef DEBUG DPRINTK ( "key map \n"); for ( i = 0; i < 8; i ++){ int j; for (j = 0; j < 8; j++){ int index = i * 8 + j; DPRINTK ("%d,0x%x ", index, keycode_map[index]); } DPRINTK ("\n"); }#endif ret = register_chrdev(0, KBD_NAME, &mega8_kbd_fops); if (ret < 0) { DPRINTK(KBD_NAME" can't be registered\n");#ifdef CONFIG_DEVFS_FS return NULL;#else return ret;#endif } kbdmajor = ret;#ifdef CONFIG_DEVFS_FS kbd_devfs_handle = devfs_register (i2c_root, "kbd", DEVFS_FL_DEFAULT, kbdmajor, KBD_MINOR, S_IFCHR | S_IRUSR | S_IWUSR, &mega8_kbd_fops, NULL);#endif DPRINTK("Registered '%s' as minor %d\n","kbd", KBD_MINOR);#ifdef CONFIG_DEVFS_FS return kbd_devfs_handle;#else return 0;#endif}static void mega8_kbd_exit (void){#ifdef CONFIG_DEVFS_FS devfs_unregister(kbd_devfs_handle); kbd_devfs_handle = NULL;#endif unregister_chrdev(kbdmajor, KBD_NAME);}#endif //#ifdef CONFIG_I2C_MEGA8_MATRIX_KEYBOARD#ifdef CONFIG_I2C_MEGA8_IC_CARD/***************************//* Mega8 ic card Driver Start *//***************************/static void mega8_iccard_raw (I2C_ICCard*iccardframe);#if 0static unsigned int mega8_iccard_poll(struct file *filp, struct poll_table_struct *wait);#endifstatic loff_t mega8_iccard_llseek (struct file *file, loff_t offset, int orig);static int mega8_iccard_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static ssize_t mega8_iccard_read (struct file *file, char *buf, size_t count, // +- modify loff_t *offset);static ssize_t mega8_iccard_write (struct file *file, const char *buf, size_t count, //+-modify loff_t *offset);static int mega8_iccard_open (struct inode *inode, struct file *file);static int mega8_iccard_release (struct inode *inode, struct file *file);#define ICCARD_24C02_MINOR ICCARD_TYPE_AT24C02#define ICCARD_24C04_MINOR ICCARD_TYPE_AT24C04#define ICCARD_24C08_MINOR ICCARD_TYPE_AT24C08#define ICCARD_24C16_MINOR ICCARD_TYPE_AT24C16#define ICCARD_24C32_MINOR ICCARD_TYPE_AT24C32#define ICCARD_24C64_MINOR ICCARD_TYPE_AT24C64#define ICCARD_4442_MINOR ICCARD_TYPE_SLE4442#define ICCARD_24C02_NAME "iccard24c02"#define ICCARD_24C04_NAME "iccard24c04"#define ICCARD_24C08_NAME "iccard24c08"#define ICCARD_24C16_NAME "iccard24c16"#define ICCARD_24C32_NAME "iccard24c32"#define ICCARD_24C64_NAME "iccard24c64"#define ICCARD_4442_NAME "iccard4442"#define ICCARD_NAME "iccard"typedef struct { ICCARD_data iccard_data; int lasterrcode; wait_queue_head_t wq; spinlock_t lock;}ICCARD_DEV;typedef struct _iccard_dev_info{ unsigned char minor; char *devname; loff_t memsize;}ICCARD_DEV_INFO;ICCARD_DEV_INFO iccarddevinfo[]={ {ICCARD_24C02_MINOR, ICCARD_24C02_NAME, 256}, {ICCARD_24C04_MINOR, ICCARD_24C04_NAME, 512}, {ICCARD_24C08_MINOR, ICCARD_24C08_NAME, 1024}, {ICCARD_24C16_MINOR, ICCARD_24C16_NAME, 2048}, {ICCARD_24C32_MINOR, ICCARD_24C32_NAME, 4096}, {ICCARD_24C64_MINOR, ICCARD_24C64_NAME, 8192}, {ICCARD_4442_MINOR, ICCARD_4442_NAME, 256},};#define DEVNM_SIZE (sizeof (iccarddevinfo) / sizeof (ICCARD_DEV_INFO))static devfs_handle_t iccard_devfs_handle[DEVNM_SIZE];static ICCARD_DEV iccarddev;atomic_t atom_cnt;static int iccardmajor=0;static struct file_operations mega8_iccard_fops = { owner: THIS_MODULE, llseek: mega8_iccard_llseek, read: mega8_iccard_read, write: mega8_iccard_write, open: mega8_iccard_open, release: mega8_iccard_release,#if 0 poll: mega8_iccard_poll,#endif ioctl: mega8_iccard_ioctl,};static void mega8_iccard_raw (I2C_ICCard* iccardframe){ if (!iccardframe) return; DPRINTK ("iccardframe->cmd:0x%x\n", iccardframe->cmd); if(iccardframe->cmd==CMD_ICC_FAILED){ iccarddev.lasterrcode=iccardframe->iccard_errcode; DPRINTK ("iccard failed code:0x%x\n", iccarddev.lasterrcode); } else{ iccarddev.lasterrcode=ICC_FAILED_NULL; if(iccardframe->cmd==CMD_ICC_WRITE){ if(iccarddev.iccard_data.address == iccardframe->iccard_addr && iccarddev.iccard_data.cnt == iccardframe->iccard_cnt){ DPRINTK ("iccard write ok:address=0x%x, count=%d\n", iccarddev.iccard_data.address, iccarddev.iccard_data.cnt); } else{ DPRINTK ("iccard write error: address=0x%x vs 0x%x\n", iccarddev.iccard_data.address, iccardframe->iccard_addr); iccarddev.lasterrcode=ICC_FAILED_WRITEERR; } } else if(iccardframe->cmd==CMD_ICC_READ){ if(iccarddev.iccard_data.address == iccardframe->iccard_addr && iccarddev.iccard_data.cnt == iccardframe->iccard_cnt){ DPRINTK ("iccard read ok:address=0x%x, count=%d\n", iccarddev.iccard_data.address, iccarddev.iccard_data.cnt); memcpy(iccarddev.iccard_data.buffer, iccardframe->iccard_buf, iccarddev.iccard_data.cnt); } else{ DPRINTK ("iccard read error: address=0x%x vs 0x%x\n", iccarddev.iccard_data.address, iccardframe->iccard_addr); iccarddev.lasterrcode=ICC_FAILED_READERR; } } else if (iccardframe->cmd == CMD_ICC_VERIFY ){ unsigned char retcode = iccardframe->iccard_errcode; if (retcode){ iccarddev.lasterrcode = ICC_FAILED_VERIFYERR; }else{ iccarddev.lasterrcode = ICC_FAILED_NULL; } } } wake_up_interruptible(&(iccarddev.wq));}#if 0static unsigned int mega8_iccard_poll(struct file *filp, struct poll_table_struct *wait){ poll_wait(filp, &(iccarddev.wq), wait); return iccarddev.lasterrcode; }#endifstatic loff_t mega8_iccard_llseek(struct file *file,loff_t offset, int orig){ ICCARD_DEV_INFO *iccd= (ICCARD_DEV_INFO*)file->private_data; switch (orig) { case 0: /* SEEK_SET */ file->f_pos = offset; break; case 1: /* SEEK_CUR */ file->f_pos += offset; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -