简单的linux驱动学习

来源:互联网 发布:mysql存储优化 编辑:程序博客网 时间:2024/05/22 12:30

#include<linux/module.h>
#include<linux/init.h>
#include<linux/cdev.h>
#include<linux/fs.h>
#include<linux/device.h>

static unsigned int hello_major =0;
static struct cdev *hello_cdev =NULL;

/*6.实现操作硬件的方法*/
static int hello_open(struct inode *inode, struct file *file)
{
 printk("hello open!\n");
 return 0;
}

static ssize_t hello_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
 printk("hello write!\n");
 return 0;
}

static ssize_t hello_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
 printk("hello read!\n");
 return 0;
}

struct file_operations hello_fops ={
 .owner =THIS_MODULE,
 .open =hello_open,
 .write =hello_write,
 .read  =hello_read,
};

static int hello_init(void)
{
 dev_t devno;
 /*1.申请设备号*/
 //MKDEV(major,minor);
 //register_chrdev(unsigned int major, const char * name, const struct file_operations * fops)
 if(hello_major)
 {
  /*1.1静态申请*/
  devno =MKDEV(hello_major, 0);
  register_chrdev_region(devno, 1, "hello");
 }
 else
 {
  /*1.2动态申请*/
  alloc_chrdev_region(&devno, 0,1, "hello");
  hello_major =MAJOR(devno);
 }

 /*2. 构造一个struct cdev结构体*/
 hello_cdev=cdev_alloc();
 cdev_init(hello_cdev, &hello_fops);
 hello_cdev->owner=THIS_MODULE,
 cdev_add(hello_cdev, MKDEV(hello_major, 0), 1);

 /*3. 创建设备节点*/
 hello_class=class_create(THIS_MODULE,"hello_class");
 class_device_create(hello_class, NULL, MKDEV(hello_major, 0),NULL, "hello");
 
 return 0;
}

static void hello_exit(void)
{
 unregister_chrdev_region(MKDEV(hello_major, 0), 1);
 cdev_del(hello_cdev);
 class_device_destroy(hello_class, MKDEV(hello_major, 0));
 class_destroy(hello_class);
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

 

 

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc,char **argv)
{
 int fd;
 char val =1;
 fd =open("/dev/hello",O_RDWR);
 if(fd<0)
 {
  printf("can not open /dev/ hello !\n");
  return -1;
 }
 write(fd,&val,1);
 return 0;
}

 

 

ifeq ($(KERNELRELEASE),)
 KERNELDIR =/home/zgp/linux_kernel/s3c2410/linux-2.6.22.6
 PWD =$(shell pwd)
modules:
 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:
 rm -rf *.o *.ko .tmp_versions *.mod.c
else
 obj-m :=hello.o
endif

 

平台设备驱动机制之源代码实现:   //一般在写控制器驱动的时候才会用到
=======================================================================================
1.设备资源层:arch/arm/plat-s3c24xx/devs.c  //所有的资源都放在这里面
arch/arm/plat-s3c24xx/devs.c :
====================================
struct resource:表示的是一个资源,irq资源 I/O资源
/*I2C控制器的资源*/
static struct resource s3c_i2c_resource[] = {
 [0] = {
  .start = S3C24XX_PA_IIC,   //0x54000000
  .end   = S3C24XX_PA_IIC + S3C24XX_SZ_IIC - 1,
  .flags = IORESOURCE_MEM,
 },
 [1] = {
  .start = IRQ_IIC,
  .end   = IRQ_IIC,
  .flags = IORESOURCE_IRQ,
 }
};

struct platform_device s3c_device_i2c = {
 .name    = "s3c2410-i2c",     //最关键的
 .id    = -1,
 .num_resources   = ARRAY_SIZE(s3c_i2c_resource),
 .resource   = s3c_i2c_resource,
};

如何注册资源:arch/arm/mach-s3c2410/mach-smdk2410.c
===============================================================
static struct platform_device *smdk2410_devices[] __initdata = {
 &s3c_device_usb,
 &s3c_device_lcd,
 &s3c_device_wdt,
 &s3c_device_i2c,
 &s3c_device_iis,
 &s3c_device_sdi 
};

入口函数
smdk2410_init
 platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));  
 for (i = 0; i < num; i++) {
   /*1.将s3c_device_i2c挂入平台设备资源链表
    *2.搜索平台驱动链表,调用platform_bus.match函数实现按名字匹配,
    *3.如果匹配成功,则调用驱动中的probe函数实际上就是s3c24xx_i2c_probe
    *4.如果匹配不成功,它只会讲自己挂入设备链表,不会调用probe函数
    */
   platform_device_register(devs[i]);

 

2.i2c控制器驱动层(控制器设备驱动层)drivers/i2c/i2c-s3c2410.c
static struct platform_driver s3c2410_i2c_driver = {
 .probe  = s3c24xx_i2c_probe,
 .remove  = s3c24xx_i2c_remove,
 .resume  = s3c24xx_i2c_resume,
 .driver  = {
  .owner = THIS_MODULE,
  .name = "s3c2410-i2c",     //名字很重要
 },
};

入口函数
module_init(i2c_adap_s3c_init);
  i2c_adap_s3c_init
    /*1.将s3c2410_i2c_driver结构体挂入平台驱动链表,
     *2.搜索平台设备链表,调用platform_bus.match函数实现按名字匹配,
     *3.如果匹配成功,则调用驱动中的probe函数实际上就是s3c24xx_i2c_probe
     *4.如果匹配不成功,它只会讲自己挂入驱动链表,不会调用probe函数
     */
    platform_driver_register(&s3c2410_i2c_driver);

s3c24xx_i2c_probe(struct platform_device *pdev)做了什么:
=======================================================
1.获取资源
 /*获取IO资源*/
 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 /*获取中断资源*/
 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
2.初始化控制器
 

i2c体系架构分析:
========================================================
1.driver/i2c/algos目录:   协议算法相关的东西
2.driver/i2c/chips目录:  i2c设备驱动(e2prom,触摸屏,传感器)   //策略性的问题
3.i2c-core.c文件:     i2c核心层的东西: 提供注册/注销/调用等等的接口
4.driver/i2c/busses目录: i2c总线驱动(控制器驱动/适配器驱动) //操作硬件的方法
5.i2c-dev.c文件:     提供给上层的通用接口

 

app:                    open(),write, read
======================================================================================================================
kernel:                 sys_open  sys_write  sys_read

 
    ==============================================================================================================
       自己写的接口                           通用接口
   file_operations
       .open                     file_operations(i2cdev_fops)
       .write                                .open  =i2cdev_open
       .read                                   .read   =i2cdev_read
                                          .write  =i2cdev_write
                                        .ioctl  =i2cdev_ioctl
    1.设备驱动层(e2prom):     2.设备驱动(传感器)          3.通用接口:i2c-dev.c分析下面
    ===============================================         =================================================


                           i2c子系统核心层(i2c-core.c):
                           1.提供注册/注销的方法
                           2.提供通用的函数,结构体
                           3.提供上层与下层打交道的函数,
                           如:i2c_transfer,i2c_master_send,i2c_master_recv
                        ===================================================

 

 

                         3.i2c总线驱动层(控制器驱动层)(i2c-s3c2410.c)分析见下面:   
===========================================================================================================================
硬件:                         i2c控制器  i2c-adapter

                  e2prom       触摸屏          传感器


上层接口:
=========================================================================
i2d-dev.c文件分析:(内核做的)
完成的任务:
1.构建一个file_operations结构体
2.申请主设备号
3.创建一个类
4.构建一个i2c_driver结构体
5.将i2c_driver挂入链表
=========================================================================
static const struct file_operations i2cdev_fops = {
 .owner  = THIS_MODULE,
 .llseek  = no_llseek,
 .read  = i2cdev_read,
 .write  = i2cdev_write,
 .ioctl   = i2cdev_ioctl,
 .open  = i2cdev_open,
 .release  = i2cdev_release,
};

static struct i2c_driver i2cdev_driver = {
 .driver = {
  .name = "dev_driver",
 },
 .id  = I2C_DRIVERID_I2CDEV,
 .attach_adapter = i2cdev_attach_adapter,
 .detach_adapter = i2cdev_detach_adapter,
 .detach_client = i2cdev_detach_client,
};

入口函数:
 i2c_dev_init
  res = register_chrdev(I2C_MAJOR(89), "i2c", &i2cdev_fops);
      struct cdev  
  /*创建一个类*/
  i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
  /*加载i2c设备驱动(万能接口),将结构体挂入到一个链表i2c_driver的链表*/
  res = i2c_add_driver(&i2cdev_driver);
  

通用接口的用法:
================================================================
open
 sys_open
  i2cdev_open
   unsigned int minor = iminor(inode);
   struct i2c_client *client;
   struct i2c_adapter *adap;
   struct i2c_dev *i2c_dev;
   
   i2c_dev = i2c_dev_get_by_minor(minor);
   adap = i2c_get_adapter(i2c_dev->adap->nr);
       
   client = kzalloc(sizeof(*client), GFP_KERNEL);
   
   client->driver = &i2cdev_driver;
   client->adapter = adap;      //适配器下面注册上来的,哪里注册的呢?
   file->private_data = client;
   
ioctl
 sys_ioctl
  i2cdev_ioctl
   struct i2c_client *client = (struct i2c_client *)file->private_data;
   client->addr = arg;
   
write
 sys_write 
   i2cdev_write
    struct i2c_client *client = (struct i2c_client *)file->private_data;
    copy_from_user(tmp,buf,count)
    i2c_master_send(client,tmp,count);
      struct i2c_adapter *adap=client->adapter;
      struct i2c_msg msg;
       msg.addr = client->addr;            //从机设备地址(0xa0)
       msg.flags = client->flags & I2C_M_TEN;   //标号:表示的是读,还是写  0:表示写  1:表示读
       msg.len = count;             //要传送的字节的个数
       msg.buf = (char *)buf;          //要传送的数据
       i2c_transfer(adap, &msg, 1);       //次接口是在核心层实现的
         /*开始调用底层的操作方法*/ 
         if (adap->algo->master_xfer) {
           ret = adap->algo->master_xfer(adap,msgs,num);  ---------> //s3c24xx_i2c_xfer
read
 sys_read
   i2cdev_read
    struct i2c_client *client = (struct i2c_client *)file->private_data;
    ret = i2c_master_recv(client,tmp,count);
        struct i2c_adapter *adap=client->adapter;
        struct i2c_msg msg;
        msg.addr = client->addr;            //从机设备地址(0xa0)
        msg.flags = client->flags & I2C_M_TEN;   //标号:表示的是读,还是写  0:表示写  1:表示读
        msg.flags |=I2C_M_RD;
        msg.len = count;             //要传送的字节的个数
        msg.buf = (char *)buf;          //要传送的数据
        i2c_transfer(adap, &msg, 1);       //次接口是在核心层实现的
          if (adap->algo->master_xfer) {
           ret = adap->algo->master_xfer(adap,msgs,num);  ---------> //s3c24xx_i2c_xfer
    copy_to_user(buf,tmp,count)       


i2c-s3c2410.c分析:底层总线驱动分析:
=============================================================================================
static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
 .master_xfer  = s3c24xx_i2c_xfer,
 .functionality  = s3c24xx_i2c_func,
};

static struct s3c24xx_i2c s3c24xx_i2c = {
 .lock  = __SPIN_LOCK_UNLOCKED(s3c24xx_i2c.lock),
 .wait  = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait),
 .tx_setup = 50,
 .adap  = {
  .name   = "s3c2410-i2c",
  .owner   = THIS_MODULE,
  .algo   = &s3c24xx_i2c_algorithm,
  .retries  = 2,
  .class   = I2C_CLASS_HWMON,
 },
};


1.利用平台设备驱动机制
2.调用probe
 入口函数:
  i2c_adap_s3c_init
    ret = platform_driver_register(&s3c2410_i2c_driver);
   
s3c24xx_i2c_probe(struct platform_device *pdev)
 /*1.构建一个本地结构体,帮我们构建了一个操作硬件的方法,而且次方法放在i2c_adapter结构体里面*/
 struct s3c24xx_i2c *i2c = &s3c24xx_i2c;
      struct i2c_msg  *msg;
      struct i2c_adapter adap;   /*一个i2c控制器*/
          const struct i2c_algorithm *algo;   /*访问总线的协议算法 */
                  int (*master_xfer)   ---->s3c24xx_i2c_xfer   /*底层的操作方法*/
      struct device  *dev;
 /*2.初始化控制器*/
 /*2.1 使能时钟*/
 i2c->clk = clk_get(&pdev->dev, "i2c");
 clk_enable(i2c->clk);
 /*2.2 获取IO资源*/
 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 /*2.3 上面申请了IO内存后,在此要映射*/
 i2c->regs = ioremap(res->start, (res->end-res->start)+1);
 /*2.4 初始化I2C控制器*/
 ret = s3c24xx_i2c_init(i2c);
     /*2.4.1 设置管脚功能*/
     /*2.4.2 配置时钟频率*/
     /*2.4.3 使能中断,使能响应,使能i2c_控制器*/ 
 /*2.5 获取中断资源*/
 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);    
 /*2.6 申请中断*/
 ret = request_irq(res->start, s3c24xx_i2c_irq, IRQF_DISABLED,
     pdev->name, i2c);
    
 
 /*3.注册这套方法/实际上就是注册i2c_adapter*/
 /*添加I2C适配器*/
 ret = i2c_add_adapter(&i2c->adap);
     res = idr_get_new_above(&i2c_adapter_idr, adapter,
    __i2c_first_dynamic_bus_num, &id);
     adapter->nr = id;
    i2c_register_adapter(adapter);
       

跟i2c子系统相关的结构体:
============================================================
1.struct i2c_driver         //描述的是一个i2c设备驱动
2.struct i2c_client *client;    //描述的是一个i2c设备(如:e2prom)
3.struct i2c_adapter *adap;    //描述的是一个i2c控制器(适配器)
4.struct i2c_dev *i2c_dev;  
5.struct i2c_msg msg;      //描述的是要发送的数据信息结构体


跟i2c子系统相关的函数接口:
===========================================================
1.i2c_master_send(struct i2c_client *client,const char *buf ,int count)
2.i2c_transfer(adap, &msg, 1);
3.i2c_master_recv(struct i2c_client *client, char *buf ,int count)
4.i2c_add_adapter(&i2c->adap);    /*注册i2c适配器*/
5.i2c_add_driver(&i2cdev_driver); /*注册i2c通用接口驱动*/

 

 

 

如何用正缓冲设备
1.app:open
   sys_open 
     进入最上层的fbmem.c
     file_operations--->fb_fops.open   =fb_open
                 int fbidx = iminor(inode);
                 struct fb_info *info;
                 /*从数组中获取fb_info*/
                 info = registered_fb[fbidx])
                 /*将fb_info放入file的私有数据*/
                 file->private_data = info;
                 /*问:fb_info->fbops->fb_open是否存在
                  *究竟是否存在,需要看底层
                  */
                 if (info->fbops->fb_open)
                 res = info->fbops->fb_open(info,1);
                 
2.app:ioctl  目的:获取某些参数,比如:分辨率,一个像素点用几个字节描述
    sys_ioctl
      进入最上层的fbmem.c
       file_operations--->fb_fops.ioctl  =fb_ioctl
                 int fbidx = iminor(inode);
                 /*再次获取fb_info*/
                 struct fb_info *info = registered_fb[fbidx];
                 /*获取底层的操作方法*/
                 struct fb_ops *fb = info->fbops;
                 struct fb_var_screeninfo var;
                struct fb_fix_screeninfo fix;
                /*获取可变参数*/
                case FBIOGET_VSCREENINFO:
                   return copy_to_user(argp, &info->var,
                     sizeof(var)) ? -EFAULT : 0;
3.app:mmap
    sys_mmap
      进入最上层的fbmem.c
       file_operations--->fb_fops.mmap  =fb_mmap
                 int fbidx = iminor(file->f_path.dentry->d_inode);
                 struct fb_info *info = registered_fb[fbidx];
                 struct fb_ops *fb = info->fbops;
                 /*问:fb_info->fbops->fb_mmap是否存在
                    *究竟是否存在,需要看底层
                    */
                 if (fb->fb_mmap)
                   res = fb->fb_mmap(info, vma);
                 /* frame buffer物理地址*/
                  start = info->fix.smem_start;
                  /*按页对齐*/
                 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
                 io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
                    vma->vm_end - vma->vm_start, vma->vm_page_prot)

4.app:在用户空间的虚拟地址中进行画图

 


驱动怎么做的:

1.上层:(fbmem.c帧缓冲设备的通用接口层)
==================================================================
static const struct file_operations fb_fops = {
 .owner = THIS_MODULE,
 .read  = fb_read,
 .write  = fb_write,
 .ioctl  = fb_ioctl,
#ifdef CONFIG_COMPAT
 .compat_ioctl = fb_compat_ioctl,
#endif
 .mmap =  fb_mmap,
 .open =  fb_open,
 .release = fb_release,
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
 .get_unmapped_area = get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO
 .fsync = fb_deferred_io_fsync,
#endif
};

入口函数
 fbmem_init
   /*1.注册一个字符设备,申请设备号*/
   register_chrdev(FB_MAJOR,"fb",&fb_fops(提供给上层的操作方法))
   /*2.创建一个类*/
   fb_class = class_create(THIS_MODULE, "graphics");
   
2.底层(lcd控制器驱动层s3c2410fb.c)
==================================================================
入口函数
 s3c2410fb_init
    platform_driver_register(&s3c2410fb_driver);
      
s3c2410fb_probe分析:
1.构建一个结构体     //struct fb_info
struct s3c2410fb_info *info
struct fb_info    *fbinfo;

获取资源
mach_info = pdev->dev.platform_data;


irq = platform_get_irq(pdev, 0);
ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);

使能时钟:
info->clk = clk_get(NULL, "lcd");
 if (!info->clk || IS_ERR(info->clk)) {
  printk(KERN_ERR "failed to get lcd clock source\n");
  ret = -ENOENT;
  goto release_irq;
 }
clk_enable(info->clk);


2.分配空间
fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);

3.设置它
  3.1 设置固定参数    //fb_fix_screeninfo
    3.1.1 只需要这只物理显存,跟物理显存的大小
    
  3.2 设置可变参数    //fb_var_screeninfo
    3.2.1 图片的高度和宽度
    3.2.2 可视分辨率,虚拟分辨率
    3.2.3 时序--->需要配置到寄存器里面的
    3.2.4 RGB分别占用那几根线
 
  3.4 设置底层的操作方法
    fbinfo->fbops      = &s3c2410fb_ops;
    
  3.3 分配显存地址
    ret = s3c2410fb_map_video_memory(info);
 
初始化控制器
ret = s3c2410fb_init_registers(info);
    1.1 配置功能管脚  数据管脚时序管脚背光灯管脚   
    modify_gpio(S3C2410_GPCUP,  mach_info->gpcup,  mach_info->gpcup_mask);
  modify_gpio(S3C2410_GPCCON, mach_info->gpccon, mach_info->gpccon_mask);
  modify_gpio(S3C2410_GPDUP,  mach_info->gpdup,  mach_info->gpdup_mask);
  modify_gpio(S3C2410_GPDCON, mach_info->gpdcon, mach_info->gpdcon_mask);
   1.2 配置lcdcon1-lcdcon5  //配置时钟频率 配置时序 屏幕类型选择 
   writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);
  writel(fbi->regs.lcdcon2, S3C2410_LCDCON2);
  writel(fbi->regs.lcdcon3, S3C2410_LCDCON3);
  writel(fbi->regs.lcdcon4, S3C2410_LCDCON4);
  writel(fbi->regs.lcdcon5, S3C2410_LCDCON5);
   1.3 配置显存
   s3c2410fb_set_lcdaddr(fbi);
     saddr1  = fbi->fb->fix.smem_start >> 1;
    saddr2  = fbi->fb->fix.smem_start;
    saddr2 += (var->xres * var->yres * var->bits_per_pixel)/8;
    saddr2>>= 1;
   
    saddr3 =  S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH((var->xres * var->bits_per_pixel / 16) & 0x3ff);
     writel(saddr1, S3C2410_LCDSADDR1);
    writel(saddr2, S3C2410_LCDSADDR2);
    writel(saddr3, S3C2410_LCDSADDR3);
   1.4 最后使能
   fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID;
   writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);
 
4.注册
register_frambuffer(struct fb_info)

                             
帧缓冲设备涉及的重要结构体与函数:
=======================================================
struct fb_info
{
  /*可变参数*/
  struct fb_var_screeninfo var; /* Current var */
  {
    __u32 xres;      /*可视分辨率,实际的屏幕大小*/
    __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   */

    /*RGB:565  红绿蓝分别占用哪几根线 */
    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 height;     /* height of picture in mm   240 */
      __u32 width;     /* width of picture in mm    320 */
     
      /*时序相关的*/
      __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_*  */
  }
  /*固定参数*/
  struct fb_fix_screeninfo fix; /* Current fix */
  {
    unsigned long smem_start; /* Start of frame buffer mem 物理显存的起始地址*/
    __u32 smem_len;   /* Length of frame buffer mem    物理显存的大小*/
    __u32 line_length;  /* length of a line in bytes    */
  }
  /*底层操作方法*/
  struct fb_ops *fbops;
  {
    
  }
  char __iomem *screen_base; /* Virtual address */
   unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */
   void *pseudo_palette;  /* Fake palette of 16 colors */
}
struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix;

static struct s3c2410fb_mach_info *mach_info;
struct s3c2410fb_mach_info {
 unsigned char fixed_syncs; /* do not update sync/border */

 /* LCD types */
 int  type;

 /* Screen size */
 int  width;
 int  height;

 /* Screen info */
 struct s3c2410fb_val xres;
 struct s3c2410fb_val yres;
 struct s3c2410fb_val bpp;

 /* lcd configuration registers */
 struct s3c2410fb_hw  regs;

 /* GPIOs */
 unsigned long gpcup;
 unsigned long gpcup_mask;
 unsigned long gpccon;
 unsigned long gpccon_mask;
 unsigned long gpdup;
 unsigned long gpdup_mask;
 unsigned long gpdcon;
 unsigned long gpdcon_mask;

 /* lpc3600 control register */
 unsigned long lpcsel;
};


帧缓冲设备涉及的重要函数接口:
=======================================================
register_frambuffer

 

 

启动信息:
s3c2410-lcd s3c2410-lcd: no platform data for lcd, cannot attach
 mach_info = pdev->dev.platform_data;  //但这个设备的Platform_data里面被初始化了些什么值呢?
 if (mach_info == NULL)
 {
  dev_err(&pdev->dev,"no platform data for lcd, cannot attach\n");
  return -EINVAL;
 }

 

s3c2410-lcd: probe of s3c2410-lcd failed with error -22

lcd测试程序:
static char *framebuffer_ptr
1.分配两个各缓冲区 buffer  bmpfilename 
2.打开图片文件
3.读取图片信息放入buffer缓冲区
4.初始化lcdinit_lcd
  4.1 开lcd设备
  framebuffer_fd = open("/dev/fb0", O_RDWR);
  4.2 获取固定参数信息
  ioctl(framebuffer_fd, FBIOGET_FSCREENINFO, &finfo)
  4.3 获取可变参数
  ioctl(framebuffer_fd, FBIOGET_VSCREENINFO, &vinfo)
  4.3 mmap进行映射
    framebuffer_ptr=(char *) mmap
  4.4 清0
  memset(framebuffer_ptr,0,screensize);
5.解码将jpg格式的图片解码为bmp格式
LoadJpegFile(buffer, bmpfilename) ;
6.由于lcd只能显示RGB的原始图片,再次解码,将bmp解码为RGB格式
draw_bmp(bmpfilename,(unsigned short *) framebuffer_ptr);

logo制作:
===========================================================
1.制作ppm各式图片
2.拷贝ppm图片到内核的driver/video/logo目录下
3.修改driver/video/logo目录下Makfile
在其中添加
obj-$(CONFIG_LOGO_FARSIGHT_CLUT224)     += logo_farsight_clut224.o
4.修改driver/video/logo目录下Kconfig
在其中添加
config LOGO_FARSIGHT_CLUT224
        bool "farsight Linux logo"
        default y
5.修改logo.c文件
添加
extern const struct linux_logo logo_farsight_clut224;
 #ifdef CONFIG_LOGO_FARSIGHT_CLUT224
                 /* Generic Linux logo */
                  logo = &logo_farsight_clut224;
  #endif
6.执行make menuconfig
-> Device Drivers                                                                                                                 │ 
         -> Graphics support
       [*]   farsight Linux logo (NEW)

 

 

 

 


 


  

 

 

 

 

0 0
原创粉丝点击