s5pc100 LED驱动

接上文,本文记录 led工程中 driver/目录下的3个文件 s5pc100_led.h s5pc100_leddriver.c Makefile

s5pc100_led.h 这个文件和上文一样,不列举了,主要是s5pc100_leddriver.c,先列出完整的函数内容:

  1. #include <linux/init.h>  
  2. #include <linux/module.h>  
  3. #include <linux/types.h>  
  4. #include <linux/fs.h>  
  5. #include <linux/proc_fs.h>  
  6. #include <linux/device.h>  
  7. #include <asm/uaccess.h>  
  8. #include <linux/ioport.h>  
  9. #include <asm/io.h>  
  10. #include <plat/gpio-cfg.h>  
  11. #include <linux/platform_device.h>  
  12. #include "s5pc100_led.h"  
  13.   
  14. //主设备和从设备号变量  
  15. static int led_major = 0;  
  16. static int led_minor = 0;  
  17.   
  18. #define mem_size 0x4    
  19. typedef unsigned int long U32;    
  20. //设备类别和设备变量  
  21. static struct class* led_class = NULL;  
  22. static struct led_android_dev* led_dev = NULL;  
  23.   
  24. //传统的设备文件操作方法  
  25. static int led_open(struct inode* inode, struct file* filp);  
  26. static int led_ioctl(struct inode *inode,struct file *file,unsigned int cmd, unsigned long arg);  
  27. //设备文件操作方法表  
  28. static struct file_operations led_fops = {  
  29.     .owner = THIS_MODULE,  
  30.     .open = led_open,  
  31.     .ioctl=led_ioctl,  
  32. };  
  33. //定义设备属性  
  34. //访问设置属性方法  
  35. static ssize_t led_val_show(struct device* dev, struct device_attribute* attr,  char* buf);  
  36. static ssize_t led_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count);  
  37. static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, led_val_show, led_val_store);  
  38. //访问设置属性方法  
  39.   
  40. //proc文件系统访问设备方法  
  41. static ssize_t led_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data);  
  42. static ssize_t led_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data);  
  43. //打开设备方法  
  44. static int led_open(struct inode* inode, struct file* filp) {  
  45.     struct led_android_dev* dev;  
  46.  //将自定义设备结构体保存在文件指针的私有数据域中,以便访问设备时拿来用  
  47.     dev = container_of(inode->i_cdev, struct led_android_dev, dev);  
  48.     filp->private_data = dev;  
  49.     unsigned long gpncon_reg;  
  50.     gpncon_reg&=0xfffffff0;//将N类引脚的最低一位配置为输出  
  51.     gpncon_reg|=0x00000001;   
  52.     *(volatile unsigned long *)(U32)led_dev->pc100_ncon=gpncon_reg;//典型应用 重点  
  53.     return 0;  
  54. }  
  55.   
  56. static int led_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg){   
  57.     unsigned int long Dat;  
  58.     if(arg>1){  
  59.         return -EINVAL;  
  60.     }  
  61.       
  62.     Dat=*(volatile unsigned long *)((U32)led_dev->pc100_ndat);  
  63.     switch(cmd){  
  64.         case 0: Dat|=0x00000001;printk("set led on\n");break;  
  65.         case 1: Dat|=0x00000000;printk("set led off\n");break;  
  66.         default :break;  
  67.     }  
  68.   
  69.     *(volatile unsigned long *)((U32)led_dev->pc100_ndat) = Dat;  
  70. }  
  71. //读取寄存器val的值到缓冲区buf中,内部使用  
  72. static ssize_t __led_get_val(struct led_android_dev* dev, char* buf) {  
  73.     int val = 0;  
  74.     if(down_interruptible(&(dev->sem))) {  //同步访问  
  75.      return -ERESTARTSYS;  
  76.   }  
  77.   val = dev->val;  
  78.   up(&(dev->sem));  
  79.   return snprintf(buf, PAGE_SIZE, "%d\n", val);  
  80. }  
  81. //把缓冲区buf的值写到设备寄存器val中去,内部使用  
  82. static ssize_t __led_set_val(struct led_android_dev* dev, const char* buf, size_t count) {  
  83.     int val = 0;  
  84.   val = simple_strtol(buf, NULL, 10); //将字符串转换成数字  
  85.   if(down_interruptible(&(dev->sem))) {//同步访问  
  86.      return -ERESTARTSYS;  
  87.   }  
  88.     
  89.   dev->val = val;  
  90.   up(&(dev->sem));  
  91.     return count;  
  92. }  
  93. //读取设备属性val  
  94. static ssize_t led_val_show(struct device* dev, struct device_attribute* attr, char* buf) {  
  95.     struct led_android_dev* hdev = (struct led_android_dev*)dev_get_drvdata(dev);  
  96.       
  97.         return __led_get_val(hdev, buf);  
  98. }  
  99. //写设备属性val  
  100. static ssize_t led_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) {  
  101.     struct led_android_dev* hdev = (struct led_android_dev*)dev_get_drvdata(dev);  
  102.   return __led_set_val(hdev, buf,count);  
  103. }  
  104. //读取设备寄存器val的值,保存在page缓冲区中  
  105. static ssize_t led_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data) {  
  106.     if(off > 0) {  
  107.         *eof = 1;  
  108.         return 0;  
  109.     }  
  110.       
  111.     return __led_get_val(led_dev, page);      
  112. }  
  113. //把缓冲区的值buff保存到设备寄存器val中去  
  114. static ssize_t led_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data) {    
  115.     int err = 0;  
  116.     char* page = NULL;  
  117.     if(len > PAGE_SIZE) {  
  118.         printk(KERN_ALERT"The buff is too large: %lu.\n", len);  
  119.         return -EFAULT;  
  120.     }  
  121.       
  122.     page = (char*)__get_free_page(GFP_KERNEL);  
  123.     if(!page) {  
  124.                 printk(KERN_ALERT"Failed to alloc page.\n");  
  125.         return -ENOMEM;  
  126.     }  
  127.           
  128.     if(copy_from_user(page, buff, len)) {//先把用户提供的缓冲区值拷贝到内核缓冲区中去  
  129.         printk(KERN_ALERT"Failed to copy buff from user.\n");  
  130.                 err = -EFAULT;  
  131.         goto out;  
  132.     }  
  133.       
  134.     err = __led_set_val(led_dev, page, len);  
  135. out:  
  136.     free_page((unsigned long)page);  
  137.     return err;   
  138. }  
  139.   
  140. static void led_create_proc(void) {//创建/proc/led文件  
  141.     struct proc_dir_entry* entry;  
  142.     entry = create_proc_entry(LED_DEVICE_PROC_NAME, 0, NULL);  
  143.     if(entry) {  
  144.         entry->owner = THIS_MODULE;  
  145.         entry->read_proc = led_proc_read;  
  146.         entry->write_proc = led_proc_write;  
  147.     }  
  148. }  
  149.   
  150. static void led_remove_proc(void) {//删除/proc/led文件  
  151.     remove_proc_entry(LED_DEVICE_PROC_NAME, NULL);  
  152. }  
  153.   
  154. static int  __led_setup_dev(struct led_android_dev* dev) {//初始化设备  
  155.     int err;  
  156.     dev_t devno = MKDEV(led_major, led_minor);  
  157.     memset(dev, 0, sizeof(struct led_android_dev));  
  158.     cdev_init(&(dev->dev), &led_fops);  
  159.     dev->dev.owner = THIS_MODULE;  
  160.     dev->dev.ops = &led_fops;  
  161.     err = cdev_add(&(dev->dev),devno, 1);//注册字符设备  
  162.     if(err) {  
  163.         return err;  
  164.     }     
  165.   
  166.     init_MUTEX(&(dev->sem));//初始化信号量和寄存器val的值  
  167.     dev->val = 0;  
  168.     return 0;  
  169. }  
  170.   
  171. void init_led(void){  
  172.     int err = -1;  
  173.     dev_t dev = 0;  
  174.     struct device* temp = NULL;  
  175.     printk(KERN_ALERT"Initializing led device.\n");  
  176.     err = alloc_chrdev_region(&dev, 0, 1, LED_DEVICE_NODE_NAME);//动态分配主设备和从设备号  
  177.     if(err < 0) {  
  178.         printk(KERN_ALERT"Failed to alloc char dev region.\n");  
  179.         goto fail;  
  180.     }  
  181.       
  182.     led_major = MAJOR(dev);  
  183.     led_minor = MINOR(dev);  
  184.     led_dev = kmalloc(sizeof(struct led_android_dev), GFP_KERNEL);//分配led设备结构体变量  
  185.     if(!led_dev) {  
  186.         err = -ENOMEM;  
  187.         printk(KERN_ALERT"Failed to alloc led_dev.\n");  
  188.         goto unregister;  
  189.     }  
  190.   
  191.     err = __led_setup_dev(led_dev);//初始化设备  
  192.     if(err) {  
  193.         printk(KERN_ALERT"Failed to setup dev: %d.\n", err);  
  194.         goto cleanup;  
  195.     }  
  196.       
  197.     led_class = class_create(THIS_MODULE, LED_DEVICE_CLASS_NAME);//在/sys/class/目录下创建设备类别目录led  
  198.     if(IS_ERR(led_class)) {  
  199.         err = PTR_ERR(led_class);  
  200.         printk(KERN_ALERT"Failed to create led class.\n");  
  201.         goto destroy_cdev;  
  202.     }  
  203.   
  204.     temp = device_create(led_class, NULL, dev, "%s", LED_DEVICE_FILE_NAME);//在/dev/目录和/sys/class/led目录下分别创建设备文件led  
  205.     if(IS_ERR(temp)) {  
  206.         err = PTR_ERR(temp);  
  207.         printk(KERN_ALERT"Failed to create led device.");  
  208.         goto destroy_class;  
  209.     }  
  210.     err = device_create_file(temp, &dev_attr_val);//在/sys/class/led/led目录下创建属性文件val  
  211.     if(err < 0) {  
  212.         printk(KERN_ALERT"Failed to create attribute val.");  
  213.                 goto destroy_device;  
  214.     }  
  215.     dev_set_drvdata(temp, led_dev);  
  216.     led_create_proc();//创建/proc/led文件  
  217.     printk(KERN_ALERT"Succedded to initialize led device.\n");  
  218.     return 0;  
  219. destroy_device:  
  220.     device_destroy(led_class, dev);  
  221. destroy_class:  
  222.     class_destroy(led_class);  
  223. destroy_cdev:  
  224.     cdev_del(&(led_dev->dev));     
  225. cleanup:  
  226.     kfree(led_dev);  
  227. unregister:  
  228.     unregister_chrdev_region(MKDEV(led_major, led_minor), 1);     
  229. fail:  
  230.     return err;  
  231. }  
  232.   
  233. int led_driver_probe(struct platform_device *pdev)  
  234. {//查询特定设备是否存在,以及是否能够才操作该设备,然后再进行设备操作。  
  235.     //check_led();  //自己假设一下检查设备  
  236.     unsigned long phys,virt;  
  237.     //struct resource *mm;  
  238.     init_led();  
  239.     //mm=platform_get_resource(pdev,IORESOURCE_MEM,0);//关键函数 获取 设备的资源 io 内存  dma 等 这里获取io内存  
  240.     phys = pdev->resource[0].start;  
  241.     //struct led_plat_data *pdatapdev->dev.platform_data;//获得设备的私有数据  
  242.     virtioremap(phys, 8);  
  243.     led_dev->pc100_ncon = virt + 0x0;  
  244.     led_dev->pc100_ndat = virt + 0x4;  
  245.   return 0;  
  246. }  
  247.   
  248. int led_driver_remove(struct platform_device *dev){  
  249.     dev_t devno = MKDEV(led_major, led_minor);  
  250.     printk(KERN_ALERT"Destroy led device.\n");  
  251.     led_remove_proc(); //删除/proc/led文件  
  252.     if(led_class) {//销毁设备类别和设备  
  253.         device_destroy(led_class, MKDEV(led_major, led_minor));  
  254.         class_destroy(led_class);  
  255.     }  
  256.     if(led_dev) {//删除字符设备和释放设备内存  
  257.         cdev_del(&(led_dev->dev));  
  258.         kfree(led_dev);  
  259.     }  
  260.     unregister_chrdev_region(devno, 1);//释放设备号  
  261.     return 0;  
  262. }  
  263.   
  264. struct platform_driver led_drv = {//结构体中不需要指定总线的成员,交由platform_device_register来完成  
  265.     .probe = led_driver_probe,  
  266.     .remove = led_driver_remove,  
  267.     .driver = {  
  268.         .name = "led",  //在/sys/中的驱动目录名字  
  269.         .owner = THIS_MODULE,  
  270.     },  
  271. };  
  272.   
  273. static int __init led_driver_init(void){  
  274.     int ret;  
  275.     ret = platform_driver_register(&led_drv);//驱动注册,注册成功后在/sys/platform/led/driver目录下创建目录  
  276.     if(ret){  
  277.         printk("driver register failed!\n");  
  278.         return ret;   
  279.     }  
  280.     printk("led driver init\n");  
  281.     return 0;  
  282. }  
  283.   
  284. static void __exit led_driver_exit(void){  
  285.     platform_driver_unregister(&led_drv);  
  286.     printk("led driver bye!\n");  
  287. }  
  288.   
  289. module_init(led_driver_init);  
  290. module_exit(led_driver_exit);  
  291.   
  292. MODULE_LICENSE("GPL");  
  293. MODULE_AUTHOR("kevin"); 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值