【驅動】第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部分有些問題。
/ # 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
<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
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是不合法的!
【驅動】第25.4課、畢業班第4課_移植2期驅動到 Linux3.4.2內核