模块加载段错误,但是加载上了,卸载出现该模块正在使用。

加载出现段错误,卸载出现正在使用


我自己试出来的解决方法:修改设备树和驱动里的compatible属性(和上一次的不一样),重试加载和卸载正常,但是我加载模块,然后重启开发板,第二次加载模块,问题就又重现了。

我使用韦老师的oled模块一切正常,我是使用ili9341的lcd屏幕,参照改的驱动程序。

请老师帮我看下为啥出现这种问题。谢谢了。

下面是我的 驱动代码和设备树信息。(参考的老师代码是70天驱动直播课中spi驱动oled,使用freambuffer框架)。

#include “linux/delay.h”

#include “linux/kthread.h”

#include <linux/interrupt.h>

#include <linux/workqueue.h>

#include <linux/device.h>

#include <linux/kernel.h>

#include <linux/slab.h>

#include <linux/sysfs.h>

#include <linux/list.h>

#include <linux/spi/spi.h>

#include <linux/err.h>

#include <linux/module.h>

#include <linux/gpio.h>

#include <linux/gpio/consumer.h>

#include <linux/uaccess.h>

#include <linux/fb.h>

#include <linux/dma-mapping.h>

#define myoled3_SET_XY 99

#define myoled3_SET_XY_WRITE_DATA 100

#define myoled3_SET_XY_WRITE_DATAS 101

#define myoled3_SET_DATAS 102 /* 102为低8位, 高16位用来表示长度 */

#define DARKBLUE 0X01CF //ÉîÀ¶É«

//为0 表示命令,为1表示数据

#define myoled3_CMD 0

#define myoled3_DATA 1

#define myoled3_W 240

#define myoled3_H 320

#define USE_HORIZONTAL 0

typedef struct

{

u16 width;          

u16 height;        

u16 id;              

u8  dir;                

u16  wramcmd;      

u16  setxcmd;      

u16  setycmd;            

}_myoled3_dev;

struct fb_info *oled3_fb_info;

struct spi_device *ili9431_oled3_device;

static unsigned int pseudo_palette[16];

static struct gpio_desc *myoled3_dc;

static struct gpio_desc *myoled3_reset;

static struct gpio_desc *myoled3_led;

static struct gpio_desc *myoled3_cs;

static _myoled3_dev myoled3dev;

static struct task_struct *oled3_kthread;

static int myoled3_setcolreg(unsigned regno,

               unsigned red, unsigned green, unsigned blue,

               unsigned transp, struct fb_info *info)

{

return 1; /* unkown type */

}

static struct fb_ops myfb_ops = {

.owner      = THIS_MODULE,

.fb_setcolreg   = myoled3_setcolreg,

.fb_fillrect    = cfb_fillrect,

.fb_copyarea    = cfb_copyarea,

.fb_imageblit   = cfb_imageblit,

};

/**********************************************************************

 * 函数名称: myoled3_write_cmd

 * 功能描述: myoled3向特定地址写入数据或者命令

 * 输入参数:@uc_data :要写入的数据

            @uc_cmd:为1则表示写入数据,为0表示写入命令

 * 输出参数:无

 * 返 回 值: 无

 * 修改日期        版本号   修改人          修改内容

 * -----------------------------------------------

 * 2020/03/04        V1.0     芯晓          创建

***********************************************************************/

static void myoled3_write_cmd_data(unsigned char uc_data,unsigned char uc_cmd)

{

//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

if(uc_cmd==0)

{

    //*GPIO4_DR_s &= ~(1<<20);//拉低,表示写入指令

    ////gpiod_set_value(myoled3_cs,1);

    gpiod_set_value(myoled3_dc, 0);

}

else

{

    //*GPIO4_DR_s |= (1<<20);//拉高,表示写入数据

    ////gpiod_set_value(myoled3_cs,1);

    gpiod_set_value(myoled3_dc, 1);

}

// spi_writeread(ESCPI1_BASE,uc_data);//写入

spi_write(ili9431_oled3_device, &uc_data, 1);

////gpiod_set_value(myoled3_cs,0);

//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

}

static void myoled3_write_datas(unsigned char *buf, int len)

{

//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

////gpiod_set_value(myoled3_cs,1);

//*GPIO4_DR_s |= (1<<20);//拉高,表示写入数据

gpiod_set_value(myoled3_dc, 1);

// spi_writeread(ESCPI1_BASE,uc_data);//写入

spi_write(ili9431_oled3_device, buf, len);

////gpiod_set_value(myoled3_cs,0);

//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

}

static void myoled3_RESET(void)

{

//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

gpiod_set_value(myoled3_reset,0);

msleep(100);

gpiod_set_value(myoled3_reset,1);

msleep(50);

//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

}

void myoled3_WriteReg(u8 myoled3_Reg, u16 myoled3_RegValue)

{

//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

myoled3_write_cmd_data(myoled3_Reg,myoled3_CMD);  

myoled3_write_cmd_data(myoled3_RegValue,myoled3_DATA);

//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);                

}

void myoled3_direction(u8 direction)

{

//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

myoled3dev.setxcmd=0x2A;

myoled3dev.setycmd=0x2B;

myoled3dev.wramcmd=0x2C;

switch(direction){        

    case 0:                                

        myoled3dev.width=myoled3_W;

        myoled3dev.height=myoled3_H;        

        myoled3_WriteReg(0x36,(1<<3)|(0<<6)|(0<<7));//BGR==1,MY==0,MX==0,MV==0

    break;

    case 1:

        myoled3dev.width=myoled3_H;

        myoled3dev.height=myoled3_W;

        myoled3_WriteReg(0x36,(1<<3)|(0<<7)|(1<<6)|(1<<5));//BGR==1,MY==1,MX==0,MV==1

    break;

    case 2:                                

        myoled3dev.width=myoled3_W;

        myoled3dev.height=myoled3_H;    

        myoled3_WriteReg(0x36,(1<<3)|(1<<6)|(1<<7));//BGR==1,MY==0,MX==0,MV==0

    break;

    case 3:

        myoled3dev.width=myoled3_H;

        myoled3dev.height=myoled3_W;

        myoled3_WriteReg(0x36,(1<<3)|(1<<7)|(1<<5));//BGR==1,MY==1,MX==0,MV==1

    break;  

    default:break;

}  

printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

}

void myoled3_WriteRAM_Prepare(void)

{

//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

myoled3_write_cmd_data(myoled3dev.wramcmd,myoled3_CMD);

//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

}

void myoled3_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd)

{

//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

myoled3_write_cmd_data(myoled3dev.setxcmd,myoled3_CMD);

myoled3_write_cmd_data(xStar>>8,myoled3_DATA);

myoled3_write_cmd_data(0x00FF&xStar,myoled3_DATA);      

myoled3_write_cmd_data(xEnd>>8,myoled3_DATA);

myoled3_write_cmd_data(0x00FF&xEnd,myoled3_DATA);

myoled3_write_cmd_data(myoled3dev.setycmd,myoled3_CMD);

myoled3_write_cmd_data(yStar>>8,myoled3_DATA);

myoled3_write_cmd_data(0x00FF&yStar,myoled3_DATA);      

myoled3_write_cmd_data(yEnd>>8,myoled3_DATA);

myoled3_write_cmd_data(0x00FF&yEnd,myoled3_DATA);

myoled3_WriteRAM_Prepare(); //  

//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);  

}

void myoled3_WriteData_16Bit(u16 Data)

{

//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

//gpiod_set_value(myoled3_cs,1);

gpiod_set_value(myoled3_dc,1);

spi_write(ili9431_oled3_device,&Data,2);

//gpiod_set_value(myoled3_cs,0);

//printk("%s %s %d\n", FILE, FUNCTION, LINE);

}

void myoled3_Clear(u16 Color)

{

int i=0,m=0;



//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

myoled3_SetWindows(0,0,myoled3dev.width-1,myoled3dev.height-1);  

//gpiod_set_value(myoled3_cs,1);

gpiod_set_value(myoled3_dc,1);

for(i=0;i<myoled3dev.height;i++)

{

for(m=0;m<myoled3dev.width;m++)

{  

    myoled3_WriteData_16Bit(Color);

}

printk("%s %s %d\n", __FILE__, __FUNCTION__, i);

}

//gpiod_set_value(myoled3_cs,0);

//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

}

/**********************************************************************

 * 函数名称: myoled3_init

 * 功能描述: myoled3_init的初始化,包括SPI控制器得初始化

 * 输入参数:无

 * 输出参数: 初始化的结果

 * 返 回 值: 成功则返回0,否则返回-1

 * 修改日期        版本号   修改人          修改内容

 * -----------------------------------------------

 * 2020/03/15        V1.0     芯晓          创建

***********************************************************************/

static int myoled3_hardware_init(void)

{

printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

myoled3_RESET();                                                                                                                  

myoled3_write_cmd_data(0xCF,myoled3_CMD);//关闭显示

myoled3_write_cmd_data(0x00,myoled3_DATA);//设置 lower column address

myoled3_write_cmd_data(0xC9,myoled3_DATA);//设置 higher column address

myoled3_write_cmd_data(0X30,myoled3_DATA);//设置 display start line

myoled3_write_cmd_data(0xED,myoled3_CMD);//设置page address

myoled3_write_cmd_data(0x64,myoled3_DATA);// contract control

myoled3_write_cmd_data(0x03,myoled3_DATA);//128

myoled3_write_cmd_data(0X12,myoled3_DATA);//设置 segment remap

myoled3_write_cmd_data(0X81,myoled3_DATA);//normal /reverse

myoled3_write_cmd_data(0xE8,myoled3_CMD);//multiple ratio

myoled3_write_cmd_data(0x85,myoled3_DATA);//duty = 1/64

myoled3_write_cmd_data(0x10,myoled3_DATA);//com scan direction

myoled3_write_cmd_data(0x7A,myoled3_DATA);//set displat offset

myoled3_write_cmd_data(0xCB,myoled3_CMD);//

myoled3_write_cmd_data(0x39,myoled3_DATA);//set osc division

myoled3_write_cmd_data(0x2C,myoled3_DATA);//

myoled3_write_cmd_data(0x00,myoled3_DATA);//ser pre-charge period

myoled3_write_cmd_data(0x34,myoled3_DATA);//

myoled3_write_cmd_data(0x02,myoled3_DATA);//set com pins

myoled3_write_cmd_data(0xF7,myoled3_CMD);//

myoled3_write_cmd_data(0x20,myoled3_DATA);//set vcomh

myoled3_write_cmd_data(0xEA,myoled3_CMD);//

myoled3_write_cmd_data(0x00,myoled3_DATA);//set charge pump disable

myoled3_write_cmd_data(0x00,myoled3_DATA);//

myoled3_write_cmd_data(0xC0,myoled3_CMD);//set dispkay on

myoled3_write_cmd_data(0x1B,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0xC1,myoled3_CMD);//set dispkay on

myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0xC5,myoled3_CMD);//set dispkay on

myoled3_write_cmd_data(0x30,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x30,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0xC7,myoled3_CMD);//set dispkay on

myoled3_write_cmd_data(0XB7,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x36,myoled3_CMD);//set dispkay on

myoled3_write_cmd_data(0x08,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x3A,myoled3_CMD);//set dispkay on

myoled3_write_cmd_data(0x55,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0xB1,myoled3_CMD);//set dispkay on

myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x1A,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0xB6,myoled3_CMD);//set dispkay on

myoled3_write_cmd_data(0x0A,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0xA2,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0xF2,myoled3_CMD);//set dispkay on

myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x26,myoled3_CMD);//set dispkay on

myoled3_write_cmd_data(0x01,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0xE0,myoled3_CMD);//set dispkay on

myoled3_write_cmd_data(0x0F,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x2A,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x28,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x08,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x0E,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x08,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x54,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0XA9,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x43,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x0A,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x0F,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0XE1,myoled3_CMD);//set dispkay on

myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x15,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x17,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x07,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x11,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x06,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x2B,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x56,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x3C,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x05,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x10,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x0F,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x3F,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x3F,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x0F,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x2B,myoled3_CMD);//set dispkay on

myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x01,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x3f,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x2A,myoled3_CMD);//set dispkay on

myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0xef,myoled3_DATA);//set dispkay on

myoled3_write_cmd_data(0x11,myoled3_CMD);//set dispkay on

msleep(120);

myoled3_write_cmd_data(0x29,myoled3_CMD);//set dispkay on

myoled3dev.setxcmd=0x2A;

myoled3dev.setycmd=0x2B;

myoled3dev.wramcmd=0x2C;                                

myoled3dev.width=myoled3_W;

myoled3dev.height=myoled3_H;        

myoled3_WriteReg(0x36,(1<<3)|(0<<6)|(0<<7));//BGR==1,MY==0,MX==0,MV==0

myoled3_direction(USE_HORIZONTAL);

gpiod_set_value(myoled3_led,1);

myoled3_Clear(DARKBLUE);

printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

return 0;

}

static int oled3_thread(void *data)

{

while (1)

{

    /* 把Framebuffer的数据刷到oled3上去 */

    myoled3_write_datas(oled3_fb_info->screen_base, oled3_fb_info->fix.smem_len);

   

    set_current_state(TASK_INTERRUPTIBLE);

    schedule_timeout(HZ);

    if (kthread_should_stop()) {

        set_current_state(TASK_RUNNING);

        break;

    }

   

}

return 0;

}

static int oled3_probe(struct spi_device *spi)

{

dma_addr_t phy_addr;

ili9431_oled3_device = spi;

oled3_fb_info = framebuffer_alloc(0, &spi->dev);

/* 1.2 设置fb_info */

/* a. var : oled3分辨率、颜色格式 */

oled3_fb_info->var.xres_virtual = oled3_fb_info->var.xres = 280;

oled3_fb_info->var.yres_virtual = oled3_fb_info->var.yres = 320;



oled3_fb_info->var.bits_per_pixel = 1;  /* rgb565 */

/* b. fix */

strcpy(oled3_fb_info->fix.id, "100ask_myoled3");

oled3_fb_info->fix.smem_len = oled3_fb_info->var.xres * oled3_fb_info->var.yres * oled3_fb_info->var.bits_per_pixel / 8;

/* c. 分配显存 */

oled3_fb_info->screen_base = dma_alloc_wc(NULL, oled3_fb_info->fix.smem_len, &phy_addr,

                 GFP_KERNEL);

oled3_fb_info->fix.smem_start = phy_addr;  /* fb的物理地址 */

printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

oled3_fb_info->fix.type = FB_TYPE_PACKED_PIXELS;

oled3_fb_info->fix.visual = FB_VISUAL_MONO10;

oled3_fb_info->fix.line_length = oled3_fb_info->var.xres * oled3_fb_info->var.bits_per_pixel / 8;

/* d. fbops */

oled3_fb_info->fbops = &myfb_ops;

oled3_fb_info->pseudo_palette = pseudo_palette;

register_framebuffer(oled3_fb_info);

printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

myoled3_dc = gpiod_get(&spi->dev, "dc", GPIOD_OUT_HIGH);

//myoled3_cs = gpiod_get(&spi->dev, "cs", GPIOD_OUT_LOW);

myoled3_reset = gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH);

myoled3_led = gpiod_get(&spi->dev, "led", GPIOD_OUT_HIGH);

myoled3_hardware_init();



/* 创建1个内核线程,用来把Framebuffer的数据通过SPI控制器发送给oled3 */

oled3_kthread = kthread_create(oled3_thread, NULL, "100ask_oled3");

wake_up_process(oled3_kthread);

return 0;

}

static int oled3_remove(struct spi_device *spi)

{

printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

kthread_stop(oled3_kthread);

/* 反注册 fb_info */

unregister_framebuffer(oled3_fb_info);

//gpiod_put(oled3_dc);

return 0;

}

static const struct of_device_id oled3_of_match[] = {

{.compatible = "100ask,myoled4"},

{}

};

struct spi_driver ili9341_oled3_driver = {

.driver ={

    .name = "ili9341_oled3",

    .of_match_table = oled3_of_match,

},

.probe      = oled3_probe,

.remove     = oled3_remove,

};

int ili9341_oled3_init (void)

{

return spi_register_driver(&ili9341_oled3_driver);

}

static void ili9341_oled3_exit(void)

{

spi_unregister_driver(&ili9341_oled3_driver);

}

module_init(ili9341_oled3_init);

module_exit(ili9341_oled3_exit);

MODULE_LICENSE(“GPL v2”);

myoled:myoled {

compatible = "100ask,myoled4";

reg = <0>;

spi-max-frequency = <32000000>;

dc-gpios = <&gpio4 20 GPIO_ACTIVE_HIGH>;

reset-gpios = <&gpio4 21 GPIO_ACTIVE_HIGH>;

led-gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>;

status = "okay";

};

oled: oled {

compatible = "100ask,oled";

reg = <0>;

spi-max-frequency = <1000000>;

dc-gpios = <&gpio4 20 GPIO_ACTIVE_HIGH>;

};