Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1156442
  • 博文数量: 241
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2279
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

JustForFun

文章分类

全部博文(241)

文章存档

2023年(8)

2022年(2)

2021年(3)

2020年(30)

2019年(11)

2018年(27)

2017年(54)

2016年(83)

2015年(23)

我的朋友

分类: LINUX

2016-10-02 16:11:14

来自zynq_book_v2 pwm_driver.c 
#include
#include
#include
#include
#include
#define DEVICE_NAME "PWM_MOUDLE"
#define PWM_MOUDLE_PHY_ADDR 0x43C00000  //This Address is based XPS
MODULE_AUTHOR("Xilinx XUP");
MODULE_DESCRIPTION("PWM moudle dirver");
MODULE_VERSION("v1.0");
MODULE_LICENSE("GPL");
 
static int pwm_driver_major;
static struct class* pwm_driver_class = NULL;
static struct device* pwm_driver_device = NULL;
unsigned long pwm_fre_addr = 0;  //pwm moulde's frequency visual address
unsigned long pwm_duty_addr = 0; //pwm moulde's duty visual address
static long frequency=0;
static struct file_operations pwm_driver_fops = {
    .owner = THIS_MODULE,
};
static ssize_t sys_pwm_frequency_set (struct device* dev, struct device_attribute* attr, const char* buf, size_t count)
{
    long value = 0;
    int i;
    frequency=0;
    iowrite32(value,  pwm_fre_addr); //close pwm moudle before we modfiy the frequency
    for (i = 0; i < count-1; i++){
        frequency  *= 10;
        frequency += buf[i] - '0';
    }
    if(value>100000000) value=100000000;
    value=100000000/frequency;  // 100Mhz/frequency 100Mhz is set by XPS
 
    iowrite32(value,  pwm_fre_addr);
    return count;
}

static ssize_t sys_pwm_duty_set (struct device* dev, struct device_attribute* attr, const char* buf, size_t count) //duty cycle
{
 long value = 0;
 int i;
 iowrite32(value,  pwm_duty_addr); //close pwm moudle before we modfiy the duty cycle
 
 for (i = 0; i < count-1; i++){
  value  *= 10;
  value += buf[i] - '0';
 }
 if (value>100)
  value=100;
 value = frequency * value / 100;
 if (value!= 0)
  value = value | 0x80000000;
 printk("duty:%ld\n", value);
 iowrite32(value,  pwm_duty_addr);
    return count;
}
static DEVICE_ATTR(pwm_frequency, S_IWUSR, NULL, sys_pwm_frequency_set);
static DEVICE_ATTR(pwm_duty, S_IWUSR, NULL, sys_pwm_duty_set);

static int __init pwm_driver_module_init(void)
{
    int ret;
//此处产生的pwm_driver_major后面device_create函数会用到
//向内核注册一个设备,返回值为注册的主设备号
    pwm_driver_major=register_chrdev(0, DEVICE_NAME, &pwm_driver_fops);
    if (pwm_driver_major < 0){
        printk("failed to register device.\n");
        return -1;
    }
//注册一个类,使mdev可以在"/dev/"目录下 面建立设备节点
//
一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面
    pwm_driver_class = class_create(THIS_MODULE, "pwm_driver");
    if (IS_ERR(pwm_driver_class)){
        printk("failed to create pwm moudle class.\n");
        unregister_chrdev(pwm_driver_major, DEVICE_NAME);
        return -1;
    }
    //创建一个设备节点,节点名为DEVICE_NAME

//如果成功,它将会在/dev目录下产生/dev/pwm_device设备。
//

//调用device_create(…)函数来在/dev目录下创建相应的设备节点
//
加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。
/**
 * device_create - creates a device and registers it with sysfs

the struct class 指针,必须在本函数调用之前先被创建

 * @class: pointer to the struct class that this device should be registered to
 * @parent: pointer to the parent struct device of this new device, if any
该设备的
parent指针。

 * @devt: the dev_t for the char device to be added字符设备的设备号,如果dev_t不是0,0的话,1”dev”文件将被创建。

 * @drvdata: the data to be added to the device for callbacks被添加到该设备回调的数据
 
* @fmt: string for the device's name   设备名字
*/ 

    pwm_driver_device = device_create(pwm_driver_class, NULL, MKDEV(pwm_driver_major, 0), NULL, "pwm_device");
    if (IS_ERR(pwm_driver_device)){
        printk("failed to create device .\n");
        unregister_chrdev(pwm_driver_major, DEVICE_NAME);
        return -1;
    }
   //利用device_create_file函数可以在/sys/class/下创建对应的属性文件,从而通过对该文件的读写实现特定的数据操作。
//使用这个函数时要引用 device_create所返回的device*指针
    ret = device_create_file(pwm_driver_device, &dev_attr_pwm_frequency);
    if (ret < 0)
        printk("failed to create pwm_frequency endpoint\n");
   
    ret = device_create_file(pwm_driver_device, &dev_attr_pwm_duty);
    if (ret < 0)
        printk("failed to create pwm_duty endpoint\n");
//将FPGA里某东东的物理地址映射到系统虚拟地址(用户)来操作
    pwm_fre_addr = (unsigned long)ioremap(PWM_MOUDLE_PHY_ADDR, 16);//To get Custom IP--PWM moudle's virtual address
    printk("basseaddr : %x\r\n", pwm_fre_addr);
   pwm_duty_addr = pwm_fre_addr + 4; 
           
    printk(" pwm driver initial successfully!\n");
    return 0;
}
 
static void __exit pwm_driver_module_exit(void)
{
  printk("exit module.\n");
    device_remove_file(pwm_driver_device, &dev_attr_pwm_frequency);
    device_remove_file(pwm_driver_device, &dev_attr_pwm_duty);
    device_destroy(pwm_driver_class, MKDEV(pwm_driver_major, 0));
    class_unregister(pwm_driver_class);
    class_destroy(pwm_driver_class);
    unregister_chrdev(pwm_driver_major, DEVICE_NAME);
    printk("pwm module exit.\n");
}
module_init(pwm_driver_module_init);
module_exit(pwm_driver_module_exit);

阅读(8719) | 评论(2) | 转发(1) |
给主人留下些什么吧!~~

MQWYY32019-11-11 15:01:50

很有参考价值

MQWYY32019-11-11 15:01:38

很有参考价值