TA的每日心情 | 奋斗 2022-9-16 05:52 |
---|
签到天数: 1368 天 连续签到: 1 天 [LV.10]以坛为家III
|
本着从易到难的过程,现有程序完全基于那个最精简的驱动程序框架来实现,也就是字符设备+寄存器操作的方式,以后有时间再改为总线设备驱动。
pcDuino上有两个LED,TX和RX,就用它们来做实验了。
下面上代码,可参照《pcDuino Linux驱动开发二 -- 最简单的驱动程序框架》这个最精简的框架来看看增加的部分,无非就是多了些寄存器的操作:
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/fs.h>
- #include <linux/cdev.h>
- #include <linux/device.h>
- #include <asm/io.h>
- #include <asm/uaccess.h>
- #include "../A10.h"
- /**********************************************************************/
- #define LED_TX 15
- #define LED_RX 16
- #define LED_ON(Pin) (*REG_PH_DAT &= ~(0x1 << Pin))
- #define LED_OFF(Pin) (*REG_PH_DAT |= (0x1 << Pin) )
- #define LED_REVERSE(Pin) (*REG_PH_DAT ^= (0x1 << Pin) )
- volatile static unsigned long* REG_PH_CFG1;
- volatile static unsigned long* REG_PH_DAT;
- int Inited = 0;
- int LED_open(struct inode* n, struct file* f)
- {
- Inited++;
- if (Inited > 1) return Inited;
- REG_PH_CFG1 = (volatile unsigned long*) ioremap(PH_CFG1, 4);
- REG_PH_DAT = (volatile unsigned long*) ioremap(PH_DAT, 4);
- *REG_PH_CFG1 &= ~(0xF << 28);
- *REG_PH_CFG1 |= (0x1 << 28);
- LED_OFF(LED_TX);
- LED_OFF(LED_RX);
- printk("Open Finished!\n");
- return 0;
- }
- ssize_t LED_write(struct file* f, const char __user* buf, size_t len, loff_t* l)
- {
- unsigned char Buf[2];
- if (copy_from_user(&Buf, buf, len)) return -1;
- if ((Buf[0] != LED_TX) && (Buf[0] != LED_RX)) return -1;
- switch (Buf[1])
- {
- case 0:
- LED_OFF(Buf[0]);
- break;
- case 1:
- LED_ON(Buf[0]);
- break;
- case 2:
- LED_REVERSE(Buf[0]);
- break;
- default:
- return -1;
- }
- return len;
- }
- ssize_t LED_read(struct file* f, char __user* buf, size_t len, loff_t* l)
- {
- //int Buf;
- //copy_to_user(&Buf, buf, sizeof(int));
- printk("Read Finished!\n");
- return 0;
- }
- int LED_release(struct inode* n, struct file* f)
- {
- Inited--;
- if (Inited <= 0)
- {
- Inited = 0;
- return 0;
- }
- iounmap(REG_PH_CFG1);
- iounmap(REG_PH_DAT);
- printk("Release Finished!\n");
- return 0;
- }
- /**********************************************************************/
- #define DEV_NAME "LED"
- #define DEV_COUNT 1
- static dev_t Dev_Num;
- static struct cdev* pDev;
- static struct class* pClass;
- static struct file_operations fops =
- {
- .owner = THIS_MODULE,
- .open = LED_open,
- .write = LED_write,
- .read = LED_read,
- .release = LED_release,
- };
- static int __init LED_init(void)
- {
- int Result;
- Result = alloc_chrdev_region(&Dev_Num, 0, DEV_COUNT, DEV_NAME);
- if (Result)
- {
- printk("alloc_chrdev_region fail!\n");
- return Result;
- }
- pDev = cdev_alloc();
- if (pDev == NULL)
- {
- printk("cdev_alloc fail!\n");
- unregister_chrdev_region(Dev_Num, DEV_COUNT);
- return -1;
- }
- cdev_init(pDev, &fops);
- Result = cdev_add(pDev, Dev_Num, DEV_COUNT);
- if (Result)
- {
- printk("cdev_add fail!\n");
- cdev_del(pDev);
- return Result;
- }
- pClass = class_create(THIS_MODULE, DEV_NAME);
- if (pClass == NULL)
- {
- printk("class_create fail!\n");
- cdev_del(pDev);
- unregister_chrdev_region(Dev_Num, DEV_COUNT);
- return -1;
- }
- device_create(pClass, NULL, Dev_Num, "%s", DEV_NAME);
- printk("Init Finished!\n");
- return 0;
- }
- static void __exit LED_exit(void)
- {
- if (pClass)
- {
- device_destroy(pClass, Dev_Num);
- class_destroy(pClass);
- }
- if (pDev)
- {
- cdev_del(pDev);
- }
- unregister_chrdev_region(Dev_Num, DEV_COUNT);
- printk("Exit Finished!\n");
- }
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("LiuYang");
- module_init(LED_init);
- module_exit(LED_exit);
复制代码
这里没有实现Read函数,可以略过。
make 后生成LED.ko,使用insmod LED.ko加载模块,可以在/dev文件夹中看到,或者使用cat /proc/devices也可以看到。
调用rmmod LED后,该设备驱动模块被卸载,使用dmesg | tail -10来观察各个接口的加载情况,调试用。 |
|