马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
- 1.注册字符设备驱动
- int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops)
- 功能:进行字符设备驱动的注册,申请了256个次设备号(0-255)
- 参数:
- major: >0:手动指定的当前驱动的主设备号
- ==0:由系统内核动态分配一个主设备号
- name:设备名或者驱动名
- fops:操作方法对象指针
- /*
- 应用程序调用文件操作接口对设备文件进行操作时,驱动中要有操作方法被回调,想要这些操作方法被回调,需要将
- 操作方法的指针放在一个操作方法对象中进行统一管理
- struct file_operations {
- int (*open) (struct inode *, struct file *);
- ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
- ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
- int (*release) (struct inode *, struct file *);
- };
- */
- 返回值:
- 调用失败返回错误码
- 成功:
- major==0,成功返回动态申请的主设备号
- major>0,成功返回0
复制代码- 2.注销字符设备驱动
- void unregister_chrdev(unsigned int major, const char *name)
- 功能:进行字符设备驱动的注销
- 参数:
- major:注册时得到的主设备号
- name:注册时填写的设备名
- 返回值:无
复制代码
led.c
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/fs.h>
- #include <linux/uaccess.h>
- #include <linux/io.h>
- #define LED1_PHY_GPIO_MODER 0x50006000
- #define LED1_PHY_GPIO_ODR 0x50006014
- #define LED1_PHY_RCC_GPIO 0x50000A28
- #define LED2_PHY_GPIO_MODER 0x50007000
- #define LED2_PHY_GPIO_ODR 0x50007014
- #define LED2_PHY_RCC_GPIO 0x50000A2C
- #define LED3_PHY_GPIO_MODER 0x50006000
- #define LED3_PHY_GPIO_ODR 0x50006014
- #define LED3_PHY_RCC_GPIO 0x50000A28
- unsigned int major; // 保存主设备号
- char kbuf[128] = {0};
- unsigned int *led1_vir_moder;
- unsigned int *led1_vir_odr;
- unsigned int *led1_vir_rcc;
- unsigned int *led2_vir_moder;
- unsigned int *led2_vir_odr;
- unsigned int *led2_vir_rcc;
- unsigned int *led3_vir_moder;
- unsigned int *led3_vir_odr;
- unsigned int *led3_vir_rcc;
- // 封装各种操作方法
- int myled_open(struct inode *inode, struct file *file) {
- printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
- return 0;
- }
- ssize_t myled_read(struct file *file, char __user *ubuf, size_t size, loff_t *lft) {
- unsigned long ret = copy_to_user(ubuf, kbuf, size);
- if (ret) {
- printk("copy_to_user failed\n");
- return -ret;
- }
- return 0;
- }
- ssize_t myled_write(struct file *file, const char __user *ubuf, size_t size, loff_t *lft) {
- unsigned long ret = copy_from_user(kbuf, ubuf, size);
- if (ret) {
- printk("copy_from_user failed\n");
- return -ret;
- }
- if (strcmp(kbuf, "1") == 0) { // 点亮 LED1
- *led1_vir_odr |= (0x1 << 10);
- printk("点亮 LED1\n");
- } else if (strcmp(kbuf, "2") == 0) { // 点亮 LED2
- *led2_vir_odr |= (0x1 << 10);
- printk("点亮 LED2\n");
- } else if (strcmp(kbuf, "3") == 0) { // 点亮 LED3
- *led3_vir_odr |= (0x1 << 8);
- printk("点亮 LED3\n");
- } else if (strcmp(kbuf, "0") == 0) { // 全部熄灭
- *led1_vir_odr &= ~(0x1 << 10);
- *led2_vir_odr &= ~(0x1 << 10);
- *led3_vir_odr &= ~(0x1 << 8);
- printk("全部熄灭\n\n");
- }
- return 0;
- }
- int myled_close(struct inode *inode, struct file *file) {
- printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
- return 0;
- }
- // 定义一个操作方法结构体变量
- struct file_operations fops = {
- .open = myled_open,
- .read = myled_read,
- .write = myled_write,
- .release = myled_close,
- };
- static int __init mycdev_init(void) {
- // 进行字符设备驱动的注册
- major = register_chrdev(0, "myled", &fops);
- if (major < 0) {
- printk("字符设备驱动注册失败\n");
- return major;
- }
- printk("字符设备驱动注册成功 major=%d\n", major);
- // 进行 LED1 寄存器的地址映射
- led1_vir_moder = ioremap(LED1_PHY_GPIO_MODER, 4);
- if (led1_vir_moder == NULL) {
- printk("LED1 物理内存映射失败%d\n", __LINE__);
- return -ENOMEM;
- }
- led1_vir_odr = ioremap(LED1_PHY_GPIO_ODR, 4);
- if (led1_vir_odr == NULL) {
- printk("LED1 物理内存映射失败%d\n", __LINE__);
- iounmap(led1_vir_moder);
- return -ENOMEM;
- }
- led1_vir_rcc = ioremap(LED1_PHY_RCC_GPIO, 4);
- if (led1_vir_rcc == NULL) {
- printk("LED1 物理内存映射失败%d\n", __LINE__);
- iounmap(led1_vir_moder);
- iounmap(led1_vir_odr);
- return -ENOMEM;
- }
- // 进行 LED2 寄存器的地址映射
- led2_vir_moder = ioremap(LED2_PHY_GPIO_MODER, 4);
- if (led2_vir_moder == NULL) {
- printk("LED2 物理内存映射失败%d\n", __LINE__);
- iounmap(led1_vir_moder);
- iounmap(led1_vir_odr);
- iounmap(led1_vir_rcc);
- return -ENOMEM;
- }
- led2_vir_odr = ioremap(LED2_PHY_GPIO_ODR, 4);
- if (led2_vir_odr == NULL) {
- printk("LED2 物理内存映射失败%d\n", __LINE__);
- iounmap(led1_vir_moder);
- iounmap(led1_vir_odr);
- iounmap(led1_vir_rcc);
- iounmap(led2_vir_moder);
- return -ENOMEM;
- }
- led2_vir_rcc = ioremap(LED2_PHY_RCC_GPIO, 4);
- if (led2_vir_rcc == NULL) {
- printk("LED2 物理内存映射失败%d\n", __LINE__);
- iounmap(led1_vir_moder);
- iounmap(led1_vir_odr);
- iounmap(led1_vir_rcc);
- iounmap(led2_vir_moder);
- iounmap(led2_vir_odr);
- return -ENOMEM;
- }
- // 进行 LED3 寄存器的地址映射
- led3_vir_moder = ioremap(LED3_PHY_GPIO_MODER, 4);
- if (led3_vir_moder == NULL) {
- printk("LED3 物理内存映射失败%d\n", __LINE__);
- iounmap(led1_vir_moder);
- iounmap(led1_vir_odr);
- iounmap(led1_vir_rcc);
- iounmap(led2_vir_moder);
- iounmap(led2_vir_odr);
- iounmap(led2_vir_rcc);
- return -ENOMEM;
- }
- led3_vir_odr = ioremap(LED3_PHY_GPIO_ODR, 4);
- if (led3_vir_odr == NULL) {
- printk("LED3 物理内存映射失败%d\n", __LINE__);
- iounmap(led1_vir_moder);
- iounmap(led1_vir_odr);
- iounmap(led1_vir_rcc);
- iounmap(led2_vir_moder);
- iounmap(led2_vir_odr);
- iounmap(led2_vir_rcc);
- iounmap(led3_vir_moder);
- return -ENOMEM;
- }
- led3_vir_rcc = ioremap(LED3_PHY_RCC_GPIO,4);
- if (led3_vir_rcc == NULL) {
- printk("LED3 物理内存映射失败%d\n", __LINE__);
- iounmap(led1_vir_moder);
- iounmap(led1_vir_odr);
- iounmap(led1_vir_rcc);
- iounmap(led2_vir_moder);
- iounmap(led2_vir_odr);
- iounmap(led2_vir_rcc);
- iounmap(led3_vir_moder);
- iounmap(led3_vir_odr);
- return -ENOMEM;
- }
- printk("物理内存映射成功\n");
- //PE10设置为输出
- (*led1_vir_moder) &= (~(0X3<<20));
- (*led1_vir_moder) |= (0x1<<20);
- //让PE10默认输出低电平
- (*led1_vir_odr) &= (~(0X1<<10));
- //PF10设置为输出
- (*led2_vir_moder) &= (~(0X3<<20));
- (*led2_vir_moder) |= (0x1<<20);
- //让PF10默认输出低电平
- (*led2_vir_odr) &= (~(0X1<<10));
- //PE8设置为输出
- (*led3_vir_moder) &= (~(0X3<<16));
- (*led3_vir_moder) |= (0x1<<16);
- //让PE8默认输出低电平
- (*led3_vir_odr) &= (~(0X1<<8));
-
- return 0;
- }
- static void __exit mycdev_exit(void)
- {
- //取消物理内存的映射
- iounmap(led1_vir_moder);
- iounmap(led1_vir_odr);
- iounmap(led1_vir_rcc);
- iounmap(led2_vir_moder);
- iounmap(led2_vir_odr);
- iounmap(led2_vir_rcc);
- iounmap(led3_vir_moder);
- iounmap(led3_vir_odr);
- iounmap(led3_vir_rcc);
- //进行字符设备驱动的注销
- unregister_chrdev(major,"myled");
- }
- module_init(mycdev_init);
- module_exit(mycdev_exit);
- MODULE_LICENSE("GPL");
复制代码 app.c
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <string.h>
-
- int main(int argc, char const *argv[])
- {
- int fd = open("/dev/myLed", O_RDWR);
- if (fd < 0) {
- printf("设备文件打开失败\n");
- return -1;
- }
-
- char cmd[2] = {0}; // 优化缓冲区大小
-
- while(1) {
- // LED1亮
- cmd[0] = '1';
- if(write(fd, cmd, sizeof(cmd)) < 0) {
- perror("write error");
- break;
- }
- sleep(1); // 延时1秒
-
- // LED2亮(保持LED1亮)
- cmd[0] = '2';
- write(fd, cmd, sizeof(cmd));
- sleep(1);
-
- // LED3亮(保持前两盏亮)
- cmd[0] = '3';
- write(fd, cmd, sizeof(cmd));
- sleep(1);
-
- // 全部熄灭
- cmd[0] = '0';
- write(fd, cmd, sizeof(cmd));
- sleep(1); // 全灭保持1秒
- }
-
- close(fd);
- return 0;
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |