day2 驱动开发 c语言

news2024/11/25 21:29:37

通过驱动开发给pcb板子点灯。

u-boot已经提前移植到了emmc中。

灯也是一种字符型设备。

编程流程需要先注册设备,然后创建结点,然后操作电灯相关寄存器

应用层直接调用read write来打开字符设备进行操作。

这样写会造成无法处理内核页面请求的虚拟地址内部错误,没找到解决方法

head.h

#ifndef __LED_H__
#define __LED_H__

typedef struct {
	volatile unsigned int TZCR;     	// 0x000
	volatile unsigned int res1[2]; 		// 0x004-0x008
	volatile unsigned int OCENSETR;     // 0x00C
	volatile unsigned int OCENCLRR;  	// 0x010
	volatile unsigned int res2[1]; 		// 0x014
	volatile unsigned int HSICFGR; 		// 0x018
	volatile unsigned int CSICFGR; 		// 0x01C
	volatile unsigned int MPCKSELR; 	// 0x020
	volatile unsigned int ASSCKSELR; 	// 0x024
	volatile unsigned int PCK12SELR; 	// 0x028
	volatile unsigned int MPCKDIVR; 	// 0x02C
	volatile unsigned int AXIDIVR; 		// 0x030
	volatile unsigned int res3[2];      
	volatile unsigned int APB4DIVR; 	// 0x03C
	volatile unsigned int APB5DIVR; 	// 0x040
	volatile unsigned int RTCDIVR; 		// 0x044
	volatile unsigned int MSSCKSELR;    // 0x048
	volatile unsigned int res4[13];
	volatile unsigned int PLL1CR; 		// 0x080
	volatile unsigned int PLL1CFGR1; 	// 0x084
	volatile unsigned int PLL1CFGR2; 	// 0x088
	volatile unsigned int PLL1FRACR; 	// 0x08C
	volatile unsigned int PLL1CSGR;     // 0x090
	volatile unsigned int PLL2CR; 		// 0x094
	volatile unsigned int PLL2CFGR1; 	// 0x098
	volatile unsigned int PLL2CFGR2; 	// 0x09C
	volatile unsigned int PLL2FRACR;    // 0x0A0
	volatile unsigned int PLL2CSGR;     // 0x0A4
	volatile unsigned int res5[6];
	volatile unsigned int I2C46CKSELR;  // 0x0C0
	volatile unsigned int SPI6CKSELR;   // 0x0C4
	volatile unsigned int UART1CKSELR;  // 0x0C8
	volatile unsigned int RNG1CKSELR;   // 0x0CC
	volatile unsigned int CPERCKSELR;   // 0x0D0
	volatile unsigned int STGENCKSELR;  // 0x0D4
	volatile unsigned int DDRITFCR; 	// 0x0D8
	volatile unsigned int res6[9];
	volatile unsigned int MP_BOOTCR;  	// 0x100
	volatile unsigned int MP_SREQSETR;  // 0x104
	volatile unsigned int MP_SREQCLRR;  // 0x108
	volatile unsigned int MP_GCR;  		// 0x10C
	volatile unsigned int MP_APRSTCR; 	// 0x110 
	volatile unsigned int MP_APRSTSR;   // 0x114
	volatile unsigned int res7[10];
	volatile unsigned int BDCR; 		// 0x140
	volatile unsigned int RDLSICR;  	// 0x144
	volatile unsigned int res8[14];
	volatile unsigned int APB4RSTSETR; 	// 0x180
	volatile unsigned int APB4RSTCLRR; 	// 0x184
	volatile unsigned int APB5RSTSETR;  // 0x188
	volatile unsigned int APB5RSTCLRR;  // 0x18C
	volatile unsigned int AHB5RSTSETR;  // 0x190
	volatile unsigned int AHB5RSTCLRR;  // 0x194
	volatile unsigned int AHB6RSTSETR;  // 0x198
	volatile unsigned int AHB6RSTCLRR;  // 0x19C
	volatile unsigned int TZAHB6RSTSELR;// 0x1A0
	volatile unsigned int TZAHB6RSTCLRR;// 0x1A4
	volatile unsigned int res9[22];
	volatile unsigned int MP_APB4ENSETR;// 0x200
	volatile unsigned int MP_APB4ENCLRR;// 0x204
	volatile unsigned int MP_APB5ENSETR;// 0x208
	volatile unsigned int MP_APB5ENCLRR;// 0x20C
	volatile unsigned int MP_AHB5ENSETR;// 0x210
	volatile unsigned int MP_AHB5ENCLRR;// 0x214
	volatile unsigned int MP_AHB6ENSETR;// 0x218
	volatile unsigned int MP_AHB6ENCLRR;// 0x21C
	volatile unsigned int MP_TZAHB6ENSELR;// 0x220
	volatile unsigned int MP_TZAHB6ENCLRR;// 0x224
	volatile unsigned int res10[22];
	volatile unsigned int MC_APB4ENSETR; // 0x280
	volatile unsigned int MC_APB4ENCLRR; // 0x284
	volatile unsigned int MC_APB5ENSETR; // 0x288
	volatile unsigned int MC_APB5ENCLRR; // 0x28C
	volatile unsigned int MC_AHB5ENSETR; // 0x290
	volatile unsigned int MC_AHB5ENCLRR; // 0x294
	volatile unsigned int MC_AHB6ENSETR; // 0x298
	volatile unsigned int MC_AHB6ENCLRR; // 0x29C
	volatile unsigned int res11[24];
	volatile unsigned int MP_APB4LPENSETR; // 0x300
	volatile unsigned int MP_APB4LPENCLRR; // 0x304
	volatile unsigned int MP_APB5LPENSETR; // 0x308
	volatile unsigned int MP_APB5LPENCLRR; // 0x30C
	volatile unsigned int MP_AHB5LPENSETR; // 0x310
	volatile unsigned int MP_AHB5LPENCLRR; // 0x314
	volatile unsigned int MP_AHB6LPENSETR; // 0x318
	volatile unsigned int MP_AHB6LPENCLRR; // 0x31C
	volatile unsigned int MP_TZAHB6LPENSETR; // 0x320
	volatile unsigned int MP_TZAHB6LPENCLRR; // 0x324
	volatile unsigned int res12[22];
	volatile unsigned int MC_APB4LPENSETR; // 0x380
	volatile unsigned int MC_APB4LPENCLRR; // 0x384
	volatile unsigned int MC_APB5LPENSETR; // 0x388
	volatile unsigned int MC_APB5LPENCLRR; // 0x38C
	volatile unsigned int MC_AHB5LPENSETR; // 0x390
	volatile unsigned int MC_AHB5LPENCLRR; // 0x394
	volatile unsigned int MC_AHB6LPENSETR; // 0x398
	volatile unsigned int MC_AHB6LPENCLRR; // 0x39C
	volatile unsigned int res13[24];
	volatile unsigned int BR_RSTSCLRR; 		// 0x400
	volatile unsigned int MP_GRSTCSETR; 	// 0x404
	volatile unsigned int MP_RSTSR; 		// 0x408 
	volatile unsigned int MP_IWDGFZSETR; 	// 0x40C
	volatile unsigned int MP_IWDGFZCLRR;  	// 0x410
	volatile unsigned int MP_CIER; 			// 0x414
	volatile unsigned int MP_CIFR; 			// 0x418
	volatile unsigned int PWRLPDLYCR; 		// 0x41C
	volatile unsigned int MP_RSTSS; 		// 0x420
	volatile unsigned int res14[247];
	volatile unsigned int MCO1CFGR; 		// 0x800
	volatile unsigned int MCO2CFGR; 		// 0x804 
	volatile unsigned int OCRDYR; 			// 0x808
	volatile unsigned int DBGCFGR; 			// 0x80C
	volatile unsigned int res15[4];
	volatile unsigned int RCK3SELR; 		// 0x820
	volatile unsigned int RCK4SELR; 		// 0x824
	volatile unsigned int TIMG1PRER;  		// 0x828
	volatile unsigned int TIMG2PRER; 		// 0x82C
	volatile unsigned int MCUDIVR; 			// 0x830
	volatile unsigned int APB1DIVR; 		// 0x834
	volatile unsigned int APB2DIVR; 		// 0x838
	volatile unsigned int APB3DIVR; 		// 0x83C
	volatile unsigned int res16[16];
	volatile unsigned int PLL3CR;   		// 0x880
	volatile unsigned int PLL3CFGR1; 		// 0x884
	volatile unsigned int PLL3CFGR2; 		// 0x888
	volatile unsigned int PLL3FRACR; 		// 0x88C
	volatile unsigned int PLL3CSGR; 		// 0x890
	volatile unsigned int PLL4CR; 			// 0x894
	volatile unsigned int PLL4CFGR1; 		// 0x898
	volatile unsigned int PLL4CFGR2; 		// 0x89C
	volatile unsigned int PLL4FRACR; 		// 0x8A0
	volatile unsigned int PLL4CSGR; 		// 0x8A4
	volatile unsigned int res17[6];
	volatile unsigned int I2C12CKSELR; 		// 0x8C0
	volatile unsigned int I2C35CKSELR;  	// 0x8C4
	volatile unsigned int SAI1CKSELR; 		// 0x8C8
	volatile unsigned int SAI2CKSELR; 		// 0x8CC
	volatile unsigned int SAI3CKSELR; 		// 0x8D0
	volatile unsigned int SAI4CKSELR; 		// 0x8D4
	volatile unsigned int SPI2S1CKSELR; 	// 0x8D8
	volatile unsigned int SPI2S23CKSELR; 	// 0x8DC
	volatile unsigned int SPI45CKSELR; 		// 0x8E0
	volatile unsigned int UART6CKSELR; 		// 0x8E4
	volatile unsigned int UART24CKSELR; 	// 0x8E8
	volatile unsigned int UART35CKSELR; 	// 0x8EC
	volatile unsigned int UART78CKSELR; 	// 0x8F0
	volatile unsigned int SDMMC12CKSELR; 	// 0x8F4
	volatile unsigned int SDMMC3CKSELR; 	// 0x8F8
	volatile unsigned int ETHCKSELR; 		// 0x8FC
	volatile unsigned int QSPICKSELR; 		// 0x900
	volatile unsigned int FMCCKSELR; 		// 0x904
	volatile unsigned int res18[1];
	volatile unsigned int FDCANCKSELR; 		// 0x90C
	volatile unsigned int res19[1];
	volatile unsigned int SPDIFCKSELR; 		// 0x914
	volatile unsigned int CECCKSELR; 		// 0x918
	volatile unsigned int USBCKSELR; 		// 0x91C
	volatile unsigned int RNG2CKSELR;  		// 0x920
	volatile unsigned int DSICKSELR; 		// 0x924
	volatile unsigned int ADCCKSELR; 		// 0x928
	volatile unsigned int LPTIM45CKSELR; 	// 0x92C
	volatile unsigned int LPTIM23CKSELR;    // 0x930
	volatile unsigned int LPTIM1CKSELR; 	// 0x934
	volatile unsigned int res20[18];
	volatile unsigned int APB1RSTSETR; 		// 0x980
	volatile unsigned int APB1RSTCLRR; 		// 0x984
	volatile unsigned int APB2RSTSETR; 		// 0x988
	volatile unsigned int APB2RSTCLRR; 		// 0x98C
	volatile unsigned int APB3RSTSETR; 		// 0x990
	volatile unsigned int APB3RSTCLRR; 		// 0x994
	volatile unsigned int AHB2RSTSETR; 		// 0x998
	volatile unsigned int AHB2RSTCLRR;  	// 0x99C
	volatile unsigned int AHB3RSTSETR; 		// 0x9A0
	volatile unsigned int AHB3RSTCLRR; 		// 0x9A4
	volatile unsigned int AHB4RSTSETR; 		// 0x9A8
	volatile unsigned int AHB4RSTCLRR; 		// 0x9AC
	volatile unsigned int res21[20];
	volatile unsigned int MP_APB1ENSETR; 	// 0xA00
	volatile unsigned int MP_APB1ENCLRR; 	// 0xA04
	volatile unsigned int MP_APB2ENSETR; 	// 0xA08
	volatile unsigned int MP_APB2ENCLRR;  	// 0xA0C
	volatile unsigned int MP_APB3ENSETR; 	// 0xA10
	volatile unsigned int MP_APB3ENCLRR; 	// 0xA14
	volatile unsigned int MP_AHB2ENSETR; 	// 0xA18
	volatile unsigned int MP_AHB2ENCLRR; 	// 0xA1C
	volatile unsigned int MP_AHB3ENSETR; 	// 0xA20
	volatile unsigned int MP_AHB3ENCLRR; 	// 0xA24
	volatile unsigned int MP_AHB4ENSETR; 	// 0xA28
	volatile unsigned int MP_AHB4ENCLRR; 	// 0xA2C
	volatile unsigned int res22[2];
	volatile unsigned int MP_MLAHBENSETR; 	// 0xA38
	volatile unsigned int MP_MLAHBENCLRR; 	// 0xA3C
	volatile unsigned int res23[16];
	volatile unsigned int MC_APB1ENSETR; 	// 0xA80
	volatile unsigned int MC_APB1ENCLRR; 	// 0xA84
	volatile unsigned int MC_APB2ENSETR; 	// 0xA88
	volatile unsigned int MC_APB2ENCLRR; 	// 0xA8C
	volatile unsigned int MC_APB3ENSETR; 	// 0xA90
	volatile unsigned int MC_APB3ENCLRR; 	// 0xA94
	volatile unsigned int MC_AHB2ENSETR; 	// 0xA98
	volatile unsigned int MC_AHB2ENCLRR; 	// 0xA9C
	volatile unsigned int MC_AHB3ENSETR; 	// 0xAA0
	volatile unsigned int MC_AHB3ENCLRR; 	// 0xAA4
	volatile unsigned int MC_AHB4ENSETR; 	// 0xAA8
	volatile unsigned int MC_AHB4ENCLRR; 	// 0xAAC
	volatile unsigned int MC_AXIMENSETR; 	// 0xAB0
	volatile unsigned int MC_AXIMENCLRR; 	// 0xAB4
	volatile unsigned int MC_MLAHBENSETR; 	// 0xAB8
	volatile unsigned int MC_MLAHBENCLRR; 	// 0xABC
	volatile unsigned int res24[16];
	volatile unsigned int MP_APB1LPENSETR; 	// 0xB00
	volatile unsigned int MP_APB1LPENCLRR; 	// 0xB04
	volatile unsigned int MP_APB2LPENSETR;  // 0xB08
	volatile unsigned int MP_APB2LPENCLRR; 	// 0xB0C
	volatile unsigned int MP_APB3LPENSETR; 	// 0xB10
	volatile unsigned int MP_APB3LPENCLRR;  // 0xB14
	volatile unsigned int MP_AHB2LPENSETR;  // 0xB18
	volatile unsigned int MP_AHB2LPENCLRR;  // 0xB1C
	volatile unsigned int MP_AHB3LPENSETR;  // 0xB20
	volatile unsigned int MP_AHB3LPENCLRR;  // 0xB24
	volatile unsigned int MP_AHB4LPENSETR;  // 0xB28
	volatile unsigned int MP_AHB4LPENCLRR;  // 0xB2C
	volatile unsigned int MP_AXIMLPENSETR;  // 0xB30
	volatile unsigned int MP_AXIMLPENCLRR;  // 0xB34
	volatile unsigned int MP_MLAHBLPENSETR; // 0xB38
	volatile unsigned int MP_MLAHBLPENCLRR; // 0xB3C
	volatile unsigned int res25[16];
	volatile unsigned int MC_APB1LPENSETR;  // 0xB80
	volatile unsigned int MC_APB1LPENCLRR; 	// 0xB84
	volatile unsigned int MC_APB2LPENSETR;  // 0xB88
	volatile unsigned int MC_APB2LPENCLRR;  // 0xB8C
	volatile unsigned int MC_APB3LPENSETR;  // 0xB90 
	volatile unsigned int MC_APB3LPENCLRR;  // 0xB94
	volatile unsigned int MC_AHB2LPENSETR;  // 0xB98
	volatile unsigned int MC_AHB2LPENCLRR;  // 0xB9C
	volatile unsigned int MC_AHB3LPENSETR;  // 0xBA0 
	volatile unsigned int MC_AHB3LPENCLRR;  // 0xBA4
	volatile unsigned int MC_AHB4LPENSETR;  // 0xBA8
	volatile unsigned int MC_AHB4LPENCLRR;  // 0xBAC
	volatile unsigned int MC_AXIMLPENSETR;  // 0xBB0
	volatile unsigned int MC_AXIMLPENCLRR;  // 0xBB4
	volatile unsigned int MC_MLAHBLPENSETR; // 0xBB8
	volatile unsigned int MC_MLAHBLPENCLRR; // 0xBBC
	volatile unsigned int res26[16];
	volatile unsigned int MC_RSTSCLRR;  	// 0xC00
	volatile unsigned int res27[4];
	volatile unsigned int MC_CIER;  		// 0xC14
	volatile unsigned int MC_CIFR; 			// 0xC18
	volatile unsigned int res28[246];
	volatile unsigned int VERR; 			// 0xFF4
	volatile unsigned int IDR; 				// 0xFF8
	volatile unsigned int SIDR; 			// 0xFFC
}rcc_t;

#define RCC   ((rcc_t *)0x50000000)

typedef struct {
	volatile unsigned int MODER;   // 0x00
	volatile unsigned int OTYPER;  // 0x04
	volatile unsigned int OSPEEDR; // 0x08
	volatile unsigned int PUPDR;   // 0x0C
	volatile unsigned int IDR;     // 0x10
	volatile unsigned int ODR;     // 0x14
	volatile unsigned int BSRR;    // 0x18
	volatile unsigned int LCKR;    // 0x1C 
	volatile unsigned int AFRL;    // 0x20 
	volatile unsigned int AFRH;    // 0x24
	volatile unsigned int BRR;     // 0x28
	volatile unsigned int res;
	volatile unsigned int SECCFGR; // 0x30

}gpio_t;

#define  GPIOA   ((gpio_t *)0x50002000)
#define  GPIOB   ((gpio_t *)0x50003000)
#define  GPIOC   ((gpio_t *)0x50004000)
#define  GPIOD   ((gpio_t *)0x50005000)
#define  GPIOE   ((gpio_t *)0x50006000)
#define  GPIOF   ((gpio_t *)0x50007000)
#define  GPIOG   ((gpio_t *)0x50008000)
#define  GPIOH   ((gpio_t *)0x50009000)
#define  GPIOI   ((gpio_t *)0x5000A000)
#define  GPIOJ   ((gpio_t *)0x5000B000)
#define  GPIOK   ((gpio_t *)0x5000C000)
#define  GPIOZ   ((gpio_t *)0x54004000)

#endif

mychrdev.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "head.h"

unsigned int major; //定义一个变量保存主设备号
char kbuf[128] = {0};//定义一个内核中的buffer
unsigned int *vir_gpioe_moder = NULL;
unsigned int *vir_gpioe_odr = NULL;
unsigned int *vir_gpiof_moder = NULL;
unsigned int *vir_gpiof_odr = NULL;
unsigned int *vir_rcc = NULL;
//封装操作方法
int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
ssize_t mycdev_read(struct file *file, char __user *ubuf, size_t size, loff_t *lof)
{
    int res;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    res = copy_to_user(ubuf, kbuf, size);
    if(res != 0)
    {
        printk("copy_to_user failed\n");
        return -EIO;
    }
    
    return 0;
}

ssize_t mycdev_write(struct file *file, const char __user *ubuf, size_t size, loff_t *lof)
{
    int res;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    res = copy_from_user(kbuf, ubuf, size);
    if(res != 0)
    {
        printk("copy_from_user failed\n");
        return -EIO;
    }
    //LED1开灯
    if(kbuf[0] == '1' && kbuf[1] == '1')
    {
        *vir_gpioe_odr |= 0x1 << 10;
    }
    //LED1关灯
    if(kbuf[0] == '1' && kbuf[1] == '0')
    {
        *vir_gpioe_odr &= ~(0x1 << 10);
    }    
    //LED2开灯
    if(kbuf[0] == '2' && kbuf[1] == '1')
    {
        *vir_gpiof_odr |= 0x1 << 10;
    }
    //LED2关灯
    if(kbuf[0] == '2' && kbuf[1] == '0')
    {
        *vir_gpiof_odr &= ~(0x1 << 10);
    }    
    //LED3开灯
    if(kbuf[0] == '3' && kbuf[1] == '1')
    {
        *vir_gpioe_odr |= 0x1 << 8;
    }
    //LED3关灯
    if(kbuf[0] == '3' && kbuf[1] == '0')
    {
        *vir_gpioe_odr &= ~(0x1 << 8);
    }
    return 0;
}

int mycdev_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

struct file_operations fops={
    .open = mycdev_open,
    .read = mycdev_read,
    .write = mycdev_write,
    .release = mycdev_close,
};

static int __init mycdev_init(void)
{
    volatile int *tmp = NULL;
    major = register_chrdev(0,"mychrdev",&fops);
    if(major < 0)
    {
        printk("注册字符设备驱动失败\n");
        return major;
    }
    printk("注册字符设备驱动成功\n");
    //初始化几个寄存器,将物理地址映射到虚拟地址,以方便用户空间进行读写操作
    tmp = &GPIOE->MODER;
    vir_gpioe_moder = ioremap(*tmp,4);
    if(vir_gpioe_moder == NULL)
    {
        printk("映射物理内存失败");
        return -EFAULT;
    }
    vir_gpiof_moder = ioremap(GPIOF->MODER,4);
    if(vir_gpioe_moder == NULL)
    {
        printk("映射物理内存失败");
        return -EFAULT;
    }
    vir_gpioe_odr = ioremap(GPIOE->ODR,4);
    if(vir_gpioe_odr == NULL)
    {
        printk("映射物理内存失败");
        return -EFAULT;
    }
    vir_gpiof_odr = ioremap(GPIOF->ODR,4);
    if(vir_gpiof_odr == NULL)
    {
        printk("映射物理内存失败");
        return -EFAULT;
    }
    vir_rcc = ioremap(RCC->MP_AHB4ENSETR,4);
    if(vir_rcc == NULL)
    {
        printk("映射物理内存失败");
        return -EFAULT;
    }
    //初始化几个寄存器的值
    //设置RCC_MP_AHB4ENSETR寄存器第4第5两个引脚为1,使能GPIOE,GPIOF
    *vir_rcc |= (0b11 << 4);
    //设置GPIOE_MODER第20-21位为01
    *vir_gpioe_moder &= ~(0b11 << 20);
    *vir_gpioe_moder |= (0b01 << 20);
    //设置GPIOF_MODER第20-21位为01
    *vir_gpiof_moder &= ~(0b11 << 20);
    *vir_gpiof_moder |= (0b01 << 20);
    //设置GPIOE_MODER第16-17位为01
    *vir_gpioe_moder &= ~(0b11 << 16);
    *vir_gpioe_moder |= (0b01 << 16);
    //设置GPIOE_ODR第10位为0
    *vir_gpioe_odr &= ~(0b1 << 10);
    //设置GPIOF_ODR第10位为0
    *vir_gpiof_odr &= ~(0b1 << 10);
    //设置GPIOE_ODR第8位为0
    *vir_gpiof_odr &= ~(0b1 << 8);
    return 0;
}

static void __exit mycdev_exit(void)
{
    printk("设备卸载\n");
    unregister_chrdev(major,"mychrdev");
}

module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

led.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>

int main()
{
    char buf[128] = {0};
    fprintf(stdout,"调用open\n");
    int fd = open("/dev/mychrdev",O_RDWR);
    if( fd < 0)
    {
        perror("");
        exit(-1);
    }
    while(1)
    {
        fprintf(stdout,"请输入开关选项:\n");
        
        fgets(buf,sizeof(buf),stdin);
        buf[strlen(buf) - 1] = '\0';
        fprintf(stdout,"调用write\n");
        write(fd,buf,sizeof(buf));
    }
    close(fd);
    return 0;
}

————————————————————————————————————

后来发现追了一下ioremap函数的参数。第一个参数应该是一个long类型的变量,变量中保存的应该是寄存器的物理地址信息。

所以一开始传参传入的是寄存器的值是不对的。

但又因为如果直接传入取地址的寄存器会造成指针类型和long类型的隐性强转,编译器会报错。

所以得先定义一个long类型的tmp变量,用来保存每一个寄存器的物理地址信息。通过tmp中的值再去映射到虚拟地址。

以下是改版的mychrdev.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "head.h"

unsigned int major; //定义一个变量保存主设备号
char kbuf[128] = {0};//定义一个内核中的buffer
unsigned int *vir_gpioe_moder = NULL;
unsigned int *vir_gpioe_odr = NULL;
unsigned int *vir_gpiof_moder = NULL;
unsigned int *vir_gpiof_odr = NULL;
unsigned int *vir_rcc = NULL;
//封装操作方法
int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
ssize_t mycdev_read(struct file *file, char __user *ubuf, size_t size, loff_t *lof)
{
    int res;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    //如果用户请求的buffer不满足用户需求,最大限度的满足用户需求
    if(size > sizeof(kbuf))
    {
        size = sizeof(kbuf);
    }
    res = copy_to_user(ubuf, kbuf, size);
    if(res != 0)
    {
        printk("copy_to_user failed\n");
        return -EIO;
    }
    
    return 0;
}

ssize_t mycdev_write(struct file *file, const char __user *ubuf, size_t size, loff_t *lof)
{
    int res;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    //如果用户请求的buffer不满足用户需求,最大限度的满足用户需求
    if(size > sizeof(kbuf))
    {
        size = sizeof(kbuf);
    }
    res = copy_from_user(kbuf, ubuf, size);
    if(res != 0)
    {
        printk("copy_from_user failed\n");
        return -EIO;
    }
    //LED1开灯
    if(kbuf[0] == '1' && kbuf[1] == '1')
    {
        *vir_gpioe_odr |= 0x1 << 10;
    }
    //LED1关灯
    if(kbuf[0] == '1' && kbuf[1] == '0')
    {
        *vir_gpioe_odr &= ~(0x1 << 10);
    }    
    //LED2开灯
    if(kbuf[0] == '2' && kbuf[1] == '1')
    {
        *vir_gpiof_odr |= 0x1 << 10;
    }
    //LED2关灯
    if(kbuf[0] == '2' && kbuf[1] == '0')
    {
        *vir_gpiof_odr &= ~(0x1 << 10);
    }    
    //LED3开灯
    if(kbuf[0] == '3' && kbuf[1] == '1')
    {
        *vir_gpioe_odr |= 0x1 << 8;
    }
    //LED3关灯
    if(kbuf[0] == '3' && kbuf[1] == '0')
    {
        *vir_gpioe_odr &= ~(0x1 << 8);
    }
    return 0;
}

int mycdev_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

struct file_operations fops={
    .open = mycdev_open,
    .read = mycdev_read,
    .write = mycdev_write,
    .release = mycdev_close,
};

static int __init mycdev_init(void)
{
    //定义一个long类型(匹配ioremap函数第一个参数),用来保存每个寄存器的地址信息
    volatile unsigned long tmp = 0;
    major = register_chrdev(0,"mychrdev",&fops);
    if(major < 0)
    {
        printk("注册字符设备驱动失败\n");
        return major;
    }
    printk("注册字符设备驱动成功\n");
    //初始化几个寄存器,将物理地址映射到虚拟地址,以方便用户空间进行读写操作

    //将地址信息强转为long类型方便tmp保存
    tmp = (long)&GPIOE->MODER;
    //将寄存器的物理地址映射到虚拟地址并保存
    vir_gpioe_moder = ioremap(tmp,4);
    if(vir_gpioe_moder == NULL)
    {
        printk("映射物理内存失败");
        return -EFAULT;
    }
    //将地址信息强转为long类型方便tmp保存
    tmp = (long)&GPIOF->MODER;
    //将寄存器的物理地址映射到虚拟地址并保存
    vir_gpiof_moder = ioremap(tmp,4);
    if(vir_gpioe_moder == NULL)
    {
        printk("映射物理内存失败");
        return -EFAULT;
    }
    //将地址信息强转为long类型方便tmp保存
    tmp = (long)&GPIOE->ODR;
    //将寄存器的物理地址映射到虚拟地址并保存
    vir_gpioe_odr = ioremap(tmp,4);
    if(vir_gpioe_odr == NULL)
    {
        printk("映射物理内存失败");
        return -EFAULT;
    }
    //将地址信息强转为long类型方便tmp保存
    tmp = (long)&GPIOF->ODR;
    //将寄存器的物理地址映射到虚拟地址并保存
    vir_gpiof_odr = ioremap(tmp,4);
    if(vir_gpiof_odr == NULL)
    {
        printk("映射物理内存失败");
        return -EFAULT;
    }
    //将地址信息强转为long类型方便tmp保存
    tmp = (long)&RCC->MP_AHB4ENSETR;
    //将寄存器的物理地址映射到虚拟地址并保存
    vir_rcc = ioremap(tmp,4);
    if(vir_rcc == NULL)
    {
        printk("映射物理内存失败");
        return -EFAULT;
    }
    //初始化几个寄存器的值
    //设置RCC_MP_AHB4ENSETR寄存器第4第5两个引脚为1,使能GPIOE,GPIOF
    *vir_rcc |= (0b11 << 4);
    //设置GPIOE_MODER第20-21位为01
    *vir_gpioe_moder &= ~(0b11 << 20);
    *vir_gpioe_moder |= (0b01 << 20);
    //设置GPIOF_MODER第20-21位为01
    *vir_gpiof_moder &= ~(0b11 << 20);
    *vir_gpiof_moder |= (0b01 << 20);
    //设置GPIOE_MODER第16-17位为01
    *vir_gpioe_moder &= ~(0b11 << 16);
    *vir_gpioe_moder |= (0b01 << 16);
    //设置GPIOE_ODR第10位为0
    *vir_gpioe_odr &= ~(0b1 << 10);
    //设置GPIOF_ODR第10位为0
    *vir_gpiof_odr &= ~(0b1 << 10);
    //设置GPIOE_ODR第8位为0
    *vir_gpiof_odr &= ~(0b1 << 8);
    return 0;
}

static void __exit mycdev_exit(void)
{
    //取消物理内存映射
    iounmap(vir_gpioe_moder);
    iounmap(vir_gpiof_moder);
    iounmap(vir_gpioe_odr);
    iounmap(vir_gpiof_odr);
    iounmap(vir_rcc);
    printk("设备卸载\n");
    unregister_chrdev(major,"mychrdev");
}

module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

改进的led.c,增加了一点儿注释

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>

int main()
{
    char buf[128] = {0};
    fprintf(stdout,"调用open\n");
    int fd = open("/dev/mychrdev",O_RDWR);
    if( fd < 0)
    {
        perror("");
        exit(-1);
    }
    while(1)
    {
        fprintf(stdout,"请输入开关选项:\n");
        fprintf(stdout,"先输入123控制led1,led2,led3,再紧跟输入1开灯,0关灯\n");
        fprintf(stdout,"输入q来结束\n");
        fgets(buf,sizeof(buf),stdin);
        buf[strlen(buf) - 1] = '\0';
        //如果输入的是q或Q,结束循环
        if(buf[0] == 'q' || buf[0] == 'Q')
        {
            break;
        }
        fprintf(stdout,"调用write\n");
        write(fd,buf,sizeof(buf));
    }
    close(fd);
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/785097.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot中java操作excel【EasyExcel】

EasyExcel 处理Excel&#xff1b;简单记录&#xff0c;方便日后查询&#xff01; 官方文档&#xff1a; Easy Excel (alibaba.com) 一、EasyExcel概述 Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存&#xff0c;poi有一套…

前端食堂技术周刊第 91 期:2023 npm 状态、TC39 会议回顾、浏览器中的 Sass、React 18 如何提高应用程序性能

美味值&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f; 口味&#xff1a;茶椰生花 食堂技术周刊仓库地址&#xff1a;https://github.com/Geekhyt/weekly 大家好&#xff0c;我是童欧巴。欢迎来到前端食堂技术周刊&#xff0c;我们先来看下…

js基础-练习三

九九乘法表&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthsc, initial-scale1.0"><title>九九乘法表</title><style&g…

5.9 Bootstrap 警告框(Alert)插件

文章目录 Bootstrap 警告框&#xff08;Alert&#xff09;插件用法选项方法事件 Bootstrap 警告框&#xff08;Alert&#xff09;插件 警告框&#xff08;Alert&#xff09;消息大多是用来向终端用户显示诸如警告或确认消息的信息。使用警告框&#xff08;Alert&#xff09;插件…

基于 Flink SQL CDC 数据处理的终极武器

文章目录 一、传统的数据同步方案与 Flink SQL CDC 解决方案1.1 Flink SQL CDC 数据同步与原理解析1.2 基于日志的 CDC 方案介绍1.3 选择 Flink 作为 ETL 工具 二、 基于 Flink SQL CDC 的数据同步方案实践2.1 CDC Streaming ETL2.2 Flink-CDC实践之mysql案例 来源互联网多篇文…

Redis—分布式系统

Redis—分布式系统 &#x1f50e;理解分布式&#x1f50e;分布式—应用服务与数据库服务分离引入更多的应用服务节点理解负载均衡 引入更多的数据库服务节点缓存分库分表 微服务 &#x1f50e;常见概念应用(Application) / 系统(System)模块(Module) / 组件(Component)分布式(D…

nvm 安装 Node 报错:panic: runtime error: index out of range [3] with length 3

最近在搞 TypeScript&#xff0c;然后想着品尝一下 pnpm&#xff0c;但是 pnmp 8.x 最低需要 Node 16.x&#xff0c;但是电脑上暂时还没有该版本&#xff0c;通过 nvm list available 命令查看可用的 Node 版本&#xff1a; nvm list available# 显示如下 | CURRENT | …

【C++进阶】:继承

继承 一.继承的概念和定义1.概念2.定义 二.基类和派生类对象赋值转换三.继承中的作用域四.派生类的默认成员函数五.继承与友元六.继承与静态成员七.复杂的菱形继承及菱形虚拟继承1.二义性2.原理 八.总结 一.继承的概念和定义 1.概念 继承(inheritance)机制是面向对象程序设计使…

虚拟文件描述符VFD

瀚高数据库 目录 环境 文档用途 详细信息 环境 系统平台&#xff1a;Linux x86-64 Red Hat Enterprise Linux 7 版本&#xff1a;14 文档用途 了解VFD 详细信息 1.相关数据类型 typedef struct vfd{int fd; /* current FD, or VFD_CLOSED if non…

23 自定义控件

案例&#xff1a;组合Spin Box和Horizontal Slider实现联动 新建Qt设计师界面&#xff1a; 选择Widget&#xff1a; 选择类名&#xff08;生成.h、.cpp、.ui文件&#xff09; 在smallWidget.ui中使用Spin Box和Horizontal Slider控件 可以自定义数字区间&#xff1a; 在主窗口w…

第17章 常见函数

创建函数 第一种格式采用关键字function&#xff0c;后跟分配给该代码块的函数名。 function name {commands }第二种 name() { commands }你也必须注意函数名。记住&#xff0c;函数名必须是唯一的&#xff0c;否则也会有问题。如果你重定义了函数&#xff0c;新定义会覆…

【时间复杂度】

旋转数组 题目 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 /* 解题思路&#xff1a;使用三次逆转法&#xff0c;让数组旋转k次 1. 先整体逆转 // 1,2,3,4,5,6,7 // 7 6 5 4 3 2 1 2. 逆转子数组[0, k - 1] // 5 6 7 4 3…

C语言基本结构:顺序、选择和循环

文章目录 前言顺序结构代码讲解 选择结构代码讲解 循环结构总结 前言 在计算机编程中&#xff0c;掌握基本的编程结构是非常重要的。C语言作为一种广泛应用的编程语言&#xff0c;具有丰富的基本结构&#xff0c;包括顺序结构、选择结构和循环结构。这些基本结构为开发人员提供…

RocketMQ主从集群broker无法启动,日志报错

使用vmWare安装的centOS7.9虚拟机&#xff0c;RocketMQ5.1.3 在rocketMQ的bin目录里使用相对路径的方式启动broker&#xff0c;jps查询显示没有启动&#xff0c;日志报错如下 排查配置文件没有问题&#xff0c;nameServer也已经正常启动 更换绝对路径&#xff0c;启动broker&…

flutter:animate_do(flutter中的Animate.css)

简介 做过web开发的应该大部分人都知道Animate.css&#xff0c;它为开发者提供了一系列预定义的动画效果&#xff0c;可以通过简单的CSS类来实现各种动画效果。而animate_do 相当于flutter中的Animate.css,它提供了很多定义好的动画效果 基本使用 官方地址 https://pub-web.…

一文学会redis在springBoot中的使用

“收藏从未停止&#xff0c;练习从未开始”&#xff0c;或许有那么一些好题好方法&#xff0c;在被你选中收藏后却遗忘在收藏夹里积起了灰&#xff1f;今天请务必打开你沉甸甸的收藏重新回顾&#xff0c;分享一下那些曾让你拍案叫绝的好东西吧&#xff01; 一、什么是redis缓存…

【深度学习】【三维重建】windows10环境配置PyTorch3d详细教程

【深度学习】【三维重建】windows10环境配置PyTorch3d详细教程 文章目录 【深度学习】【三维重建】windows10环境配置PyTorch3d详细教程Anaconda31.安装Anaconda32.卸载Anaconda33.修改Anaconda3安装虚拟环境的默认位置 安装PyTorch3d确定版本对应关系源码编译安装Pytorch3d 总…

Day 65: 集成学习之 AdaBoosting (3. 集成器)

代码&#xff1a; package dl;import java.io.FileReader; import weka.core.Instance; import weka.core.Instances;/*** The booster which ensembles base classifiers.*/ public class Booster {/*** Classifiers.*/SimpleClassifier[] classifiers;/*** Number of classi…

解决报错:Can‘t connect to HTTPS URL because the SSL module is not available.

本人今天准备打开安装一个label-studio包&#xff0c;试了很多次&#xff0c;接连报如下错误&#xff0c;因此我就去找了一些解决方案&#xff0c;现在总结如下&#xff1a; 1、报错信息如下 2、解决方案如下&#xff1a; github上有对应的解决方案&#xff0c;链接&#xff…

教师ChatGPT的23种用法

火爆全网的ChatGPT&#xff0c;作为教师应该如何正确使用&#xff1f;本文梳理了教师ChatGPT的23种用法&#xff0c;一起来看看吧&#xff01; 1、回答问题 ChatGPT可用于实时回答问题&#xff0c;使其成为需要快速获取信息的学生的有用工具。 从这个意义上说&#xff0c;Cha…