platform驱动程序模板

来源:互联网 发布:淘宝店铺被处罚怎么办 编辑:程序博客网 时间:2024/06/06 12:53

是一个platform驱动的设计模板。

#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/mm.h>

#include <linux/platform_device.h>
#include <linux/cdev.h>

#include <asm/irq.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>

#define DEV_NAME   "HELLO"

#define BUFF_SIZE   32*1024
unsigned char *buffer;
unsigned char *kmalloc_area;

typedef struct _hello_dev
{
    unsigned char           major;
 dev_t                   dev_id;
 struct platform_device  *plat_dev;
 struct class            *cls;
 struct cdev             *char_dev;
 struct device           *dev;
}HELLO_DEV,*pHELLO_DEV;

static pHELLO_DEV   phello_dev;
static int hello_open(struct inode *pinode,struct file *pfile)
{
    return 0;
}

static int hello_release(struct inode *pinode,struct file *pfile)
{
    return 0;
}

static size_t hello_mmap(struct file *pfile,struct vm_area_struct *vma)
{
   /* unsigned long start;
 unsigned long len = 0;
 start = (unsigned long)buffer; 
 len = PAGE_ALIGN((start&~PAGE_MASK)+BUFF_SIZE);
 start &= PAGE_MASK;
 if(remap_pfn_range(vma,start,vma->vm_pgoff,len,vma->vm_page_prot))
  return -EAGAIN;*/
 int ret;
 ret = remap_pfn_range(vma,
               vma->vm_start,
               virt_to_phys((void*)((unsigned long)kmalloc_area)) >> PAGE_SHIFT,
               vma->vm_end-vma->vm_start,
               PAGE_SHARED);
    if(ret != 0)
 {
        return -EAGAIN;
    }
    return 0;
 printk(KERN_ALERT "mmap ok!/n");
    return 0;
}
static size_t hello_read(struct file *pfile,void __user *buff,size_t count,loff_t *plofft)
{
    return 0;
}
static size_t hello_write(struct file *pfile,void __user *buff,size_t count,loff_t *plofft)
{
    return 0;
}

struct file_operations hello_fops=
{
    .owner   = THIS_MODULE,
 .read    = (void(*))hello_read,
 .write   = (void(*))hello_write,
 .mmap    = (void(*))hello_mmap,
 .open    = (void(*))hello_open,
 .release = (void(*))hello_release,
};

static int __devinit hello_probe(struct platform_device *plat_dev)
{   
     int ret;
  printk("device %s-%d is delect",plat_dev->name,plat_dev->id);

  plat_dev->dev.devt = phello_dev->dev_id;
  cdev_init(phello_dev->char_dev,&hello_fops);
  phello_dev->char_dev->owner = THIS_MODULE;
  ret = cdev_add(phello_dev->char_dev,phello_dev->dev_id,1);
  if(ret)
  {
      printk("cdev add err!/n");
   goto cdev_add_err;
  }
  platform_set_drvdata(plat_dev,phello_dev->char_dev);
  phello_dev->dev = device_create(phello_dev->cls,NULL,phello_dev->dev_id,&(plat_dev->dev),DEV_NAME);
  if(IS_ERR(phello_dev->dev))
  {
      printk("device_create err!/n");
      goto device_create_err;
  }
  goto probe_ok;
device_create_err:
  device_destroy(phello_dev->cls,phello_dev->dev_id);
     platform_set_drvdata(plat_dev,NULL);
cdev_add_err:
  cdev_del(phello_dev->char_dev);
probe_ok:
        return 0;
}

static int __devexit hello_remove(struct platform_device *plat_dev)
{
     struct cdev *chrdev;
  chrdev = platform_get_drvdata(plat_dev);
  if(chrdev)
  {
       cdev_del(phello_dev->char_dev);
  }
     device_destroy(phello_dev->cls,phello_dev->dev_id);
     platform_set_drvdata(plat_dev,NULL);
  plat_dev->dev.devt = 0;
     return 0;
}

#ifdef CONFIG_PW
static int hello_suspend(struct platform_device *plat_dev, pm_message_t state)
{
     return 0;
}

static int hello_resume(struct platform_device  *plat_dev)
{
     return 0;
}

#else
#define hello_suspend  NULL
#define hello_resume   NULL
#endif

struct platform_driver hello_driver=
{
     .probe   = hello_probe,
  .remove  = __devexit_p(hello_remove),
#ifdef CONFIG_PW
     .suspend = hello_suspend,
     .resume  = hello_resume,
#endif
     .driver=
     {
         .name  = DEV_NAME,
   .owner = THIS_MODULE,
     },
};

static int __init  hello_init(void)
{
     int ret;
  unsigned int i;
  phello_dev = kmalloc(sizeof(HELLO_DEV),GFP_KERNEL);
  if(!(phello_dev && (phello_dev->char_dev)))
  {  
      ret = -ENOMEM;
      goto malloc_mem_err;
  }
  memset(phello_dev,0,sizeof(HELLO_DEV));
  phello_dev->char_dev = kmalloc(sizeof(struct cdev),GFP_KERNEL);
     memset(phello_dev->char_dev,0,sizeof(struct cdev));
#ifdef  DEV_MAJOR
     phello_dev->major =  DEV_MAJOR;
     phello_dev->dev_id = MKDEV(phello_dev->major,0);
#endif

     phello_dev->plat_dev = platform_device_alloc(DEV_NAME,0);
     ret = platform_device_add(phello_dev->plat_dev);
  if(ret<0)
  {
      goto platform_device_add_err;
  }

  if(phello_dev->major)
  {
      ret = register_chrdev_region(phello_dev->dev_id,1,DEV_NAME);
   if(ret < 0)
   {
    goto register_chrdev_err;

   }
  }
  else
  {
      ret = alloc_chrdev_region(&(phello_dev->dev_id),0,1,DEV_NAME);
   if(ret<0)
   {
      goto  register_chrdev_err;
   }
   phello_dev->major = MAJOR(phello_dev->dev_id);
  }
     printk("dev major is %d minor is %d/n",phello_dev->major,MINOR(phello_dev->dev_id));
  //add other source such as clk,irq,dma and so on
     buffer = kmalloc(BUFF_SIZE+2*PAGE_SIZE,GFP_KERNEL);
  kmalloc_area = (unsigned char *)(((unsigned long)buffer + PAGE_SIZE -1) & PAGE_MASK);
    
  for(i=0;i<256;i++)
  {
      *buffer = i+10;
    buffer++;
  }
  //creat class
  phello_dev->cls = class_create(THIS_MODULE,DEV_NAME);
  if(IS_ERR(phello_dev->cls))
  {
       goto class_create_err;
  }
     printk(KERN_ALERT "hello world !/n");
  platform_driver_register(&hello_driver);
  goto register_ok;
class_create_err:
register_chrdev_err:
     unregister_chrdev_region(phello_dev->dev_id, 1);
platform_device_add_err:
  platform_device_put(phello_dev->plat_dev);
malloc_mem_err:
  kfree(phello_dev);
register_ok:
  return ret;
}

static void __exit  hello_exit(void)
{
 
 platform_driver_unregister(&hello_driver);
 class_destroy(phello_dev->cls);
 unregister_chrdev_region(phello_dev->dev_id, 1);
 platform_device_unregister(phello_dev->plat_dev);
 kfree(buffer);
 kfree(phello_dev->char_dev);
 kfree(phello_dev);
    printk(KERN_ALERT "remove hello world!/n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");

 

 

原创粉丝点击