📄 lcd_module.c
字号:
#include <linux/ioport.h>#ifdef KERNEL20#include <asm/segment.h>#include <linux/sched.h>#endif#ifdef KERNEL21#include <asm/uaccess.h>#endif#include <asm/io.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/delay.h>#include <asm/delay.h>#include <string.h>#include "version.h"#include "hardware.h"#include "c_table.h"/* * (c) 1998,1999 by Nils Faerber, GNU Public License applies *//* * Some globals */static int lcd_usage=0;static char dline=0,dcol=0;/* * Some prototypes */void pos_cursor(unsigned char, unsigned char);/* * Maybe this saves some cpu cycles and sysload*/static void sleep_delay(unsigned long n){/* Sleep nicely for 'n' uS */int d=n/(1000000/HZ); if(!d) udelay(n); else { /* Yield CPU time */ unsigned long x=jiffies; while((jiffies-x)<=d) schedule(); }}/* * LCD specific commands *//* * Set to instruction mode and write a command byte */void write_command(char command){ outb(15,LCD_ADDRESS+2); USLEEP(TIME_SHORT); outb(14,LCD_ADDRESS+2); /* set EN to 1 and RS to 0 */ USLEEP(TIME_SHORT); outb(command,LCD_ADDRESS); USLEEP(TIME_LONG); outb(15,LCD_ADDRESS+2); USLEEP(TIME_SHORT); if (command==1) USLEEP(3000); /* 1640 works on mine but others seem slower */}/* * Set data mode and write a data byte */void write_data(char data){ outb(12,LCD_ADDRESS+2); /* set EN to 1 and RS to 1 */ USLEEP(TIME_SHORT); /* write the data translated by c_table.h */ outb(c_table[(unsigned char)data],LCD_ADDRESS); USLEEP(TIME_LONG); outb(13,LCD_ADDRESS+2); /* clear out EN */ USLEEP(TIME_SHORT);}/* * Resets LCD panel and sets initial mode, i.e. * underline cursor, not blinking * one line mode * small font */void init_lcd(void){ USLEEP(15000); write_command(48); /* Set 8-bit mode */ USLEEP(4200); write_command(48); /* Set 8-bit mode */ USLEEP(200); write_command(48); /* Set 8-bit mode */ USLEEP(4200); write_command(56); /* Set 8-bit mode, font, matrix */ USLEEP(240); write_command(8); /* Set display off */ USLEEP(240); write_command(14);/*15*/ /* Set display on, cursor on */ USLEEP(1740); write_command(6); /* Set entry mode, cursor moves right, shift display */ USLEEP(240); write_command(1);}void init_cgram(void){unsigned int a,b; write_command(64); /* Move to first CD-RAM address */ /* We have 8x8 bytes for our own chars */ for (a=0; a<8; a++) { for (b=0; b<8; b++) { write_data(0); /* At init we clear the CG-RAM */ } } pos_cursor(dcol,dline);}void wr_cgram(char which, char *buf){unsigned int a; if (which<0 || which>7) return; write_command(64+(8*which)); /* Move to first CD-RAM address (char# * 8) */ /* We have 8x8 bytes for our own chars */ for (a=0; a<8; a++) { write_data(buf[a]); /* Write the 8 char-defining bytes */ } USLEEP(200); pos_cursor(dcol,dline); /* Bring us back to DD-RAM */}/* * Following functions are for tty like handling of the panel * i.e. set cursor position, clear display, home cursor, etc. *//* * Sets cursor to certain position * col = column [0-19] * line = line [0-3] */void pos_cursor(unsigned char col, unsigned char line){unsigned char offset=0;unsigned char pos=0; /* some sanity checking */ if (col>(LCD_COLS-1)) { col=0; line++; } if (line>(LCD_LINES-1)) line=0; /* line address offsets (weird, aren't they?) */ switch (line) { case 0: offset=0; break; case 1: offset=64; break; case 2: offset=20; break; case 3: offset=84; break; } /* Command for addressing is 128 so we add all this here */ pos=offset+col+128; /* Update our private position counter */ dline=line; dcol=col; /* now write it out */ write_command(pos);}/* * All functions after here are for device driver specific purposes *//* * Called when the device is open()ed */#ifdef KERNEL20static int lcd_open(struct inode *minode, struct file *file)#endif#ifdef KERNEL21int lcd_open(struct inode *minode, struct file *mfile)#endif{ if (lcd_usage!=0) return -EBUSY; MOD_INC_USE_COUNT; lcd_usage=1;#ifdef DEBUG printk("LCD opened\n");#endif return(0);}/* * Called when the device is close()ed */#ifdef KERNEL20static void lcd_release(struct inode *minode, struct file *mfile)#endif#ifdef KERNEL21int lcd_release(struct inode *minode, struct file *mfile)#endif{ MOD_DEC_USE_COUNT; lcd_usage=0;#ifdef DEBUG printk("LCD module closed\n");#endif#ifdef KERNEL21 return 0;#endif}/* * Called if data is to be written out to the device */#ifdef KERNEL20int lcd_write_byte(struct inode *minode, struct file *mfile, const char *gdata, int length)#endif#ifdef KERNEL21ssize_t lcd_write_byte(struct file *inode, const char *gdata, size_t length, loff_t *off_what)#endif{int i,cnt;const char *data;char cgenbuf[8];char c; data=gdata; for (i=0; i<length; i++) {#ifdef KERNEL20 c=get_user((char *)(data+i));#endif#ifdef KERNEL21 get_user(c,(char *)(data+i));#endif#ifdef DEBUG printk("LCD: starting %d\n",i); printk("LCD: which is '%c'\n",c);#endif if (c==10) { /* line feed */ dline++; dcol=0; pos_cursor(dcol,dline); } else if (c==27) { if ((i+1)<length) { i+=1;#ifdef KERNEL20 c=get_user((char *)(data+i));#endif#ifdef KERNEL21 get_user(c,(char *)(data+i));#endif if (c=='c') { write_command(1); dcol=0; dline=0; } else if (c=='h') { write_command(128); dcol=0; dline=0; } else if (c=='R') { init_lcd(); dcol=0; dline=0; } else if (c<8) {#ifdef DEBUG printk("Def.char\n");#endif if ((i+8)<length) { for (cnt=0; cnt<8; cnt++) {#ifdef KERNEL20 cgenbuf[cnt]=get_user((char *)(data+i+cnt+1));#endif#ifdef KERNEL21 get_user(cgenbuf[cnt],(char *)(data+i+cnt+1));#endif }; wr_cgram(c,cgenbuf); i+=8; }#ifdef DEBUG else printk("Def. too short\n");#endif } } } else if (c==13) { /* carriage return */ dcol=0; pos_cursor(dcol,dline); } else { write_data(c); dcol++; if (dcol>(LCD_COLS-1)) { dcol=0; dline++; pos_cursor(dcol,dline); } } } return(length);}/* * Called if data is to be read */#ifdef KERNEL20int lcd_read_byte(struct inode *inode, struct file *mfile, char *data, int length)#endif#ifdef KERNEL21ssize_t lcd_read_byte(struct file *inode, char *udata, size_t length, loff_t *loff_what)#endif{#ifdef DEBUG printk("LCD: Trying to read readonly device\n");#endif return(EACCES);/* sprintf(data,"%d %d\x004",dcol,dline); return(strlen(data));*/}/* * Called when module is unloaded */void cleanup_module(void){ release_region(LCD_ADDRESS,3); printk("LCD: I/O region freed\n"); if (unregister_chrdev(LCD_MAJOR,"LCD panel")) printk("LCD: module cleanup failed\n"); else printk("LCD: module cleanup succeeded\n");}/* * First function called when module is inserted */int init_module(void){#ifdef KERNEL20 static struct file_operations lcd_fops={NULL,lcd_read_byte,lcd_write_byte, NULL,NULL,NULL,NULL,lcd_open,lcd_release};#endif#ifdef KERNEL21 static struct file_operations lcd_fops={NULL,lcd_read_byte,lcd_write_byte, NULL,NULL,NULL,NULL,lcd_open,NULL,lcd_release};#endif if (register_chrdev(LCD_MAJOR,"LCD panel",&lcd_fops)) printk("unable to get major 120 for LCD device\n"); else { printk("LCD device %s init:\n",LCD_MODULE_VERSION); if (!check_region(LCD_ADDRESS,3)) { request_region(LCD_ADDRESS,3,"LCD panel"); printk(" got 3 addresses from %#x\n",LCD_ADDRESS); lcd_usage=0; init_lcd(); init_cgram(); dline=0; dcol=0; } else { release_region(LCD_ADDRESS,3); unregister_chrdev(LCD_MAJOR,"LCD panel"); printk(" could not get 3 addresses from %#x\n",LCD_ADDRESS); } } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -