萝卜头IT论坛

搜索
查看: 3240|回复: 3
收起左侧

上课了分享[arm驱动]linux内核时钟完整代码

[复制链接]
发表于 2017-5-31 11:09:56 | 显示全部楼层 |阅读模式
//“timerlist_drv”,"timerlist_"
#include <linux/module.h>//模块所需的大量符号和函数定义
#include <linux/kernel.h>
#include <linux/fs.h>//文件系统相关的函数和头文件
#include <linux/init.h> //指定初始化和清除函数
#include <linux/delay.h>
#include <linux/cdev.h> //cdev结构的头文件包含<linux/kdev_t.h>
#include <linux/device.h>
#include <linux/mm.h>
//#include <linux/sched.h>//包含驱动程序使用的大部分内核API的定义,包括睡眠函数以及各种变量声明
#include <asm/uaccess.h>//在内核和用户空间中移动数据的函数
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/timer.h>  /*timer*/
#include <asm/uaccess.h>  /*jiffies*/
#define VIRTUALDISK_SIZE  0x1000//4k
#define MEM_CLEAR 0x1
#define VIRTUALDISK_MAJOR 250
/******timer *******/
#define TIMERDELAY 2
int VirtualDisk_major = VIRTUALDISK_MAJOR;
struct VirtualDisk{
    struct cdev cdev;//详细看cdev机制
    unsigned char mem[VIRTUALDISK_SIZE ];
    long count;          /*记录设备目前被多少设备打开*/
    struct timer_list mytimer;
};
static struct class *timerlist_class;
static struct class_device    *timerlist_class_dev;
struct VirtualDisk *VirtualDiskp;
/*********timer opration*************/
static void domytimer(unsigned long arg){//just used by follow function
    struct VirtualDisk* myVirtualDiskp = (struct VirtualDisk *)(arg);
    printk("arg is %ld\n", myVirtualDiskp->mytimer.expires);
    myVirtualDiskp->mytimer.expires = jiffies + (TIMERDELAY*HZ);
    add_timer(&myVirtualDiskp->mytimer);
}
static void initMytimer(struct VirtualDisk *myVirtualDiskp, int delay){
    init_timer(&myVirtualDiskp->mytimer);
    myVirtualDiskp->mytimer.data = (unsigned long) myVirtualDiskp;
    myVirtualDiskp->mytimer.function = &domytimer;
    myVirtualDiskp->mytimer.expires = jiffies + (delay*HZ);
    add_timer(&myVirtualDiskp->mytimer);
}
/*********timer opration over*************/
static int timerlist_drv_open(struct inode *inode, struct file *file)
{
    printk("timerlist_dev read\n");
    file->private_data = VirtualDiskp;
    VirtualDiskp->count++;    /*增加设备打开次数*/
    return 0;
}
static int timerlist_drv_release(struct inode *inode, struct file *file)
{
    printk("timerlist_dev release\n");
    VirtualDiskp->count--;  /*减少设备打开次数*/
    return 0;
}
/*seek文件定位函数:seek()函数对文件定位的起始地址可以是文件开头(SEEK_SET,0)、当前位置(SEEK_CUR,1)、文件尾(SEEK_END,2)*/
static loff_t timerlist_drv_llseek(struct file *file, loff_t offset, int origin){
    loff_t ret = 0;/*返回的位置偏移*/
  switch (origin)
  {
    case SEEK_SET:   /*相对文件开始位置偏移*/
      if (offset < 0)/*offset不合法*/
      {
        ret =  - EINVAL;    /*无效的指针*/
        break;
      }
      if ((unsigned int)offset > VIRTUALDISK_SIZE)/*偏移大于设备内存*/
      {
        ret =  - EINVAL;    /*无效的指针*/
        break;
      }
      file->f_pos = (unsigned int)offset;  /*更新文件指针位置*/
      ret = file->f_pos;/*返回的位置偏移*/
      break;
    case SEEK_CUR:   /*相对文件当前位置偏移*/
      if ((file->f_pos + offset) > VIRTUALDISK_SIZE)/*偏移大于设备内存*/
      {
        ret =  - EINVAL;/*无效的指针*/
        break;
      }
      if ((file->f_pos + offset) < 0)/*指针不合法*/
      {
        ret =  - EINVAL;/*无效的指针*/
        break;
      }
      file->f_pos += offset;/*更新文件指针位置*/
      ret = file->f_pos;/*返回的位置偏移*/
      break;
    default:
      ret =  - EINVAL;/*无效的指针*/
      break;
  }
  return ret;
}
/*设备控制函数:ioctl()函数接受的MEM_CLEAR命令,这个命令将全局内存的有效数据长度清零,对于设备不支持的命令,ioctl()函数应该返回-EINVAL*/
static int timerlist_drv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){
     struct VirtualDisk *devp = file->private_data;/*获得设备结构体指针*/
    switch (cmd)
    {
    case MEM_CLEAR:/*设备内存清零*/
      memset(devp->mem, 0, VIRTUALDISK_SIZE);
      printk(KERN_INFO "VirtualDisk is set to zero\n");
      break;
    default:
      return  - EINVAL;
    }
    return 0;
}
/*读函数:读写函数主要是让设备结构体的mem[]数组与用户空间交互数据,并随着访问字节数变更返回用户的文件读写偏移位置*/
static ssize_t timerlist_drv_read(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
   printk("timerlist_dev read\n");
   unsigned long p =  *ppos; /*记录文件指针偏移位置*/
  unsigned int countt = count;/*记录需要读取的字节数*/
  int ret = 0;    /*返回值*/
  struct VirtualDisk *devp = file->private_data; /*获得设备结构体指针*/
  /*分析和获取有效的读长度*/
  if (p >= VIRTUALDISK_SIZE )  /*要读取的偏移大于设备的内存空间*/
    return countt ?  - ENXIO: 0;/*读取地址错误*/
  if (countt > VIRTUALDISK_SIZE  - p)/*要读取的字节大于设备的内存空间*/
    countt = VIRTUALDISK_SIZE  - p;/*将要读取的字节数设为剩余的字节数*/
/*内核空间->用户空间交换数据*/
  if (copy_to_user(buf, (void*)(devp->mem + p), countt))
  {
    ret =  - EFAULT;
  }
  else
  {
    *ppos += countt;
    ret = countt;
    printk("read %d bytes(s) is  %ld\n", countt, p);
  }
    printk("bytes(s) is  %s\n", buf);
initMytimer(devp, 2);
  return ret;
}
/*
file 是文件指针,count 是请求的传输数据长度,buff 参数是指向用户空间的缓冲区,这个缓冲区或者保存要写入的数据,或者是一个存放新读入数据的空缓冲区,该地址在内核空间不能直接读写,ppos 是一个指针指向一个"long offset type"对象, 它指出用户正在存取的文件位置. 返回值是一个"signed size type。写的位置相对于文件开头的偏移。
*/
static ssize_t timerlist_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
    printk("timerlist_dev write\n");
     unsigned long p =  *ppos; /*记录文件指针偏移位置*/
  int ret = 0;  /*返回值*/
  unsigned int countt = count;/*记录需要写入的字节数*/
  struct VirtualDisk *devp = file->private_data; /*获得设备结构体指针*/
  /*分析和获取有效的写长度*/
  if (p >= VIRTUALDISK_SIZE )/*要写入的偏移大于设备的内存空间*/
    return countt ?  - ENXIO: 0;/*写入地址错误*/
  if (countt > VIRTUALDISK_SIZE  - p)/*要写入的字节大于设备的内存空间*/
    countt = VIRTUALDISK_SIZE  - p;/*将要写入的字节数设为剩余的字节数*/
  /*用户空间->内核空间*/
  if (copy_from_user(devp->mem + p, buf, countt))
    ret =  - EFAULT;
  else
  {
    *ppos += countt;/*增加偏移位置*/
    ret = countt;/*返回实际的写入字节数*/
    printk("written %d bytes(s) from%ld\n", countt, p);
  }
  return ret;
    return 0;
}
static struct file_operations timerlist_drv_fops = {
    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .read = timerlist_drv_read,
    .write    =    timerlist_drv_write,
    .open   =   timerlist_drv_open,
    .release = timerlist_drv_release,
    .llseek = timerlist_drv_llseek,
    .ioctl = timerlist_drv_ioctl,
};
/*将 cdev 结构嵌入一个你自己的设备特定的结构,你应当初始化你已经分配的结构使用以上函数,有一个其他的 struct cdev 成员你需要初始化. 象 file_operations 结构,struct cdev 有一个拥有者成员,应当设置为 THIS_MODULE,一旦 cdev 结构建立, 最后的步骤是把它告诉内核, 调用:
   cdev_add(&dev->cdev, devno, 1);*/
static void VirtualDisk_setup_cdev(struct VirtualDisk *dev, int minorIndex){
    int err;
    int devno = MKDEV(VirtualDisk_major, minorIndex);
    cdev_init(&dev->cdev, &timerlist_drv_fops);
    dev->cdev.owner = THIS_MODULE;
    err = cdev_add(&dev->cdev, devno, 1);
    if(err){
    printk("error %d cdev file added\n", err);
    }
}
static int timerlist_drv_init(void)
{
    int result;
    dev_t devno = MKDEV(VirtualDisk_major, 0);
    if(VirtualDisk_major){
    result = register_chrdev_region(devno, 1, "timerlist_dev");
    }else{
    result = alloc_chrdev_region(&devno, 0, 1, "timerlist_dev");
    VirtualDisk_major = MAJOR(devno);
    }
    if(result < 0 ){
    return result;
    }
    VirtualDiskp = kmalloc(sizeof(struct VirtualDisk), GFP_KERNEL);
    if(!VirtualDiskp){
    result = -ENOMEM;
    goto fail_malloc;
    }
    memset(VirtualDiskp, 0, sizeof(struct VirtualDisk));
    VirtualDisk_setup_cdev(VirtualDiskp, 0);
    timerlist_class = class_create(THIS_MODULE, "timerlist_drv");
    if (IS_ERR(timerlist_class))
        return PTR_ERR(timerlist_class);
    timerlist_class_dev = class_device_create(timerlist_class, NULL, MKDEV(VirtualDisk_major, 0), NULL, "timerlist_dev"); /* /dev/xyz */
    if (IS_ERR(timerlist_class_dev))
        return PTR_ERR(timerlist_class_dev);
    return 0;
    fail_malloc:
        unregister_chrdev_region(devno, 1);
        return result;
}
static void timerlist_drv_exit(void)
{
    if(VirtualDiskp)del_timer(&VirtualDiskp->mytimer);
    cdev_del(&VirtualDiskp->cdev);
    kfree(VirtualDiskp);
    unregister_chrdev_region(MKDEV(VirtualDisk_major, 0), 1);
    class_device_unregister(timerlist_class_dev);
    class_destroy(timerlist_class);
}
module_init(timerlist_drv_init);
module_exit(timerlist_drv_exit);
MODULE_LICENSE("GPL");
回复

使用道具 举报

发表于 2017-6-2 23:21:29 | 显示全部楼层
就一个源文件没啥意思
回复

使用道具 举报

发表于 2019-1-23 13:46:53 | 显示全部楼层
很强大的源码
回复

使用道具 举报

发表于 2019-2-14 19:56:08 | 显示全部楼层
How to use!?
回复

使用道具 举报

联系我们(Contact)|手机版|萝卜头IT论坛 ( 苏ICP备15050961号-1 )

GMT+8, 2024-4-26 01:24 , Processed in 0.102864 second(s), 21 queries , Gzip On.

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表