驱动错误。。求解
第一次加载正常 卸载时提示如下
[root@FriendlyARM /first_drv]# rmmod first_drv
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = c3abc000
[00000000] *pgd=33a39031, *pte=00000000, *ppte=00000000
Internal error: Oops: 17 [#1]
last sysfs file: /sys/devices/virtual/firstdrv_leds/firstdrv_leds/dev
Modules linked in: [last unloaded: first_drv]
CPU: 0 Not tainted (2.6.32.2-FriendlyARM #1)
PC is at remove_vm_area+0x78/0xac
LR is at __vunmap+0x2c/0x10c
pc : [<c0091644>] lr : [<c0092a60>] psr: a0000013
sp : c3a89ed0 ip : c3a63f40 fp : c3a89ee4
r10: 00000000 r9 : c3a88000 r8 : beadff62
r7 : 00000001 r6 : bf000000 r5 : bf000894 r4 : c3948b20
r3 : 00000000 r2 : 00000000 r1 : bf000000 r0 : bf000000
Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: c000717f Table: 33abc000 DAC: 00000015
Process rmmod (pid: 719, stack limit = 0xc3a88270)
Stack: (0xc3a89ed0 to 0xc3a8a000)
9ec0: 00000000 bf000894 c3a89f04 c3a89ee8
9ee0: c0092a60 c00915dc bf00084c bf000894 c3a88000 c3a89f44 c3a89f14 c3a89f08
9f00: c0092bbc c0092a44 c3a89f24 c3a89f18 c0034ec4 c0092b98 c3a89f3c c3a89f28
9f20: c006e0a0 c0034ec0 00000000 bf00084c c3a89fa4 c3a89f40 c006e25c c006dfc0
9f40: c008d3e4 73726966 72645f74 c3a90076 00000000 00001000 4001f000 c0030088
9f60: c3a88000 00000000 c3a89f84 c3a89f78 c0060f28 c014a150 c3a89fa4 00a89f88
9f80: c008d484 beadff62 00000001 00000000 00000081 c0030088 00000000 c3a89fa8
9fa0: c002fee0 c006e0d0 beadff62 00000001 beadff62 00000880 4022a024 00000000
9fc0: beadff62 00000001 00000000 00000081 00000001 00000000 beadfe88 00000000
9fe0: 00000000 beadfb10 00018250 401c886c 60000010 beadff62 00000000 00000000
Backtrace:
[<c00915cc>] (remove_vm_area+0x0/0xac) from [<c0092a60>] (__vunmap+0x2c/0x10c)
r5:bf000894 r4:00000000
[<c0092a34>] (__vunmap+0x0/0x10c) from [<c0092bbc>] (vfree+0x34/0x4c)
r7:c3a89f44 r6:c3a88000 r5:bf000894 r4:bf00084c
[<c0092b88>] (vfree+0x0/0x4c) from [<c0034ec4>] (module_free+0x14/0x18)
[<c0034eb0>] (module_free+0x0/0x18) from [<c006e0a0>] (free_module+0xf0/0x110)
[<c006dfb0>] (free_module+0x0/0x110) from [<c006e25c>] (sys_delete_module+0x19c/0x208)
r5:bf00084c r4:00000000
[<c006e0c0>] (sys_delete_module+0x0/0x208) from [<c002fee0>] (ret_fast_syscall+0x0/0x28)
r8:c0030088 r7:00000081 r6:00000000 r5:00000001 r4:beadff62
Code: e1540002 059f3034 0a000003 e1a03002 (e5922000)
---[ end trace d708ca1bf775c8f6 ]---
Segmentation fault
再次加载时 linux就没反应了
驱动源代码:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include<asm/uaccess.h>
#include<asm/irq.h>
#include<asm/io.h>
#include<mach/regs-gpio.h>
#include<mach/hardware.h>
#include<linux/device.h>
#include<linux/gpio.h>
#define DEVICE_NAME "firstdrv_leds" /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */
#define LED_MAJOR 231 /* 主设备号 */
static struct class *firstdrv_class;
static struct device *firstdrv_class_devs[5];
/* bit0<=>D10, 0:亮, 1:灭
* bit1<=>D11, 0:亮, 1:灭
* bit2<=>D12, 0:亮, 1:灭
*/
static char leds_status = 0x0;
static DECLARE_MUTEX(leds_lock); // 定义赋值
//static int minor;
static unsigned long gpio_va;
#define GPIO_OFT(x) ((x) - 0x56000000)
#define GPBCON (*(volatile unsigned long *)(gpio_va + GPIO_OFT(0x56000010)))
#define GPBDAT (*(volatile unsigned long *)(gpio_va + GPIO_OFT(0x56000014)))
static int first_drv_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev);
switch(minor)
{
case 0: /* /dev/leds */
{
// 配置引脚为输出
//s3c2410_gpio_cfgpin(S3C2410_GPB(5), S3C2410_GPB(5)_OUTP);
//s3c2410_gpio_cfgpin(S3C2410_GPB(6), S3C2410_GPB(6)_OUTP);
//s3c2410_gpio_cfgpin(S3C2410_GPB(7), S3C2410_GPB(7)_OUTP);
//s3c2410_gpio_cfgpin(S3C2410_GPB(8), S3C2410_GPB(8)_OUTP);
GPBCON &= ~(0x3<<(5*2));
GPBCON |= (1<<(5*2));
GPBCON &= ~(0x3<<(6*2));
GPBCON |= (1<<(6*2));
GPBCON &= ~(0x3<<(7*2));
GPBCON |= (1<<(7*2));
GPBCON &= ~(0x3<<(8*2));
GPBCON |= (1<<(8*2));
// 都输出0
//s3c2410_gpio_setpin(S3C2410_GPB(5), 0);
//s3c2410_gpio_setpin(S3C2410_GPB(6), 0);
//s3c2410_gpio_setpin(S3C2410_GPB(7), 0);
//s3c2410_gpio_setpin(S3C2410_GPB(8), 0);
GPBDAT &= ~(1<<5);
GPBDAT &= ~(1<<6);
GPBDAT &= ~(1<<7);
GPBDAT &= ~(1<<8);
down(&leds_lock);
leds_status = 0x0;
up(&leds_lock);
break;
}
case 1: /* /dev/led1 */
{
s3c2410_gpio_cfgpin(S3C2410_GPB(5), S3C2410_GPIO_OUTPUT);
s3c2410_gpio_setpin(S3C2410_GPB(5), 0);
down(&leds_lock);
leds_status &= ~(1<<0);
up(&leds_lock);
break;
}
case 2: /* /dev/led2 */
{
s3c2410_gpio_cfgpin(S3C2410_GPB(6), S3C2410_GPIO_OUTPUT);
s3c2410_gpio_setpin(S3C2410_GPB(6), 0);
down(&leds_lock);
leds_status &= ~(1<<1);
up(&leds_lock);
break;
}
case 3: /* /dev/led3 */
{
s3c2410_gpio_cfgpin(S3C2410_GPB(7), S3C2410_GPIO_OUTPUT);
s3c2410_gpio_setpin(S3C2410_GPB(7), 0);
down(&leds_lock);
leds_status &= ~(1<<2);
up(&leds_lock);
break;
}
case 4: /* /dev/led4 */
{
s3c2410_gpio_cfgpin(S3C2410_GPB(8), S3C2410_GPIO_OUTPUT);
s3c2410_gpio_setpin(S3C2410_GPB(8), 0);
down(&leds_lock);
leds_status &= ~(1<<3);
up(&leds_lock);
break;
}
}
return 0;
}
static int first_drv_read(struct file *filp, char __user *buff,
size_t count, loff_t *offp)
{
int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
char val;
switch (minor)
{
case 0: /* /dev/leds */
{
copy_to_user(buff, (const void *)&leds_status, 1);
break;
}
case 1: /* /dev/led1 */
{
down(&leds_lock);
val = leds_status & 0x1;
up(&leds_lock);
copy_to_user(buff, (const void *)&val, 1);
break;
}
case 2: /* /dev/led2 */
{
down(&leds_lock);
val = (leds_status>>1) & 0x1;
up(&leds_lock);
copy_to_user(buff, (const void *)&val, 1);
break;
}
case 3: /* /dev/led3 */
{
down(&leds_lock);
val = (leds_status>>2) & 0x1;
up(&leds_lock);
copy_to_user(buff, (const void *)&val, 1);
break;
}
case 4: /* /dev/led4 */
{
down(&leds_lock);
val = (leds_status>>3) & 0x1;
up(&leds_lock);
copy_to_user(buff, (const void *)&val, 1);
break;
}
}
return 1;
}
static int first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
int minor = MINOR( file ->f_dentry->d_inode->i_rdev);
char val;
copy_from_user(&val, buf, 1);
switch (minor)
{
case 0: /* /dev/leds */
{
s3c2410_gpio_setpin(S3C2410_GPB(5), (val & 0x1));
s3c2410_gpio_setpin(S3C2410_GPB(6), (val & 0x1));
s3c2410_gpio_setpin(S3C2410_GPB(7), (val & 0x1));
s3c2410_gpio_setpin(S3C2410_GPB(8), (val & 0x1));
down(&leds_lock);
leds_status = val;
up(&leds_lock);
break;
}
case 1: /* /dev/led1 */
{
s3c2410_gpio_setpin(S3C2410_GPB(5), val);
if (val == 0)
{
down(&leds_lock);
leds_status &= ~(1<<0);
up(&leds_lock);
}
else
{
down(&leds_lock);
leds_status |= (1<<0);
up(&leds_lock);
}
break;
}
case 2: /* /dev/led2 */
{
s3c2410_gpio_setpin(S3C2410_GPB(6), val);
if (val == 0)
{
down(&leds_lock);
leds_status &= ~(1<<1);
up(&leds_lock);
}
else
{
down(&leds_lock);
leds_status |= (1<<1);
up(&leds_lock);
}
break;
}
case 3: /* /dev/led3 */
{
s3c2410_gpio_setpin(S3C2410_GPB(7), val);
if (val == 0)
{
down(&leds_lock);
leds_status &= ~(1<<2);
up(&leds_lock);
}
else
{
down(&leds_lock);
leds_status |= (1<<2);
up(&leds_lock);
}
break;
}
case 4: /* /dev/led4 */
{
s3c2410_gpio_setpin(S3C2410_GPB(8), val);
if (val == 0)
{
down(&leds_lock);
leds_status &= ~(1<<3);
up(&leds_lock);
}
else
{
down(&leds_lock);
leds_status |= (1<<3);
up(&leds_lock);
}
break;
}
}
return 1;
}
static struct file_operations first_drv_fops = {
.owner = THIS_MODULE,
.open = first_drv_open,
.read = first_drv_read,
.write = first_drv_write,
};
int first_drv_init(void)
{
int ret;
int minor = 0;
gpio_va = ioremap(0x56000000, 0x100000);
if (!gpio_va) {
return -EIO;
}
ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &first_drv_fops);
if (ret < 0) {
printk(DEVICE_NAME " can't register major number\n");
return ret;
}
firstdrv_class = class_create(THIS_MODULE, "firstdrv_leds");
if (IS_ERR(firstdrv_class))
return PTR_ERR(firstdrv_class);
firstdrv_class_devs[0] = device_create(firstdrv_class, NULL, MKDEV(LED_MAJOR, 0), NULL, "firstdrv_leds");
for (minor = 1; minor < 5; minor++)
{
firstdrv_class_devs[minor] = device_create(firstdrv_class, NULL, MKDEV(LED_MAJOR, minor), NULL, "firstdrv_led%d", minor);
if (unlikely(IS_ERR(firstdrv_class_devs[minor])))
return PTR_ERR(firstdrv_class_devs[minor]);
}
printk(DEVICE_NAME " initialized\n");
return 0;
}
void first_drv_exit(void)
{
int minor;
unregister_chrdev(LED_MAJOR, DEVICE_NAME);
for (minor = 0; minor < 5; minor++)
{
device_unregister(firstdrv_class_devs[minor]);
}
class_destroy(firstdrv_class);
iounmap(&gpio_va);
}
module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_LICENSE("GPL");