LCD 驱动源码完全注释
lcd_struct.h
/*****************************
定义LCD所用数据结构
******************************/
#ifndef _LCD_STRUC_DEF
#define _LCD_STRUC_DEF
/* LCD颜色类型
* COLOR[0-3] : 红
* COLOR[4-7] : 绿
* COLOR[8-11] : 蓝
* COLOR[12-15]: 保留半字节
*/
//typedef unsigned short COLOR;
typedef unsigned int COLOR;
// 保存屏幕缓冲区结构
struct save_struct
{
int save_w;
int save_h;
unsigned char * save_buf;
};
// LCD显示命令的参数结构
struct lcd_display
{
int x1, y1; /* 第一个点的x, y坐标 */
int x2, y2; /* 第二个点的x, y坐标 */
unsigned char * lcd_buf; //add by ywc
int lcd_buf_size;
int lcd_row;
unsigned char codes[32]; /* 字符点阵数据 */
COLOR color; /* 显示颜色 */
};
// LCD屏幕命令的参数结构
struct lcd_screen
{
int x1, y1; /* 第一个点的x, y坐标 */
int x2, y2; /* 第二个点的x, y坐标 */
struct save_struct * buffer; /* 保存屏幕缓冲区 */
};
#endif // _LCD_STRUC_DEF
ep7312_sys.h
/***************************
定义ep7312系统寄存器
***************************/
#ifndef _SYS_EP7312_REG
#define _SYS_EP7312_REG
#define SYSCON1 *(unsigned long*)0xff000100 /* 系统寄存器1 */
#define SYSCON2 *(unsigned long*)0xff001100 /* 系统寄存器2 */
#define PADR *(unsigned char*)0xff000000 /* 端口A数据寄存器 */
#define PADDR *(unsigned char*)0xff000040 /* 端口A方向寄存器 */
#define PBDR *(unsigned char*)0xff000001 /* 端口B数据寄存器 */
#define PBDDR *(unsigned char*)0xff000041 /* 端口B方向寄存器 */
#define LCDCON *(unsigned long*)0xff0002c0 /* LCD控制寄存器 */
#define PALLSW *(unsigned long*)0xff000540 /* 调色板颜色寄存低位有效字 */
#define PALMSW *(unsigned long*)0xff000580 /* 调色板颜色寄存高位有效字 */
#define FBADDR *(unsigned long*)0xff001000 /* LCD显示帧缓存起始地址 */
#define COM2DATA *(volatile unsigned char *)0xff001480 /* 串口2数据寄存器 */
#define COM2CONTROL *(volatile unsigned long *)0xff001140 /* 串口2控制寄存器 */
#define INTSR *(unsigned long *)0xff000240
#define EINT2 0x00000040
#endif //_SYS_EP7312_REG
lcd_drv.c
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <asm/fcntl.h>
#include <asm/unistd.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include "ep7312_sys.h"
#include "lcd_struct.h"
// ioctl 命令ID
#define LCD_Clear 0
#define LCD_Draw_Pixel 1
#define LCD_Draw_VLine 2
#define LCD_Draw_HLine 3
#define LCD_Draw_Rectangle 4
#define LCD_Draw_Buf 5
#define LCD_Write_EN 10
#define LCD_Write_CN 11
#define LCD_Save_SCR 12
#define LCD_Load_SCR 13
#define LCD_Release_SCR 14
// 定义LCD的主设备号
#define DEV_MAJOR 60
// 定义LCD显示模式参数
//#define SCR_X 160 /* LCD屏幕宽度 */
//#define SCR_Y 160 /* LCD屏幕高度 */
#define SCR_X 320 /* LCD屏幕宽度 */
#define SCR_Y 240 /* LCD屏幕高度 */
//#define BPP 32 /* LCD显示模式 */
//#define BPP 16 /* LCD显示模式 */
//#define BPP 24 /* LCD显示模式 */
//#define BPP 8 /* LCD显示模式 */
#define BPP 4 /* LCD显示模式 */
//#define BPP 2 /* LCD显示模式 */
//#define BPP 1 /* LCD显示模式 */
// 半字节复制标志
#define LowS 0 /* 取字节低四位标志 */
#define HighS 1 /* 取字节高四位标志 */
// LCD显示缓存的基址
static unsigned char * __lcd_base;
/* 设置LCD寄存器 */
static void setup_lcd(void)
{
// 禁用LCD设备
SYSCON1 &= ~0x00001000;
// 设置LCD控制寄存器
// 显示缓存容量[0:12] : 320 * 240 * 12 / (8*16) = 0x1c1f
// 线长度[13:18] : 320 / 16 - 1 = 0x13
// 像素预定标[19:24] : 0x01
// AC预定标[25:29] : 0x13
// 灰度使能[30] : = 1, 使用灰度级显示
// 灰度级模式[31] : = 1, 4 bpp模式(16灰度级)
//LCDCON = 0xe60f7c1f;
// LCDCON = 0xe60a7c1f; //320*720
//LCDCON =0xe60a6257; //320x240x1
// LCDCON =0xe60920c8; //160x160x1
// LCDCON =0xe60a64af; //320x240x2
LCDCON =0xe60a695f; //320x240x4
//LCDCON =0xe60a72bf; //320x240x8
// LCDCON =0xe60a72bf; //320x240x16/(8*32)
// LCDCON =0xe60a7c1f; //320x240x24/(8*32)
// LCDCON =0xe60a72bf; //320x240x32/(8*64)
// 设置调色板颜色寄存器的低位和高位有效字
PALLSW = 0x76543210; /* 低位有效字 */
PALMSW = 0xfedcba98; /* 高位有效字 */
// 设置LCD显示缓冲区在系统存储区域的起始位置
FBADDR = 0xc;
// 启用LCD设备
SYSCON1 |= 0x00001000;
return;
}
// 限制横坐标范围
// 使横坐标在0至SCR_X之间
static int xFormat(int x)
{
int fx;
fx = x;
fx = (fx < 0) ? 0 : fx;
fx = (fx >= SCR_X) ? (SCR_X - 1) : fx;
return fx;
}
// 限制纵坐标范围
// 使纵坐标在0至SCR_Y之间
static int yFormat(int y)
{
int fy;
fy = y;
fy = (fy < 0) ? 0 : fy;
fy = (fy >= SCR_Y) ? (SCR_Y - 1) : fy;
return fy;
}
// 释放保存屏幕缓冲区
static void lcd_kernel_release_screen(struct save_struct * buffer)
{
if ((*buffer).save_buf != NULL)
{
// 释放缓冲区
kfree((*buffer).save_buf);
// 恢复缓冲区初始化设置
(*buffer).save_buf = NULL;
(*buffer).save_w = (*buffer).save_h = 0;
}
}
// 保存屏幕部分区域的内容
static void lcd_kernel_save_screen(int x1, int y1, int x2, int y2, struct save_struct * buffer)
{
unsigned char * fb_lptr; /* 每行第一个点的显存地址 */
unsigned char bufferByte; /* 临时缓存字节 */
long buffer_size; /* 保存屏幕缓冲区的字节数 */
int factorCount; /* 每行需要存取的半字节的个数 */
int sb_sign, fb_sign; /* 半字节复制标志, = LowS: 复制低四位, = HighS: 复制高四位*/
int p_sb; /* 保存屏幕缓冲区指针偏移量 */
int p_fb; /* 显示缓冲区指针偏移量 */
int currLine; /* 当前行的纵坐标 */
int tmp, i;
// 修正保存范围坐标, 使其在屏幕的显示范围之内
x1 = xFormat(x1);
x2 = xFormat(x2);
y1 = yFormat(y1);
y2 = yFormat(y2);
// 修正保存范围的横坐标, 使x2值永远大于x1的值
if (x1 > x2)
{
tmp = x1;
x1 = x2;
x2 = tmp;
}
// 修正保存范围的纵坐标, 使y2值永远大于y1的值
if (y1 > y2)
{
tmp = y1;
y1 = y2;
y2 = tmp;
}
// 计算新保存的屏幕的宽度和高度
(*buffer).save_w = x2 - x1 + 1;
(*buffer).save_h = y2 - y1 + 1;
// 计算新缓冲区大小
buffer_size = (*buffer).save_w * (*buffer).save_h * 3 * BPP / 8 + 1;
// 申请新的屏幕缓冲区
(*buffer).save_buf = kmalloc(buffer_size, GFP_KERNEL);
// 初始化保存屏幕半字节复制标志
sb_sign = LowS;
// 计算每行中半字节的个数
factorCount = (*buffer).save_w * 3;
// 初始化屏幕缓冲区指针偏移量
p_sb = 0;
// 复制显存的内容到保存屏幕缓冲区中
for (currLine = y1; currLine <= y2; currLine++)
{
// 计算当前行第一个点的显存地址
fb_lptr = __lcd_base + (x1 + currLine * SCR_X) * 3 * BPP / 8;
// 初始化显存半字节复制标志
fb_sign = (x1 & 0x1);
// 初始化显示缓冲区指针偏移量
p_fb = 0;
// 复制显存当前行的内容
for (i = 0; i < factorCount; i++)
{
// 临时缓冲字节清零
bufferByte &= 0x00;
// 根据显存半字节复制标志, 将显存中当前字节的内容的低四位(或高四位)
// 复制到临时缓冲字节的低四位中
if (fb_sign == LowS)
bufferByte = (fb_lptr[p_fb] & 0x0f);
else
bufferByte = (fb_lptr[p_fb] & 0xf0) >> 4;
// 根据保存屏幕缓冲区半字节复制标志,
// 对保存屏幕缓冲区当前字节中相应的四位清零;
// 如果是要复制高四位的内容,
// 还要将临时缓冲字节的低四位内容移到高四位中
if (sb_sign == HighS)
{
(*buffer).save_buf[p_sb] &= 0x0f;
bufferByte = bufferByte << 4;
}
else
(*buffer).save_buf[p_sb] &= 0xf0;
// 用临时缓冲字节更新保存屏幕缓冲区的当前字节
(*buffer).save_buf[p_sb] |= bufferByte;
// 根据半字节复制标志, 设置相应的指针偏移量
if (fb_sign == HighS)
p_fb++;
if (sb_sign == HighS)
p_sb++;
// 更新半字节复制标志
sb_sign ^= 0x1;
fb_sign ^= 0x1;
}
}
}
// 加载屏幕部分区域的内容
static void lcd_kernel_load_screen(int x1, int y1, struct save_struct buffer)
{
unsigned char * fb_lptr; /* 每行第一个点的显存地址 */
unsigned char bufferByte; /* 临时缓存字节 */
int factorCount; /* 每行需要存取的半字节的个数 */
int sb_sign, fb_sign; /* 半字节复制标志, = LowS: 复制低四位, = HighS: 复制高四位*/
int p_sb; /* 保存屏幕缓冲区指针偏移量 */
int p_fb; /* 显示缓冲区指针偏移量 */
int x2, y2; /* 加载区域右下角的坐标 */
int currLine; /* 当前行的纵坐标 */
int i;
// 修正加载范围坐标, 使其在屏幕的显示范围之内
x1 = xFormat(x1);
y1 = xFormat(y1);
// 计算加载范围右下角的坐标
x2 = x1 + buffer.save_w - 1;
y2 = y1 + buffer.save_h - 1;
// 如果加载范围超出屏幕的显示范围
// 则不作任何操作返回
if (x2 >= SCR_X || y2 >= SCR_Y)
{
printk(KERN_INFO "Load position out of screen boundary!\n");
return;
}
// 如果尚未执行保存屏幕的操作,
// 则不作任何操作返回
if (buffer.save_buf == NULL)
{
printk(KERN_INFO "No Saved Screen!\n");
return;
}
// 初始化保存屏幕半字节复制标志
sb_sign = LowS;
// 计算每行中半字节的个数
factorCount = buffer.save_w * 3;
// 初始化屏幕缓冲区指针偏移量
p_sb = 0;
// 加载保存屏幕缓冲区的内容到显存中
for (currLine = y1; currLine <= y2; currLine++)
{
// 计算当前行第一个点的显存地址
fb_lptr = __lcd_base + (x1 + currLine * SCR_X) * 3 * BPP / 8;
// 初始化显存半字节复制标志
fb_sign = (x1 & 0x1);
// 初始化显示缓冲区指针偏移量
p_fb = 0;
// 加载当行的内容到显存中
for (i = 0; i < factorCount; i++)
{
// 临时缓冲字节清零
bufferByte &= 0x00;
// 根据保存屏幕半字节复制标志, 将保存屏幕缓冲区中
// 当前字节的内容的低四位(或高四位)
// 复制到临时缓冲字节的低四位中
if (sb_sign == LowS)
bufferByte = (buffer.save_buf[p_sb] & 0x0f);
else
bufferByte = (buffer.save_buf[p_sb] & 0xf0) >> 4;
// 根据显存半字节复制标志,
// 对显存当前字节中相应的四位清零;
// 如果是要复制高四位的内容,
// 还要将临时缓冲字节的低四位内容移到高四位中
if (fb_sign == HighS)
{
fb_lptr[p_fb] &= 0x0f;
bufferByte = bufferByte << 4;
}
else
fb_lptr[p_fb] &= 0xf0;
// 用临时缓冲字节更新显存内容
fb_lptr[p_fb] |= bufferByte;
// 根据半字节复制标志, 设置相应的指针偏移量
if (fb_sign == HighS)
p_fb++;
if (sb_sign == HighS)
p_sb++;
// 更新半字节复制标志
sb_sign ^= 0x1;
fb_sign ^= 0x1;
}
}
}
// 绘制一个像素点
static void lcd_kernel_pixel(int x, int y, COLOR color)
{
unsigned char* fb_ptr; /* 更新像素点对应的显存地址 */
unsigned short* fb_ptr_halfword;
unsigned int* fb_ptr_word;
unsigned int pointeraddr;
//COLOR pure_color=0x0000;
unsigned char pure_color_byte = 0x00; /* 更新颜色信息 */
unsigned short pure_color_halfword = 0x0000;
unsigned int pure_color_word = 0x00000000;
// 如果坐标越界则不做任何操作, 直接返回
if ( x < 0 || x >= SCR_X|| y < 0 || y >= SCR_Y)
{
printk("out of bounds\n");
return;
}
// 计算当前点对应的显存地址
//fb_ptr = __lcd_base + (x + y * SCR_X) * 3 * BPP / 8;
fb_ptr = __lcd_base + (x + y * SCR_X) * 1 * BPP / 8; //by ywc 4bpp,8bpp
fb_ptr_halfword = (unsigned short *)(__lcd_base + (x + y * SCR_X) * 1 * BPP / 8);//by ywc
pointeraddr = (((unsigned int )(__lcd_base + (x + y * SCR_X) * 1 * BPP / 8)));//by ywc
fb_ptr_word =(unsigned int *)(pointeraddr&~0x3);
//fb_ptr_word =__lcd_base + (x + y * SCR_X) * 1 * BPP / (8);
switch (BPP) {
case 1:
switch(x & 0x07){
case 0:
pure_color_byte = (color & 0x01 ) <<0; // add by ywc
*(fb_ptr) &= 0xfe;
*(fb_ptr) |= pure_color_byte;
break;
case 1:
pure_color_byte = (color & 0x01 ) <<1; // add by ywc
*(fb_ptr) &= 0xfd;
*(fb_ptr) |= pure_color_byte;
break;
case 2:
pure_color_byte = (color & 0x01 ) <<2; // add by ywc
*(fb_ptr) &= 0xfb;
*(fb_ptr) |= pure_color_byte;
break;
case 3:
pure_color_byte = (color & 0x01 ) <<3; // add by ywc
*(fb_ptr) &= 0xf7;
*(fb_ptr) |= pure_color_byte;
break;
case 4:
pure_color_byte = (color & 0x01 ) <<4; // add by ywc
*(fb_ptr) &= 0xef;
*(fb_ptr) |= pure_color_byte;
break;
case 5:
pure_color_byte = (color & 0x01 ) <<5; // add by ywc
*(fb_ptr) &= 0xdf;
*(fb_ptr) |= pure_color_byte;
break;
case 6:
pure_color_byte = (color & 0x01 ) <<6; // add by ywc
*(fb_ptr) &= 0xbf;
*(fb_ptr) |= pure_color_byte;
break;
case 7:
pure_color_byte = (color & 0x01 ) <<7; // add by ywc
*(fb_ptr) &= 0x7f;
*(fb_ptr) |= pure_color_byte;
break;
}
break;
case 2:
switch(x & 0x03){
case 0:
pure_color_byte = (color & 0x03 ) <<0; // add by ywc
*(fb_ptr) &= 0xfc;
*(fb_ptr) |= pure_color_byte;
break;
case 1:
pure_color_byte = (color & 0x03 ) <<2; // add by ywc
*(fb_ptr) &= 0xf3;
*(fb_ptr) |= pure_color_byte;
break;
case 2:
pure_color_byte = (color & 0x03 ) <<4; // add by ywc
*(fb_ptr) &= 0xcf;
*(fb_ptr) |= pure_color_byte;
break;
case 3:
pure_color_byte = (color & 0x03 ) <<6; // add by ywc
*(fb_ptr) &= 0x3f;
*(fb_ptr) |= pure_color_byte;
break;
}
break;
case 4:
if (x & 0x1)
{
pure_color_byte = (color & 0x0f) << 4; // add by ywc
*fb_ptr &= 0x0f;
*fb_ptr |= pure_color_byte;
}
else
{
pure_color_byte = ( color & 0x0f ); // add by ywc
*(fb_ptr) &= 0xf0;
*(fb_ptr) |= pure_color_byte;
}
break;
case 8:
pure_color_byte = ( color & 0xff); // why not ? by ywc
*(fb_ptr) = pure_color_byte;
break;
case 15:
break;
case 16:
pure_color_halfword = ( color & 0xffff); // why not ? by ywc
if(y==212)printk("color=%8x,fb_ptr_halfword=%p\n",color,fb_ptr_halfword);
*(fb_ptr_halfword) = pure_color_halfword;
break;
/* case 24:
printk("color=%8x,fb_ptr_word=%p\n",color,fb_ptr);
*(fb_ptr) = ( color & 0x0000ff); // 24 bit=3 byte;
*(fb_ptr+1) = ( color & 0x00ff00)>>4;
*(fb_ptr+2) = ( color & 0xff0000)>>8;
printk("pure_color_word=%8x\n",pure_color_word);
break;
*/
case 32:
pure_color_word = ( color & 0x00ffffff); // why not ? by ywc
// if(y==212)
printk("color=%8x,fb_ptr_word=%p\n",color,fb_ptr_word);
*(fb_ptr_word) = pure_color_word;
break;
default:
break;
}
//pure_color = ( color & 0x00ff); // why not ? by ywc
//*(fb_ptr) = pure_color;
// 更新像素点的颜色信息
// 处理x坐标为奇数的情况
/* if (x & 0x1)
{
pure_color = (color & 0x000f) << 4; // add by ywc
*fb_ptr &= 0x0f;
*fb_ptr |= pure_color;
}
// 处理x坐标为偶数的情况
else
{
pure_color = ( color & 0x000f ); // add by ywc
*(fb_ptr) &= 0xf0;
*(fb_ptr) |= pure_color;
}
*/
return;
}
// 绘制一条垂直直线
static void lcd_kernel_vline(int x, int y1, int y2, COLOR color)
{
int tmp;
int i = 0;
// 如果起始点的y坐标大于终止点的y坐标, 则交换起始点和终止点
if (y1 > y2)
{
tmp = y1;
y1 = y2;
y2 = tmp;
}
// 计算两点的垂直距离
tmp = y2 - y1;
// 用点组成垂直的直线
for (i = 0; i <= tmp; i++ )
{
lcd_kernel_pixel(x, y1 + i,color);
}
return;
}
// 绘制一条水平直线
static void lcd_kernel_hline(int x1, int x2, int y, COLOR color)
{
int tmp;
int i = 0;
// 如果起始点的x坐标大于终止点的x坐标, 则交换起始点和终止点
if (x1 > x2)
{
tmp = x1;
x1 = x2;
x2 = tmp;
}
// 计算两点的水平距离
tmp = x2 - x1;
// 用点组成水平的直线
for (i = 0; i <= tmp; i++ )
{
lcd_kernel_pixel(x1 + i, y, color);
}
return;
}
// 绘制一个矩形边框
// 边框左上角坐标为(start_x, start_y)
// 边框右下角坐标为(end_x, end_y))
static void lcd_kernel_rectangle(int start_x,int start_y,int end_x,int end_y,COLOR color)
{
lcd_kernel_vline(start_x, start_y, end_y, color); /* 绘制左边框 */
lcd_kernel_vline(end_x, start_y, end_y, color); /* 绘制右边框 */
lcd_kernel_hline(start_x, end_x, start_y, color); /* 绘制上边框 */
lcd_kernel_hline(start_x, end_x, end_y, color); /* 绘制下边框 */
return;
}
// 显示一个ASCII字符
// codes为指定ASCII字符的8 x 16点阵数组
static void lcd_kernel_text_en(int x, int y, unsigned char* codes, COLOR color)
{
int i, j;
// 显示8 x 16的点阵
for (i = 0;i < 16; i++)
{
// 移动x坐标至要显示的字符的右侧的边界上
x += 8;
// 从左向右显示一行点
for (j = 0; j < 8; j++)
{
// x坐标向左移一个像素
x--;
// 根据点阵信息显示一个指定颜色的点
if ((codes[i] >> j) & 0x1)
{
lcd_kernel_pixel(x, y, color);
}
}
// 开始显示新的一行, y坐标向下移一个像素
y++;
}
return;
}
// 显示一个中文字符
// codes为指定中文字符的16 * 16点阵数组
static void lcd_kernel_text_chs(int x, int y, unsigned char* codes, COLOR color)
{
int i, j, k;
// 显示16 * 16的点阵
for(i = 0;i < 16; i++)
{
// 循环两次,
// 先显示字符的左半部分的一行,
// 然后显示字符的右半部分的一行
for (j = 0; j < 2; j++)
{
// 计算x坐标的位置
// 左半部分的起始点为x + 8
// 右半部分的起始点为x + 16
x += 8 * ( j + 1);
// 从左向右显示左(右)半部分的一行
for (k = 0; k < 8; k++)
{
// x坐标向左移一个像素
x--;
// 根据点阵信息显示一个指定颜色的点
// codes[2 * i + j]计算行点阵在数组中的位置:
// 2 * i + 0 为左半部分的行点阵信息
// 2 * i + 1 为右半部分的行点阵信息
if ((codes[2 * i + j] >> k) & 0x1)
{
lcd_kernel_pixel(x,y,color);
}
}
}
// 开始显示新的一行,
// x坐标回到原先位置,
// y坐标向下移一个像素
x -= 8;
++y;
}
return;
}
// 用指定颜色清屏
static void lcd_kernel_clear(COLOR color)
{
unsigned char buffer[3];
long i;
COLOR pure_color;
printk("\nclear the screen to color '%d' !!!\n",color);
pure_color=color&0x0000f;
pure_color|=(color&0x000f)<<4;
// 根据像素点的位置, 设置相应的更新字节
// 以两个像素点为一组, 共三个字节
// buffer[0] = color & 0xff; //green(M)+red(L)
// buffer[1] = ((color & 0xf00) >> 8) + ((color & 0x0f) << 4);//red(M)+blue(L)
// buffer[2] = color >> 4;//blue(M)+green(L)
// *(__lcd_base + i) = 0x11;
// *(__lcd_base + i) = buffer[i % 3];
// 更新显示缓冲区
// for (i = 0; i < SCR_X * SCR_Y * 3 * BPP / 8; i++)
for (i = 0; i < SCR_X * SCR_Y * 1 * BPP / 8; i++){
*(__lcd_base + i) = pure_color;
/* if (i & 0x1)
{
pure_color = (color & 0x000f) << 4; // add by ywc
*(__lcd_base + i) &= 0x0f;
*(__lcd_base + i) |= pure_color;
}else{
pure_color = (color & 0x000f); // add by ywc
*(__lcd_base + i) &= 0xf0;
*(__lcd_base + i) |= pure_color;
} */
}
}
// 打开LCD设备文件
static int lcd_kernel_open(struct inode *node, struct file *file)
{
return 0;
}
// 对LCD设备文件进行读操作
static int lcd_kernel_read(struct file *file, char *buff, size_t count, loff_t *offp)
{
return 0;
}
// 对LCD设备文件进行写操作
static int lcd_kernel_write(struct file *file, const char *buff, size_t count, loff_t *offp)
{
return 0;
}
/
// by ywc 2004-04-17 对LCD设备文件按字节进行写操作(应用程序无法通过write
//调用到该函数???暂时没有找出原因,所以先通过ioctl复制位图缓冲到显存
//static int lcd_kernel_writeb(struct file *file, const char *buff, size_t count, loff_t *offp)
static int lcd_kernel_writeb(const char *buff, size_t count, int rownum)
{
int i;
unsigned char * fb_ptr;
fb_ptr=(unsigned char *)__lcd_base;
// printk("\n!!!enter the lcd_kernel_writeb()");
for(i=0;i<count;i++){
//*(fb_ptr+20*rownum+i)=*(buff+i);
*(fb_ptr+i)=*(buff+i);
}
return 0;
}
static int lcd_kernel_writew(const char *buff, size_t count, int rownum)
{
int i;
// unsigned char * fb_ptr;
unsigned long * fb_ptr_word;
fb_ptr_word=(unsigned long *)__lcd_base;
// printk("\n!!!enter the lcd_kernel_writeb()");
for(i=0;i<count/4;i++){
*(fb_ptr_word+i)=*((unsigned long *)buff+i);
}
return 0;
}
///
// 对LCD设备文件进行读写之外的其它操作
static int lcd_kernel_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
// 根据指令ID, 调用相应的操作
switch (cmd)
{
// 清屏
case LCD_Clear:
{
struct lcd_display clear_display;
// 复制显示结构
if (copy_from_user(&clear_display, (struct lcd_display*)arg, sizeof(struct lcd_display)))
{
printk("System: copy_from_user error!\n");
printk("Caller: lcd_kernel_ioctl -> LCD_Clear!\n");
return -1;
}
// 调用清屏函数
lcd_kernel_clear(clear_display.color);
break;
}
// 绘制像素点
case LCD_Draw_Pixel:
{
struct lcd_display pixel_display;
// 复制显示结构
if ( copy_from_user(&pixel_display, (struct lcd_display*)arg, sizeof(struct lcd_display)))
{
printk("System: copy_from_user error!\n");
printk("Caller: lcd_kernel_ioctl -> LCD_Draw_Pixel!\n");
return -1;
}
// 调用画点函数
lcd_kernel_pixel(pixel_display.x1, pixel_display.y1, pixel_display.color);
break;
}
// 绘制垂直直线
case LCD_Draw_VLine:
{
struct lcd_display vline_display;
// 复制显示结构
if ( copy_from_user(&vline_display, (struct lcd_display*)arg, sizeof(struct lcd_display)))
{
printk("System: copy_from_user error!\n");
printk("Caller: lcd_kernel_ioctl -> LCD_Draw_VLine!\n");
return -1;
}
// 调用画线函数
lcd_kernel_vline(vline_display.x1, vline_display.y1, vline_display.y2, vline_display.color);
break;
}
// 绘制水平直线
case LCD_Draw_HLine:
{
struct lcd_display hline_display;
// 复制显示结构
if ( copy_from_user(&hline_display,(struct lcd_display*)arg,sizeof(struct lcd_display)))
{
printk("System: copy_from_user error!\n");
printk("Caller: lcd_kernel_ioctl -> LCD_Draw_HLine!\n");
return -1;
}
// 调用画线函数
lcd_kernel_hline(hline_display.x1, hline_display.x2, hline_display.y1, hline_display.color);
break;
}
// 绘制矩形边框
case LCD_Draw_Rectangle:
{
struct lcd_display rect_display;
// 复制显示结构
if (copy_from_user(&rect_display, (struct lcd_display*)arg, sizeof(struct lcd_display)))
{
printk("System: copy_from_user error!\n");
printk("Caller: lcd_kernel_ioctl -> LCD_Draw_Rectangle!\n");
return -1;
}
// 调用画矩形边框函数
lcd_kernel_rectangle(rect_display.x1, rect_display.y1, rect_display.x2, rect_display.y2, rect_display.color);
break;
}
//将位图缓冲区写入显存 add by ywc 2004-04-18
case LCD_Draw_Buf:
{
struct lcd_display buf_display;
// 复制显示结构
if ( copy_from_user(&buf_display, (struct lcd_display*)arg, sizeof(struct lcd_display)))
{
printk("System: copy_from_user error!\n");
printk("Caller: lcd_kernel_ioctl -> LCD_Draw_Buf!\n");
return -1;
}
//调用复制位图缓冲到显存的函数
//lcd_kernel_writeb(buf_display.lcd_buf, buf_display.lcd_buf_size,buf_display.lcd_row);
lcd_kernel_writew(buf_display.lcd_buf, buf_display.lcd_buf_size,buf_display.lcd_row);
break;
}
// 显示一个ASCII字符
case LCD_Write_EN:
{
struct lcd_display en_display;
// 复制显示结构
if ( copy_from_user(&en_display, (struct lcd_display*)arg, sizeof(struct lcd_display)))
{
printk("System: copy_from_user error!\n");
printk("Caller: lcd_kernel_ioctl -> LCD_Write_EN!\n");
return -1;
}
// 调用显示字符函数
lcd_kernel_text_en(en_display.x1, en_display.y1, en_display.codes, en_display.color);
break;
}
// 显示一个中文字符
case LCD_Write_CN:
{
struct lcd_display cn_display;
// 复制显示结构
if ( copy_from_user(&cn_display,(struct lcd_display*)arg,sizeof(struct lcd_display)))
{
printk("System: copy_from_user error!\n");
printk("Caller: lcd_kernel_ioctl -> LCD_Write_EN!\n");
return -1;
}
// 调用显示字符函数
lcd_kernel_text_chs(cn_display.x1, cn_display.y1, cn_display.codes, cn_display.color);
break;
}
// 保存屏幕指定部分内容
case LCD_Save_SCR:
{
// 调用保存屏幕函数
lcd_kernel_save_screen((*(struct lcd_screen*)arg).x1, (*(struct lcd_screen*)arg).y1,
(*(struct lcd_screen*)arg).x2, (*(struct lcd_screen*)arg).y2,
(*(struct lcd_screen*)arg).buffer);
break;
}
// 加载保存的屏幕内容到指定位置
case LCD_Load_SCR:
{
struct lcd_screen load_screen;
// 复制屏幕结构
if ( copy_from_user(&load_screen,(struct lcd_screen*)arg,sizeof(struct lcd_screen)))
{
printk("System: copy_from_user error!\n");
printk("Caller: lcd_kernel_ioctl -> LCD_Load_SCR!\n");
return -1;
}
// 调用加载屏幕函数
lcd_kernel_load_screen(load_screen.x1, load_screen.y1, *load_screen.buffer);
break;
}
// 释放保存的屏幕内容
case LCD_Release_SCR:
{
lcd_kernel_release_screen((*(struct lcd_screen*)arg).buffer);
break;
}
default:
printk("Unknown LCD command ID.\n");
}
return 0;
}
// 释放LCD设备文件
static int lcdexp_release(struct inode *node, struct file *file)
{
// 缓存基址复位
__lcd_base = (unsigned char *)0xc0000000;
return 0;
}
// LCD设备文件操作结构
static struct file_operations lcd_fops = {
open: lcd_kernel_open, /* 打开设备文件 */
read: lcd_kernel_read, /* 设备文件的读操作 */
ioctl: lcd_kernel_ioctl, /* 设备文件的其它操作 */
//write: lcd_kernel_write, /* 设备文件的写操作 */
write: lcd_kernel_writeb, /* 设备文件的写操作 */
release: lcdexp_release, /* 释放设备文件 */
};
// 初始化LCD设备
static int __init lcd_kernel_init(void)
{
int result; /* 注册设备结果 */
long i;
// 设置显示缓存基地址
__lcd_base = (unsigned char*)0xc0000000;
// 注册LCD系统设备
printk("\nRegistering LCD Device\t--->\t");
result = register_chrdev(DEV_MAJOR, "lcd_ep7312", &lcd_fops);
if (result < 0)
{
printk(KERN_INFO "[FAILED: Cannot register lcd_ep7312!]\n");
return -EBUSY;
}
else
printk("[OK]\n");
printk("Initializing LCD Device\t--->\t\n");
// 设置LCD
setup_lcd();
// printk(" \nsetup_lcd runing end !//y ywc");
// 初始化显示缓冲区内容
// for (i=0; i < SCR_X * SCR_Y * 3 * BPP / 8; i++)
/* for (i=0; i < SCR_X * SCR_Y * 1* BPP / 8; i++)
{
*__lcd_base++ = 0x00;
// *__lcd_base= 0x11;
__lcd_base++;
// *(__lcd_base)&= 0xf0;
// *(__lcd_base)|= 0x04;
// *(__lcd_base)&= 0x0f;
// *(__lcd_base)|= 0x40;
// __lcd_base++;
}
*/
//printk("\n__lcd_base=%p,*__lcd_base=%x\n",--__lcd_base,*__lcd_base);
// 复位显存基地址
__lcd_base =(unsigned char*)0xc0000000;
//printk("\n__lcd_base=%x\n",__lcd_base);
printk("[OK]\n");
// 显示成功加载信息
printk("\nEP7312 LCD Driver installed.\n");
// printk("Written by BIT200009123.\n");
return 0;
}
// 释放LCD设备
static void __exit lcd_kernel_exit(void)
{
// 注销LCD设备, 并释放保存屏幕缓冲区
printk("Unregistering LCD Device\t--->\t");
unregister_chrdev(DEV_MAJOR, "lcd_ep7312");
printk("[OK]\n");
return;
}
// 初始化模块
module_init(lcd_kernel_init);
// 卸载模块
module_exit(lcd_kernel_exit);