【驱动】第25.4课、毕业班第4课_移植2期驱动到 Linux3.4.2内核

主    机:VMWare--Ubuntu-16.04.2-x64-100ask

开发板:JZ2440--256M NandFlash,   2M NorFlash,   64M SDRAM,   LCD-4.3寸;
    bootlorder:  u-boot-2012.04.01,       Kernel:  Linux3.4.2;
编译器:arm-linux-gcc-4.3.2


节一、网卡驱动移植
1、网卡(包括ifconfig命令、ping命令的有效性)在当machid为mini2440的7cf时才可用,在machid是smdk2440的16a时是不可用的。
因此也证明了,之前修改的linux-3.4.2内核中网卡部分关于smdk2440.c部分有些问题。
<1>machid是smdk2440的16a时,实操如下:
/ # ifconfig eth0 192.168.1.11
dm9000 dm9000: eth0: link down
dm9000 dm9000: eth0: link up, 100Mbps, full-duplex, lpa 0xC1E1
/ # ping 192.168.1.105
PING 192.168.1.105 (192.168.1.105): 56 data bytes
64 bytes from 192.168.1.105: seq=0 ttl=64 time=13.754 ms
...
^C
--- 192.168.1.105 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 3.170/5.689/13.754 ms
<2>machid是smdk2440的16a时,实操如下:
/ # ifconfig
/ # ifconfig eth0 192.168.1.11
ifconfig: SIOCSIFADDR: No such device
/ # ping 192.168.1.105
PING 192.168.1.105 (192.168.1.105): 56 data bytes
ping: sendto: Network is unreachable

2、常用命令:
192.168.1.105
192.168.1.11
# ifconfig eth0 192.168.1.11
# ping 192.168.1.105
mount -t nfs -o nolock,vers=2 192.168.1.105:/work/nfs_root/fs_mini_mdev_new_digitpic /mnt
nfs 30000000 192.168.1.105:/work/nfs_root/uImage_net_new; bootm 30000000
set bootargs console=ttySAC0,115200 root=/dev/nfs nfsroot=192.168.1.105:/work/nfs_root/fs_mini_mdev_new_digitpic ip=192.168.1.11:192.168.1.105:192.168.1.1:255.255.255.0::eth0:off
nfs 32000000 192.168.1.105:/work/nfs_root/uImage_mini2440_new

---------------------------------------------
节二、LED和按键驱动移植
一、LED驱动移植
1.Makefile修改:
KERN_DIR ?= /home/book/workbook/mini2440/systems/linux-3.4.2

2、课堂问题
问题:1、test文件open()函数,如:fd = open("/dev/leds", O_RDWR)打开的是设备、文件还是什么?
答:open打开的是设备,是class_create函数创建的设备的类class下,用class_device_create函数创建的该类设备的某一个设备class_device,
也称为设备节点。

3、调试问题
3.1、led_2驱动加载出现错误(基本崩溃,但还可用),系统报错如下,原因是什么?
错误打印:
/driver_test/char/leds # insmod led_2.ko
------------[ cut here ]------------
WARNING: at fs/sysfs/dir.c:508 sysfs_add_one+0x8c/0xb0()
sysfs: cannot create duplicate filename '/class/leds'
Modules linked in: led_2(O+) [last unloaded: first_drv]
...
WARNING: at lib/kobject.c:198 kobject_add_internal+0x1c0/0x1f8()
kobject_add_internal failed for leds with -EEXIST, don't try to register things with the same name in the same directory.
Modules linked in: led_2(O+) [last unloaded: first_drv]
...
/driver_test/char/leds # rmmod led_2
Unable to handle kernel NULL pointer dereference at virtual address 0000002b
pgd = c3ad4000
...
原因1.查看一下驱动源码
原因2.根文件系统时么有mdev; 答:不是此原因,fs已经有了mdev;
答:查看已经在sys/系统下创建的设备类class:
# ls /sys/class/
... input leds mtd net sb_device...
如此可知,sys/文件系统中已经有了leds设备类,系统提示:对于具有-EEXIST的led, kobject_add_internal失败,请不要尝试在相同目录中注册
具有相同名称的内容。

3.2、问题:驱动keys_2_drv.c执行ctrl +c强制中断当前程序时当前程序崩溃:
# ./keys_2_drvtest
key_val = 0x1
key_val = 0x81
key_val = 0x4
key_val = 0x84
^C------------[ cut here ]------------
WARNING: at kernel/irq/manage.c:1193 __free_irq+0xa0/0x184()
Trying to free already-free IRQ 16
Modules linked in: keys_2_drv(O)
...
错误源码:
static int keys_drv_open(struct inode * inode, struct file *filp)
{
request_irq(IRQ_EINT0, keys_irq, (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING), "key_2", &pins_desc[0]);
...
}
static int keys_drv_close(struct inode * inode, struct file *file)
{
free_irq(IRQ_EINT0, NULL);
...
}
改为:
static int keys_drv_close(struct inode * inode, struct file *file)
{
free_irq(IRQ_EINT0, &pins_desc[0]);
...
}
则当执行ctrl +c强制中断当前程序时,不会再发生程序崩溃了。
其中的原因是什么?
两个函数原型:
static inline int __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)
{...}
void free_irq(unsigned int irq, void *dev_id)
{...}


---------------------------------------------
节三、LCD及输入系统
1.Makefile修改:
KERN_DIR ?= /home/book/workbook/mini2440/systems/linux-3.4.2


---------------------------------------------
节四、块设备和虚拟网卡

1、调试错误及解决
1.1关于释放空指针造成系统崩溃的解决
/driver_test # insmod s3c_nor3.ko
use cfi_probe
use jedec_probe
map_probe failed!
Unable to handle kernel NULL pointer dereference at virtual address 000000d8
...
Backtrace:
[<c01c31d4>] (map_destroy+0x0/0x44) from [<bf004158>] (s3c_nor_init+0x11c/0x19c [s3c_nor3])
r5:bf0044d4 r4:c39e8b20
[<bf00403c>] (s3c_nor_init+0x0/0x19c [s3c_nor3]) from [<c0008580>] (do_one_initcall+0x3c/0x194)
r5:000e2e38 r4:0000a6a3
[<c0008544>] (do_one_initcall+0x0/0x194) from [<c004d324>] (sys_init_module+0x8c/0x1a4)
[<c004d298>] (sys_init_module+0x0/0x1a4) from [<c0009280>] (ret_fast_syscall+0x0/0x2c)
r7:00000080 r6:bea93ea8 r5:00000000 r4:00000001
Code: 00200200 e1a0c00d e92dd830 e24cb004 (e59040d8)
---[ end trace 2caaa0976448c7ae ]---
Segmentation fault


造成崩溃的原代码:
static int s3c_nor_init(void)
{
int err, ret;
/* 1.分配一个map_info结构体 */
s3c_nor_map = kzalloc(sizeof(struct map_info ), GFP_KERNEL);
if(!s3c_nor_map)
{
printk(KERN_ERR "Failed to allocate s3c_nor_map map_info structure!\n");
err = -ENOMEM;
goto err_fail1;
}
/* 2.设置该结构体 */
s3c_nor_map->name = "s3c_nor"; /* 名字 */
s3c_nor_map->phys = 0; /* 物理基地址 */
s3c_nor_map->size = 0x1000000; /* 16M大小 */
s3c_nor_map->bankwidth = 2; /* 位宽: 2x8位 */
s3c_nor_map->virt = ioremap(s3c_nor_map->phys, s3c_nor_map->size); /* 虚拟基地址 */
if(!s3c_nor_map->virt)
{
printk(KERN_ERR "Failed to ioremap s3c_nor_map->virt regions!\n");
err = -ENOMEM;
goto err_fail2;
}
simple_map_init(s3c_nor_map);
/* 3.使用: 调用Norflash协议层提供的函数来识别 */
printk("use cfi_probe\n");
s3c_nor_mtd = do_map_probe("cfi_probe", s3c_nor_map);
if(!s3c_nor_mtd)
{
printk("use jedec_probe\n");
s3c_nor_mtd = do_map_probe("jedec_probe", s3c_nor_map);
}
if(!s3c_nor_mtd)
{
printk("map_probe failed!\n");
err = -ENXIO;
goto err_fail3;
}
s3c_nor_mtd->owner = THIS_MODULE;
/* 4.注册mtd分区表 */
//add_mtd_partitions(s3c_nor_mtd, s3c_nor_parts, 2);
ret = mtd_device_register(s3c_nor_mtd, s3c_nor_parts, 2);
if(ret < 0)
{
printk("Failed to register s3c_nor_mtd mtd device!\n");
goto err_fail3;
}

return 0;
err_fail3:
map_destroy(s3c_nor_mtd); //在这里!!!
err_fail2:
iounmap(s3c_nor_map->virt); //在这里!!!
err_fail1:
kfree(s3c_nor_map);
return err;
}
static void s3c_nor_exit(void)
{
//del_mtd_device(s3c_nor_mtd);
//del_mtd_partitions(s3c_nor_mtd);
mtd_device_unregister(s3c_nor_mtd); //在这里!!!
map_destroy(s3c_nor_mtd); //在这里!!!
iounmap(s3c_nor_map->virt);
kfree(s3c_nor_map);
}


修改之后的代码:
static int s3c_nor_init(void)
{
int err, ret;
/* 1.分配一个map_info结构体 */
s3c_nor_map = kzalloc(sizeof(struct map_info ), GFP_KERNEL);
if(!s3c_nor_map)
{
printk(KERN_ERR "Failed to allocate s3c_nor_map map_info structure!\n");
err = -ENOMEM;
goto err_fail1;
}
/* 2.设置该结构体 */
s3c_nor_map->name = "s3c_nor"; /* 名字 */
s3c_nor_map->phys = 0; /* 物理基地址 */
s3c_nor_map->size = 0x1000000; /* 16M大小 */
s3c_nor_map->bankwidth = 2; /* 位宽: 2x8位 */
s3c_nor_map->virt = ioremap(s3c_nor_map->phys, s3c_nor_map->size); /* 虚拟基地址 */
if(!s3c_nor_map->virt)
{
printk(KERN_ERR "Failed to ioremap s3c_nor_map->virt regions!\n");
err = -ENOMEM;
goto err_fail2;
}
simple_map_init(s3c_nor_map);
/* 3.使用: 调用Norflash协议层提供的函数来识别 */
printk("use cfi_probe\n");
s3c_nor_mtd = do_map_probe("cfi_probe", s3c_nor_map);
if(!s3c_nor_mtd)
{
printk("use jedec_probe\n");
s3c_nor_mtd = do_map_probe("jedec_probe", s3c_nor_map);
}
if(!s3c_nor_mtd)
{
printk("map_probe failed!\n");
err = -ENXIO;
goto err_fail3;
}
s3c_nor_mtd->owner = THIS_MODULE;
/* 4.注册mtd分区表 */
//add_mtd_partitions(s3c_nor_mtd, s3c_nor_parts, 2);
ret = mtd_device_register(s3c_nor_mtd, s3c_nor_parts, 2);
if(ret < 0)
{
printk("Failed to register s3c_nor_mtd mtd device!\n");
goto err_fail3;
}

return 0;
err_fail3:
if(s3c_nor_mtd) //在这里!!!
{
map_destroy(s3c_nor_mtd); //在这里!!!
}
err_fail2:
iounmap(s3c_nor_map->virt);
err_fail1:
kfree(s3c_nor_map);
return err;
}
static void s3c_nor_exit(void)
{
//del_mtd_device(s3c_nor_mtd);
//del_mtd_partitions(s3c_nor_mtd);
if(s3c_nor_mtd) //在这里!!!
{
mtd_device_unregister(s3c_nor_mtd); //在这里!!!
//map_destroy(s3c_nor_mtd); //在这里!!!
}

iounmap(s3c_nor_map->virt);
kfree(s3c_nor_map);
}
举例:
s3c_nor_mtd = do_map_probe("cfi_probe", s3c_nor_map);
与: map_destroy(s3c_nor_mtd); //在这里!!!
当map不成功时,map_destroy是不合法的!


猜你喜欢

转载自www.cnblogs.com/xiaohujian/p/10604880.html