驅動05.lcd設備驅動程式

来源:http://www.cnblogs.com/Lwd-linux/archive/2017/01/10/6267595.html
-Advertisement-
Play Games

參考s3c2410fb.c總結出框架 1.代碼分析 1.1 入口函數 註冊一個platform_driver結構體,如果存在同名的設備dev時,將調用probe函數。 搜索s3c2410-lcd可得下麵的s3c_device_lcd結構體 1.2 probe函數(只列出關鍵性代碼) 由此可知,其主要 ...


參考s3c2410fb.c總結出框架

1.代碼分析

1.1 入口函數

1 int __devinit s3c2410fb_init(void)
2 {
3     return platform_driver_register(&s3c2410fb_driver);
4 }

註冊一個platform_driver結構體,如果存在同名的設備dev時,將調用probe函數。

 1 static struct platform_driver s3c2410fb_driver = {
 2     .probe        = s3c2410fb_probe,
 3     .remove        = s3c2410fb_remove,
 4     .suspend    = s3c2410fb_suspend,
 5     .resume        = s3c2410fb_resume,
 6     .driver        = {
 7         .name    = "s3c2410-lcd",   //如果存在有同名"s3c2410-lcd"的平臺設備,就會調用s3c2410fb_driver的s3c2410fb_probe函數
 8         .owner    = THIS_MODULE,
 9     },
10 };      //這是s3c2410fb_driver這個結構體的具體成員

搜索s3c2410-lcd可得下麵的s3c_device_lcd結構體

 1 struct platform_device s3c_device_lcd = {
 2     .name          = "s3c2410-lcd",
 3     .id          = -1,
 4     .num_resources      = ARRAY_SIZE(s3c_lcd_resource),
 5     .resource      = s3c_lcd_resource,               //最重要的部分
 6     .dev              = {
 7         .dma_mask        = &s3c_device_lcd_dmamask,
 8         .coherent_dma_mask    = 0xffffffffUL
 9     }
10 };

 

1.2 probe函數(只列出關鍵性代碼)

 1 static int __init s3c2410fb_probe(struct platform_device *pdev)
 2 {
 3     struct s3c2410fb_info *info;
 4     struct fb_info       *fbinfo;
 5                         ......
 6 
 7     fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);
 8     if (!fbinfo) {
 9         return -ENOMEM;
10     }
11                         ......
12     fbinfo->fix.type        = FB_TYPE_PACKED_PIXELS;
13     fbinfo->fix.type_aux        = 0;
14     fbinfo->fix.xpanstep        = 0;
15     fbinfo->fix.ypanstep        = 0;
16     fbinfo->fix.ywrapstep        = 0;
17     fbinfo->fix.accel        = FB_ACCEL_NONE;
18 
19     fbinfo->var.nonstd        = 0;
20     fbinfo->var.activate        = FB_ACTIVATE_NOW;
21     fbinfo->var.height        = mach_info->height;
22     fbinfo->var.width        = mach_info->width;
23     fbinfo->var.accel_flags     = 0;
24     fbinfo->var.vmode        = FB_VMODE_NONINTERLACED;
25                         .......
26     ret = register_framebuffer(fbinfo);
27     return 0;
28 
29 }

由此可知,其主要框架是

(1)分配一個fb_info結構體

(2)設置其參數

(3)註冊這個結構體

(4)硬體相關的操作

1.3 fb_info結構體成員的瞭解

lcd為標準的幀緩衝設備,其主設備號為29,對應的設備為/dev/fb*

 1     struct fb_info {  
 2         int node;                       //用作次設備號索引  
 3         int flags;  
 4         struct mutex lock;              //用於open/release/ioctl函數的鎖  
 5         struct fb_var_screeninfo var;   //可變參數,重點  
 6         struct fb_fix_screeninfo fix;   //固定參數,重點  
 7         struct fb_monspecs monspecs;    //顯示器標準  
 8         struct work_struct queue;       //幀緩衝區隊列  
 9         struct fb_pixmap pixmap;        //圖像硬體映射  
10         struct fb_pixmap sprite;        //游標硬體映射  
11         struct fb_cmap cmap;            //當前顏色表  
12         struct list_head modelist;      //模式鏈表  
13         struct fb_videomode *mode;      //當前video模式  
14       
15         char __iomem *screen_base;      //顯存基地址  
16         unsigned long screen_size;      //顯存大小  
17         void *pseudo_palette;           //16色調色板  
18     #define FBINFO_STATE_RUNNING    0  
19     #define FBINFO_STATE_SUSPENDED  1  
20         u32 state;                      //硬體狀態,如掛起  
21         void *fbcon_par;                //用作私有數據區  
22         void *par;                      //info->par指向了額外多申請記憶體空間的首地址  
23     };  

另外,fb_fix_screeninfofb_var_screeninfo也是兩個比較重要的結構體,在設置fb_info結構體時會大量用到。

 1 struct fb_fix_screeninfo {
 2     char id[16];            /* identification string eg "TT Builtin" */
 3     unsigned long smem_start;    /* Start of frame buffer mem */
 4                     /* (physical address) */
 5     __u32 smem_len;            /* Length of frame buffer mem */
 6     __u32 type;            /* see FB_TYPE_*        */
 7     __u32 type_aux;            /* Interleave for interleaved Planes */
 8     __u32 visual;            /* see FB_VISUAL_*        */ 
 9     __u16 xpanstep;            /* zero if no hardware panning  */
10     __u16 ypanstep;            /* zero if no hardware panning  */
11     __u16 ywrapstep;        /* zero if no hardware ywrap    */
12     __u32 line_length;        /* length of a line in bytes    */
13     unsigned long mmio_start;    /* Start of Memory Mapped I/O   */
14                     /* (physical address) */
15     __u32 mmio_len;            /* Length of Memory Mapped I/O  */
16     __u32 accel;            /* Indicate to driver which    */
17                     /*  specific chip/card we have    */
18     __u16 reserved[3];        /* Reserved for future compatibility */
19 };
struct fb_var_screeninfo {
    __u32 xres;            /* visible resolution        */
    __u32 yres;
    __u32 xres_virtual;        /* virtual resolution        */
    __u32 yres_virtual;
    __u32 xoffset;            /* offset from virtual to visible */
    __u32 yoffset;            /* resolution            */

    __u32 bits_per_pixel;        /* guess what            */
    __u32 grayscale;        /* != 0 Graylevels instead of colors */

    struct fb_bitfield red;        /* bitfield in fb mem if true color, */
    struct fb_bitfield green;    /* else only length is significant */
    struct fb_bitfield blue;
    struct fb_bitfield transp;    /* transparency            */    

    __u32 nonstd;            /* != 0 Non standard pixel format */

    __u32 activate;            /* see FB_ACTIVATE_*        */

    __u32 height;            /* height of picture in mm    */
    __u32 width;            /* width of picture in mm     */

    __u32 accel_flags;        /* (OBSOLETE) see fb_info.flags */

    /* Timing: All values in pixclocks, except pixclock (of course) */
    __u32 pixclock;            /* pixel clock in ps (pico seconds) */
    __u32 left_margin;        /* time from sync to picture    */
    __u32 right_margin;        /* time from picture to sync    */
    __u32 upper_margin;        /* time from sync to picture    */
    __u32 lower_margin;
    __u32 hsync_len;        /* length of horizontal sync    */
    __u32 vsync_len;        /* length of vertical sync    */
    __u32 sync;            /* see FB_SYNC_*        */
    __u32 vmode;            /* see FB_VMODE_*        */
    __u32 rotate;            /* angle we rotate counter clockwise */
    __u32 reserved[5];        /* Reserved for future compatibility */
};

1.4 fb_open函數

app:  open("/dev/fb0"...)   主設備號:29   次設備號:0
-----------------------------------------------------------
kernel:
      fb_open
               int fbidx = iminor(inode)//獲取次設備號
                    struct fb_info *info =  registered_fb[fbidx]

 

1.5 fb_read函數

app:    read()
------------------------------------------------------------            
kernel:
            fb_read
                int fbidx = iminor(inode);
                struct fb_info *info = registered_fb[fbidx];    
                    if (info->fbops->fb_read)
                            return info->fbops->fb_read(info, buf, count, ppos);
                    src = (u32 __iomem *) (info->screen_base + p);
                    *dst++ = fb_readl(src++);
                    copy_to_user(buf, buffer, c)

1.6 registered_fb數組由誰來定義?

register_framebuffer

  registered_fb[i] = fb_info

2 寫代碼

由1.2我們可以得知,代碼的總體框架為:

(1)分配一個fb_info結構體

(2)設置其參數

(3)註冊這個結構體

(4)硬體相關的操作

其實難點就在於第(2)步,主要是設置fb_info結構體的固定參數 fb_fix_screeninfo結構體和可變參數fb_var_screeninfo結構體,還有就是硬體相關

的設置,比如lcd時序參數的設置,也就是要設置lcdcon1~lcdcon5,lcdaddr1~lcdaddr3個寄存器。

 2.2 源代碼

  1 #include <linux/module.h>
  2 #include <linux/kernel.h>
  3 #include <linux/errno.h>
  4 #include <linux/string.h>
  5 #include <linux/mm.h>
  6 #include <linux/slab.h>
  7 #include <linux/delay.h>
  8 #include <linux/fb.h>
  9 #include <linux/init.h>
 10 #include <linux/dma-mapping.h>
 11 #include <linux/interrupt.h>
 12 #include <linux/workqueue.h>
 13 #include <linux/wait.h>
 14 #include <linux/platform_device.h>
 15 #include <linux/clk.h>
 16 
 17 #include <asm/io.h>
 18 #include <asm/uaccess.h>
 19 #include <asm/div64.h>
 20 
 21 #include <asm/mach/map.h>
 22 #include <asm/arch/regs-lcd.h>
 23 #include <asm/arch/regs-gpio.h>
 24 #include <asm/arch/fb.h>
 25 
 26 
 27 struct lcd_regs{
 28     unsigned long lcdcon1;
 29     unsigned long lcdcon2;
 30     unsigned long lcdcon3;
 31     unsigned long lcdcon4;
 32     unsigned long lcdcon5;
 33     unsigned long lcdsaddr1;
 34     unsigned long lcdsaddr2;
 35     unsigned long lcdsaddr3;
 36     unsigned long redlut;
 37     unsigned long greenlut;
 38     unsigned long bluelut;
 39     unsigned long reserved[9];
 40     unsigned long dithmode;
 41     unsigned long tpal;
 42     unsigned long lcdintpnd;
 43     unsigned long lcdsrcpnd;
 44     unsigned long lcdintmsk;
 45     unsigned long tconsel;
 46 };
 47 
 48 static struct fb_info *s3c_lcd;
 49 static volatile unsigned long *gpbcon;
 50 static volatile unsigned long *gpbdat;
 51 static volatile unsigned long *gpccon;
 52 static volatile unsigned long *gpdcon;
 53 static volatile unsigned long *gpgcon;
 54 static u32 pseudo_palette[16];
 55 static volatile struct lcd_regs *lcd_regs;
 56 
 57 
 58 static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
 59 {
 60     chan &= 0xffff;
 61     chan >>= 16 - bf->length;
 62     return chan << bf->offset;
 63 }
 64 
 65 static int s3c_lcdfb_setcolreg(unsigned regno,
 66                    unsigned red, unsigned green, unsigned blue,
 67                    unsigned transp, struct fb_info *info)
 68 {
 69     unsigned int val;
 70     
 71     if (regno < 16) 
 72     {
 73 //        u32 *pal = fbi->fb->pseudo_palette;
 74         val  = chan_to_field(red,   &info->var.red);
 75         val |= chan_to_field(green, &info->var.green);
 76         val |= chan_to_field(blue,  &info->var.blue);
 77         pseudo_palette[regno] = val;
 78     }
 79     else
 80         return 1;
 81 
 82     return 0;
 83 
 84 }
 85 
 86 static struct fb_ops s3clcdfb_ops = {
 87     .owner        = THIS_MODULE,
 88     .fb_setcolreg    = s3c_lcdfb_setcolreg,//調色板
 89     .fb_fillrect    = cfb_fillrect,
 90     .fb_copyarea    = cfb_copyarea,
 91     .fb_imageblit    = cfb_imageblit,
 92 };
 93 
 94 static int lcd_init(void)
 95 {
 96     int ret;
 97     /*1.分配一個fb_info結構體*/
 98     s3c_lcd = framebuffer_alloc(0, NULL);
 99     if (!s3c_lcd) {
100         return -ENOMEM;
101     }
102 
103 
104     /*2.設置 */
105     strcpy(s3c_lcd->fix.id, "mylcd");
106 
107     /*2.1設置固定數據fix*/
108     s3c_lcd->fix.smem_len = 480*272*16/8;
109     s3c_lcd->fix.type         = FB_TYPE_PACKED_PIXELS;
110     s3c_lcd->fix.type_aux   = 0;
111     s3c_lcd->fix.visual           = FB_VISUAL_TRUECOLOR;//TFT真彩色
112     s3c_lcd->fix.line_length = 480*16/8;
113 //    s3c_lcd->fix.smem_start
114 
115     /*2.2設置可變參數var*/
116     s3c_lcd->var.xres = 480;
117     s3c_lcd->var.yres = 272;
118     s3c_lcd->var.xres_virtual = 480;
119     s3c_lcd->var.yres_virtual = 272;
120     s3c_lcd->var.bits_per_pixel = 16;
121 
122     /*RGB:565*/
123     s3c_lcd->var.red.offset= 11;
124     s3c_lcd->var.red.length = 5;
125     s3c_lcd->var.green.offset = 5;
126     s3c_lcd->var.green.length = 6;
127     s3c_lcd->var.blue.offset = 0;
128     s3c_lcd->var.blue.length = 5;
129 
130     s3c_lcd->var.activate = FB_ACTIVATE_NOW;
131 
132     s3c_lcd->fbops            = &s3clcdfb_ops;
133     s3c_lcd->pseudo_palette = pseudo_palette;
134     s3c_lcd->screen_size   = 480*272*16/8;
135 
136     /*3.硬體相關的操作*/
137     /*3.1GPIO的初始化*/
138     gpbcon = ioremap(0x56000010, 8);
139     gpbdat = gpbcon+1;
140     gpccon = ioremap(0x56000020, 4);
141     gpdcon = ioremap(0x56000030, 4);
142     gpgcon = ioremap(0x56000060, 4);
143 
144     *gpccon = 0xaaaaaaaa;
145     *gpdcon = 0xaaaaaaaa;
146     
147     *gpbcon &= ~(3);
148     *gpbcon |= 1;
149     *gpbdat &= ~1;//背光使能
150     
151     *gpgcon  |= (3<<8); //LCD 電源使能
152 
153     /*3.2 設置LCD controller*/
154     lcd_regs = ioremap(0x4D000000,sizeof(struct lcd_regs));
155 
156 
157     lcd_regs->lcdcon1 = (4<<8) |(3<<5) |(0x0c<<1);
158     //lcdcon1[0] Enable the video output and the LCD control signal
159 
160     lcd_regs->lcdcon2 = (1<<24) |(271<<14) |(1<<6) |(9);
161 
162     lcd_regs->lcdcon3 = (1<<19) |(479<<8) |(1);
163 
164     lcd_regs->lcdcon4 = 40;
165 
166     lcd_regs->lcdcon5 = (1<<11) |(1<<9) |(1<<8) |(1<<0);
167 
168     /*3.3 設置顯存的地址*/
169     s3c_lcd->screen_base = dma_alloc_writecombine(NULL,s3c_lcd->fix.smem_len,&s3c_lcd->fix.smem_start,GFP_KERNEL);
170     
171     lcd_regs->lcdsaddr1 = (s3c_lcd->fix.smem_start>>1) & ~(3<<30);
172     lcd_regs->lcdsaddr2 = (s3c_lcd->fix.smem_start + s3c_lcd->fix.smem_len) & 0x1fffff;
173     lcd_regs->lcdsaddr3 = (480*16/16);//行的長度
174 
175 
176     /*啟動lcd*/
177     
178     lcd_regs->lcdcon1 |= (1);//使能LCD控制器
179     lcd_regs->lcdcon5 |= (1<<3);//使能LCD電源
180     *gpbdat |=1;  //使能背光
181 
182 
183     /*4.註冊該結構體*/
184     ret = register_framebuffer(s3c_lcd);
185     if (ret < 0) {
186         printk("Failed to register framebuffer device: %d\n", ret);
187     }
188 
189     return 0;
190 }
191 
192 static int lcd_exit(void)
193 {    
194     unregister_framebuffer(s3c_lcd);
195     lcd_regs->lcdcon1 &= ~1;
196     lcd_regs->lcdcon5 &= ~(1<<3);
197     *gpbdat &= ~1;  
198 
199     dma_free_writecombine(NULL, s3c_lcd->fix.smem_len, s3c_lcd->screen_base, s3c_lcd->fix.smem_start);
200     iounmap(lcd_regs);
201     iounmap(gpbcon);
202     iounmap(gpccon);
203     iounmap(gpdcon);
204     iounmap(gpgcon);
205 
206     framebuffer_release(s3c_lcd);
207     return 0;
208 }
209 
210 module_init(lcd_init);
211 module_exit(lcd_exit);
212 
213 MODULE_AUTHOR("lwd20170110");
214 
215 MODULE_LICENSE("GPL");
lcd驅動程式
測試:
1. make menuconfig去掉原來的驅動程式
-> Device Drivers
  -> Graphics support
<M> S3C2410 LCD framebuffer support

2. make uImage
   make modules  

3. 使用新的uImage啟動開發板:

4. 
insmod cfbcopyarea.ko 
insmod cfbfillrect.ko 
insmod cfbimgblt.ko 
insmod lcd.ko

echo hello > /dev/tty1  // 可以在LCD上看見hello
cat lcd.ko > /dev/fb0   // 花屏

5. 修改 /etc/inittab
tty1::askfirst:-/bin/sh
用新內核重啟開發板

insmod cfbcopyarea.ko 
insmod cfbfillrect.ko 
insmod cfbimgblt.ko 
insmod lcd.ko
insmod buttons.ko

2.3 待解決:1.出現段錯誤。2.用新內核啟動後無法掛載nfs。

2017-01-10 16:12:27


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 寫在前面 在QQ群,微信群,論壇中經常幫助使用SQL Server資料庫的朋友解決問題,但是有一些最常見最基本的問題,每天都有人問,回答多了也不想再解答了,索性把這些問題整理一下,再有人問到直接發鏈接。 一時想法而寫這篇文章,問題可能不全面,後續會一直更新。 基礎問題收集 資源下載 描述:XX版本數 ...
  • 一、HBase的特點是什麼 1.HBase一個分散式的基於列式存儲的資料庫,基於hadoop的hdfs存儲,zookeeper進行管理。 2.HBase適合存儲半結構化或非結構化數據,對於數據結構欄位不夠確定或者雜亂無章很難按一個概念去抽取的數據。 3.HBase為null的記錄不會被存儲. 4.基 ...
  • twemproxy背景 在業務量劇增的今天,單台高速緩存伺服器已經無法滿足業務的需求, 而相較於大容量SSD數據存儲方案,緩存具備速度和成本優勢,但也存在數據安全性的挑戰。為此搭建一個高速緩存伺服器集群來進行分散式存儲是十分必要的。 目前主流的高速緩存伺服器是redis和memchache。而twe ...
  • 本文將介紹閃回原理,給出筆者的實戰經驗,並對現存的閃回工具作比較。 DBA或開發人員,有時會誤刪或者誤更新數據,如果是線上環境並且影響較大,就需要能快速回滾。傳統恢復方法是利用備份重搭實例,再應用去除錯誤sql後的binlog來恢複數據。此法費時費力,甚至需要停機維護,並不適合快速回滾。也有團隊利用 ...
  • 本文轉自:樂沙彌的世界 對於物理損壞的數據塊,我們可以通過RMAN塊介質恢復(BLOCK MEDIA RECOVERY)功能來完成受損塊的恢復,而不需要恢復整個資料庫或所有文件來修複這些少量受損的數據塊。恢復整個資料庫或數據文件那不是大炮用來打蚊子,有點不值得!但前提條件是你得有一個可用的RMAN備 ...
  • SQL Server 2016支持哈希查找,用戶可以在記憶體優化表(Memory-Optimized Table)上創建Hash Index,使用Hash 查找演算法,實現數據的極速查找。在使用上,Hash Index 和B-Tree索引的區別是:Hash Index 是無序查找,Index Key必須 ...
  • 賬號是一種用來記錄單個用戶或者多個用戶的數據。RHEL中每一個合法的用戶都必須擁有賬號,才能使用RHEL。 在RHEL上的賬號可以分為兩類: 用戶賬號:用來存儲單一用戶的數據,你也可以使用一個用戶賬號來存儲某一個用戶的數據。 組賬號:用來存儲多個用戶的信息,每一個組賬號都可以記錄一組用戶的數據。 在 ...
  • 首先要安裝VirtualBox的增強版功能(VBoxGuestAdditions) 在 設備 >安裝增強版功能 >運行,重啟電腦。 1、Linux本地的共用文件夾建立 mkdir /mnt/localShare 2、/etc/下的fstab 修改添加 win_share /mnt/localShar ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...