📄 lcd_12232f.c.bak
字号:
/* Copyright (c) 2007,9,18 北京华龙通有限公司事业二部一室
*
* 文件名称:lcd12232F.c
* 摘 要:使用Avalon总线的4×4键盘底层驱动。
*
* 当前版本:v1.1.0
* 日期:2008年2月18日
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include "lcd_12232F.h"
#define SUCCESS 0
static int Device_Open = 0;
static char Message[BUF_LEN];
static char *Message_Ptr;
/*****************************************
* 定义用户程序访问外设接口函数
****************************************/
/*
* Function 1:device_open
*/
static int device_open(struct inode *inode, struct file *file)
{
if (Device_Open)
return -EBUSY;
Device_Open++;
Message_Ptr = Message;
try_module_get(THIS_MODULE);
return SUCCESS;
}
/*
* Function 2:device_release
*/
static int device_release(struct inode *inode, struct file *file)
{
Device_Open--;
module_put(THIS_MODULE);
return SUCCESS;
}
/*
* Function 3:device_read
*/
static ssize_t device_read(struct file *file,char __user * buffer,size_t length,loff_t * offset)
{
int bytes_read = 0;
if (*Message_Ptr == 0)
return 0;
while (length && *Message_Ptr) {
put_user(*(Message_Ptr++), buffer++);
length--;
bytes_read++;
}
return bytes_read;
}
/*
* Function 4:device_write
*/
static ssize_t device_write(struct file *file,const char __user * buffer, size_t length, loff_t * offset)
{
int ii;
unsigned char c;
//0x80=10000000;代表设定DDRAM第一行地址到地址计数器AC,
WriteNios(ADR_LCD_COMMAND,ADR_LCD_LINE1_OFFSET);
udelay(50);
//length为用户缓冲区的长度,BUF_LEN=16
for (ii = 0; ii < length && ii < BUF_LEN; ii++)
{
get_user(c, buffer + ii);
//将从用户空间得到的字符c写到LCD的Data Register中
WriteNios(ADR_LCD_DATA, (unsigned long) c);
udelay(50);
}
if (length < BUF_LEN) //当用户缓冲区长度小于或等于16bytes
{
//将第一行其它写成空,0x20的ASCII值为空
for (ii = length; ii < BUF_LEN; ii++)
{
WriteNios(ADR_LCD_DATA,0x20);
udelay(50);
}
//将第二行其它全部写成空,0x20的ASCII值为空
WriteNios(ADR_LCD_COMMAND,ADR_LCD_LINE2_OFFSET);
udelay(50);
for (ii = BUF_LEN; ii < BUF_LEN+BUF_LEN; ii++)
{
WriteNios(ADR_LCD_DATA,0x20);
udelay(50);
}
}
else //当用户缓冲区长度大于16bytes
{
//此时,用户数据已经将第一行写满,准备接着写第二行
WriteNios(ADR_LCD_COMMAND,ADR_LCD_LINE2_OFFSET);
udelay(50);
for (ii = BUF_LEN; ii < length && ii < BUF_LEN+BUF_LEN; ii++)
{
get_user(c, buffer + ii);
WriteNios(ADR_LCD_DATA,(unsigned long) c);
udelay(50);
}
if (length < BUF_LEN + BUF_LEN) //如果用户缓冲区数据长度小于或等于32bytes
{
//将第二行未写满的DDRAM写成空
for (ii = length; ii < BUF_LEN + BUF_LEN; ii++)
{
WriteNios(ADR_LCD_DATA, 0x20);
udelay(50);
}
}
}
//返回从用户段写入内核段数据的长度
return length;
}
/*
* Function 5:device_ioctl
*/
static int device_ioctl(struct inode *inode,struct file *file, unsigned int ioctl_num,unsigned long ioctl_param)
{
int i;
char *temp;
char ch;
switch (ioctl_num)
{
case IOCTL_WRITE: // 将temp指针指向用户空间的message数据,将这条信息设置为需要传递给LCD设备的信息
temp = (char *)ioctl_param; // 得到用户进程传递给ioctl函数的地址内的数据取出
get_user(ch, temp);
for (i = 0; ch && i < BUF_LEN + BUF_LEN; i++, temp++)
{
get_user(ch, temp);
} //解析这条message的长度,得到i值
if (i<BUF_LEN)
{
i=i-1;
}
device_write(file, (char *)ioctl_param, i, 0);
break;
case IOCTL_READ: //从LCD设备中读取内容到ioclt_param 地址所在的空间
i = device_read(file, (char *)ioctl_param, 99, 0);
put_user('\0', (char *)ioctl_param + i);
break;
case IOCTL_LCD_ON:
case IOCTL_LCD_OFF:
WriteNios(ADR_LCD_COMMAND,LCD_CMD_ONOFF);
mdelay(1);
break;
case IOCTL_LCD_CLEAR:
WriteNios(ADR_LCD_COMMAND,LCD_CMD_CLEAR);
mdelay(2);
break;
case IOCTL_LCD_RESET :
WriteNios(ADR_LCD_COMMAND,LCD_COM_RESET);
mdelay(5);
break;
case IOCTL_LCD_HOME:
WriteNios(ADR_LCD_COMMAND,LCD_CMD_HOME);
mdelay(1);
break;
case IOCTL_LCD_CURSOR_LEFT:
WriteNios(ADR_LCD_COMMAND,LCD_CMD_MODES);
mdelay(1);
break;
case IOCTL_LCD_CURSOR_RIGHT:
WriteNios(ADR_LCD_COMMAND,LCD_CMD_MODES | LCD_CMD_ONOFF_SHIFT);
mdelay(1);
break;
case IOCTL_LCD_CURSOR_ON:
WriteNios(ADR_LCD_COMMAND,LCD_CMD_ONOFF | LCD_CMD_ONOFF_CURSOR);
mdelay(1);
break;
case IOCTL_LCD_DISP_SHOW_ON:
WriteNios(ADR_LCD_COMMAND,LCD_CMD_ONOFF | LCD_CMD_ONOFF_DISP);
mdelay(1);
break;
case IOCTL_LCD_CURSOR_GET:
break;
case IOCTL_LCD_CURSOR_SET:
break;
case IOCTL_LCD_GET_CURSOR_POS:
break;
case IOCTL_LCD_SET_CURSOR_POS:
break;
case IOCTL_LCD_CURSOR_BLINK:
WriteNios(ADR_LCD_COMMAND,LCD_CMD_ONOFF | LCD_CMD_ONOFF_BLINK);
mdelay(1);
break;
case IOCTL_LCD_ROW1_BLINK:
break;
case IOCTL_LCD_DISP_LEFT:
break;
case IOCTL_LCD_DISP_RIGHT:
break;
case IOCTL_LCD_DISP_ON:
break;
case IOCTL_LCD_DISP_OFF:
break;
case IOCTL_LCD_LINE1:
WriteNios(ADR_LCD_COMMAND,ADR_LCD_LINE1_OFFSET);
udelay(50);
break;
case IOCTL_LCD_LINE2:
WriteNios(ADR_LCD_COMMAND,ADR_LCD_LINE2_OFFSET);
udelay(50);
break;
case IOCTL_LED_NORMAL:
WriteNios(0x02010850,LED_STATE_NORMAL);
udelay(50);
break;
case IOCTL_LCD_BACKGROUND_LED_OFF:
WriteNios(0x02010850,0x02);
udelay(50);
break;
case IOCTL_LCD_WARNING_LED_ON:
WriteNios(0x02010850,0x01);
udelay(50);
break;
}
return SUCCESS;
}
/* Module Declarations */
struct file_operations Fops = {
.read = device_read,
.write = device_write,
.ioctl = device_ioctl,
.open = device_open,
.release = device_release, /* a.k.a. close */
};
/*
* Initialize the module - Register the character device
*/
int init_module()
{
int ret_val; //int i; //unsigned long *p;
ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops);
if (ret_val < 0) {
printk(KERN_ALERT "%s failed with %d\n",
"Sorry, registering the character device ", ret_val);
return ret_val;
}
printk(KERN_INFO "Device %s registered\n", DEVICE_FILE_NAME);
mdelay(20);
WriteNios(ADR_LCD_COMMAND,LCD_COM_RESET);
mdelay(5);
WriteNios(ADR_LCD_COMMAND,LCD_COM_RESET);
udelay(200);
WriteNios(ADR_LCD_COMMAND,LCD_COM_RESET);
udelay(200); //在此之前,不能检查BF标志
WriteNios(ADR_LCD_COMMAND,LCD_NUMROWS | LCD_INTERFACE | LCD_CMD_FUNC); //00111000
udelay(50);
WriteNios(ADR_LCD_COMMAND,LCD_CMD_ONOFF); //显示状态开
udelay(50);
WriteNios(ADR_LCD_COMMAND,LCD_CMD_CLEAR); //清屏
mdelay(2);
//WriteNios(ADR_LCD_COMMAND,LCD_CMD_ONOFF | LCD_CMD_ONOFF_DISP | LCD_CMD_ONOFF_CURSOR | LCD_CMD_ONOFF_BLINK); WriteNios(ADR_LCD_COMMAND,LCD_CMD_ONOFF | LCD_CMD_ONOFF_DISP);
udelay(50);
//初始化液晶显示 /*for(i=0;i<16;i++) { p=0x02010850+i; *p=0x00; mdelay(200); }*/ WriteNios(0x02010850,0xff); mdelay(200);
WriteNios(ADR_LCD_DATA,0xb1);
udelay(50);
WriteNios(ADR_LCD_DATA,0xb1);
udelay(50);
WriteNios(ADR_LCD_DATA,0xbe);
udelay(50);
WriteNios(ADR_LCD_DATA,0xa9);
udelay(50);
WriteNios(ADR_LCD_DATA,0xbb);
udelay(50);
WriteNios(ADR_LCD_DATA,0xaa);
udelay(50);
WriteNios(ADR_LCD_DATA,0xc1);
udelay(50);
WriteNios(ADR_LCD_DATA,0xfa);
udelay(50);
WriteNios(ADR_LCD_DATA,0xcd);
udelay(50);
WriteNios(ADR_LCD_DATA,0xa8);
udelay(50);
WriteNios(ADR_LCD_COMMAND,ADR_LCD_LINE2_OFFSET);
udelay(50);
WriteNios(ADR_LCD_DATA,0xbb);
udelay(50);
WriteNios(ADR_LCD_DATA,0xb6);
udelay(50);
WriteNios(ADR_LCD_DATA,0xd3);
udelay(50);
WriteNios(ADR_LCD_DATA,0xad);
udelay(50);
WriteNios(ADR_LCD_DATA,0xc4);
udelay(50);
WriteNios(ADR_LCD_DATA,0xfa);
udelay(50);
return 0;
}
/*
* Cleanup - unregister the appropriate file from /proc
*/
void cleanup_module()
{
int ret;
/*
* Unregister the device
*/
ret = unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
/*
* If there's an error, report it
*/
if (ret < 0)
printk(KERN_ALERT "Error: unregister_chrdev: %d\n", ret);
}
int WriteNios(unsigned long addr, unsigned long value)
{
int ret = 0;
unsigned long data;
unsigned long *p = (unsigned long *)addr;
data = (unsigned long)(value);
ret = put_user(data, p);
return ret;
}
int ReadNios(unsigned long addr, unsigned long * pValue)
{
int ret = 0;
unsigned long *p = (unsigned long *)addr;
if (get_user(*pValue, p))
return -EFAULT;
return ret;
}
module_init(init_module);
module_exit(cleanup_module);
#define author "HLT of TCB: Department 2"
#define description "A driver for LCD12232F device of the satellite project."
MODULE_AUTHOR(author);
MODULE_DESCRIPTION(description);
MODULE_SUPPORTED_DEVICE(DEVICE_NAME);
MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -