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

📄 lcd_module.c

📁 LCD module driver
💻 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 + -