📄 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -