platform:i386
OS; ubuntu 10.04(linux2.6.32-38)
tools:gcc
short的编译:
liqinghan@ubuntu:~/examples/short$ make
make -C /lib/modules/2.6.32-38-generic/build M=/home/liqinghan/examples/short modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.32-38-generic'
scripts/Makefile.build:49: *** CFLAGS was changed in "/home/liqinghan/examples/short/Makefile". Fix it to use EXTRA_CFLAGS. Stop.
make[1]: *** [_module_/home/liqinghan/examples/short] Error 2
make[1]: Leaving directory `/usr/src/linux-headers-2.6.32-38-generic'
make: *** [default] Error 2
修改makefile,把CFLAGS改为EXTRA_CFLAGS即可!
liqinghan@ubuntu:~/examples/short$ vi Makefile
:%s/CFLAGS/EXTRA_CFLAGS/g
:wq
liqinghan@ubuntu:~/examples/short$ make
make -C /lib/modules/2.6.32-38-generic/build M=/home/liqinghan/examples/short modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.32-38-generic'
CC [M] /home/liqinghan/examples/short/short.o
/home/liqinghan/examples/short/short.c:24:26: error: linux/config.h: No such file or directory
/home/liqinghan/examples/short/short.c: In function short_selfprobe?
/home/liqinghan/examples/short/short.c:514: error: SA_INTERRUPT?undeclared (first use in this function)
/home/liqinghan/examples/short/short.c:514: error: (Each undeclared identifier is reported only once
/home/liqinghan/examples/short/short.c:514: error: for each function it appears in.)
/home/liqinghan/examples/short/short.c:514: warning: passing argument 2 of request_irq?from incompatible pointer type
include/linux/interrupt.h:126: note: expected irq_handler_t?but argument is of type anum irqreturn_t (*)(int, void *, struct pt_regs *)?
/home/liqinghan/examples/short/short.c:597:64: error: macro "INIT_WORK" passed 3 arguments, but takes just 2
/home/liqinghan/examples/short/short.c: In function short_init?
/home/liqinghan/examples/short/short.c:597: error: INIT_WORK?undeclared (first use in this function)
/home/liqinghan/examples/short/short.c:624: error: SA_SHIRQ?undeclared (first use in this function)
/home/liqinghan/examples/short/short.c:624: error: SA_INTERRUPT?undeclared (first use in this function)
/home/liqinghan/examples/short/short.c:625: warning: passing argument 2 of request_irq?from incompatible pointer type
include/linux/interrupt.h:126: note: expected irq_handler_t?but argument is of type anum irqreturn_t (*)(int, void *, struct pt_regs *)?
/home/liqinghan/examples/short/short.c:638: warning: passing argument 2 of request_irq?from incompatible pointer type
include/linux/interrupt.h:126: note: expected irq_handler_t?but argument is of type anum irqreturn_t (*)(int, void *, struct pt_regs *)?
/home/liqinghan/examples/short/short.c:658: warning: passing argument 2 of request_irq?from incompatible pointer type
include/linux/interrupt.h:126: note: expected irq_handler_t?but argument is of type anum irqreturn_t (*)(int, void *, struct pt_regs *)?
make[2]: *** [/home/liqinghan/examples/short/short.o] Error 1
make[1]: *** [_module_/home/liqinghan/examples/short] Error 2
make[1]: Leaving directory `/usr/src/linux-headers-2.6.32-38-generic'
make: *** [default] Error 2
修改把#include <linux/config.h>改为#include <linux/autoconf.h>
liqinghan@ubuntu:~/examples/short$ make
make -C /lib/modules/2.6.32-38-generic/build M=/home/liqinghan/examples/short modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.32-38-generic'
CC [M] /home/liqinghan/examples/short/short.o
/home/liqinghan/examples/short/short.c: In function short_selfprobe?
/home/liqinghan/examples/short/short.c:514: error: SA_INTERRUPT?undeclared (first use in this function)
/home/liqinghan/examples/short/short.c:514: error: (Each undeclared identifier is reported only once
/home/liqinghan/examples/short/short.c:514: error: for each function it appears in.)
/home/liqinghan/examples/short/short.c:514: warning: passing argument 2 of request_irq?from incompatible pointer type
include/linux/interrupt.h:126: note: expected irq_handler_t?but argument is of type anum irqreturn_t (*)(int, void *, struct pt_regs *)?
/home/liqinghan/examples/short/short.c:597:64: error: macro "INIT_WORK" passed 3 arguments, but takes just 2
/home/liqinghan/examples/short/short.c: In function short_init?
/home/liqinghan/examples/short/short.c:597: error: INIT_WORK?undeclared (first use in this function)
/home/liqinghan/examples/short/short.c:624: error: SA_SHIRQ?undeclared (first use in this function)
/home/liqinghan/examples/short/short.c:624: error: SA_INTERRUPT?undeclared (first use in this function)
/home/liqinghan/examples/short/short.c:625: warning: passing argument 2 of request_irq?from incompatible pointer type
include/linux/interrupt.h:126: note: expected irq_handler_t?but argument is of type anum irqreturn_t (*)(int, void *, struct pt_regs *)?
/home/liqinghan/examples/short/short.c:638: warning: passing argument 2 of request_irq?from incompatible pointer type
include/linux/interrupt.h:126: note: expected irq_handler_t?but argument is of type anum irqreturn_t (*)(int, void *, struct pt_regs *)?
/home/liqinghan/examples/short/short.c:658: warning: passing argument 2 of request_irq?from incompatible pointer type
include/linux/interrupt.h:126: note: expected irq_handler_t?but argument is of type anum irqreturn_t (*)(int, void *, struct pt_regs *)?
make[2]: *** [/home/liqinghan/examples/short/short.o] Error 1
make[1]: *** [_module_/home/liqinghan/examples/short] Error 2
make[1]: Leaving directory `/usr/src/linux-headers-2.6.32-38-generic'
make: *** [default] Error 2
1、对于SA_XX编译不通过,解决方法如下:
查看内核代码 interrupt.h文件
在linux2.6.32内核中没有
SA_INTERRUPT
SA_SHIRQ
..
SA_XX
的定义而在linux2.6.22却存在,可以根据SA_XX的定义如下:
//这里linux2.6.22和2.6.32都存在
#define IRQF_DISABLED 0x00000020
#define IRQF_SAMPLE_RANDOM 0x00000040
#define IRQF_SHARED 0x00000080
#define IRQF_PROBE_SHARED 0x00000100
#define IRQF_TIMER 0x00000200
#define IRQF_PERCPU 0x00000400
#define IRQF_NOBALANCING 0x00000800
#define IRQF_IRQPOLL 0x00001000
//这里linux2.6.22存在和2.6.32不存在
/*
* Migration helpers. Scheduled for removal in 9/2007
* Do not use for new code !
*/
static inline
unsigned long __deprecated deprecated_irq_flag(unsigned long flag)
{
return flag;
}
#define SA_INTERRUPT deprecated_irq_flag(IRQF_DISABLED)
#define SA_SAMPLE_RANDOM deprecated_irq_flag(IRQF_SAMPLE_RANDOM)
#define SA_SHIRQ deprecated_irq_flag(IRQF_SHARED)
#define SA_PROBEIRQ deprecated_irq_flag(IRQF_PROBE_SHARED)
#define SA_PERCPU deprecated_irq_flag(IRQF_PERCPU)
#define SA_TRIGGER_LOW deprecated_irq_flag(IRQF_TRIGGER_LOW)
#define SA_TRIGGER_HIGH deprecated_irq_flag(IRQF_TRIGGER_HIGH)
#define SA_TRIGGER_FALLING deprecated_irq_flag(IRQF_TRIGGER_FALLING)
#define SA_TRIGGER_RISING deprecated_irq_flag(IRQF_TRIGGER_RISING)
#define SA_TRIGGER_MASK deprecated_irq_flag(IRQF_TRIGGER_MASK)
可以知道SA_XX和IRQF_YY本质是一样,只不过通过一个函数返回来了而已。
所以只需要把SA_XX没有编译通过的改为对应的IRQF_YY既可。
2.INIT_WORK编译不通过,如下修改:
下面是linux2.3.32的INIT_WORK函数的定义
#ifdef CONFIG_LOCKDEP
#define INIT_WORK(_work, _func) \
do { \
static struct lock_class_key __key;\
\
(_work)->data = (atomic_long_t) WORK_DATA_INIT();\
lockdep_init_map(&(_work)->lockdep_map, #_work, &__key, 0);\
INIT_LIST_HEAD(&(_work)->entry);\
PREPARE_WORK((_work), (_func));\
} while (0)
#else
#define INIT_WORK(_work, _func) \
do { \
(_work)->data = (atomic_long_t) WORK_DATA_INIT();\
INIT_LIST_HEAD(&(_work)->entry);\
PREPARE_WORK((_work), (_func));\
} while (0)
#endif
而本程序用的却是这样子的,INIT_WORK(&short_wq, (void (*)(void *)) short_do_tasklet, NULL);明显这个INIT_WORK用的是老版本的INIT_WORK具体变化的版本,暂时未查,但是可以知道是在linux2.6.22以前的,因为在2.6.22的INIT_WORK和2.6.32是一样的。
我们只需要把第三个参数NULL去掉即可。
3、/home/liqinghan/examples/short/short.c:625: warning: passing argument 2 of request_irq?from incompatible pointer type
include/linux/interrupt.h:126: note: expected irq_handler_t?but argument is of type anum irqreturn_t (*)(int, void *, struct pt_regs *)?
这种警告,解决方法如下:
short是这样子使用的
irqreturn_t short_interrupt(int irq, void *dev_id, struct pt_regs *regs)
而在函数中struct pt_regs *regs这个参数根本没有用到。
在2.6.22和2.6.32中发现irq_handler_t函数指针如下:
typedef irqreturn_t (*irq_handler_t)(int, void *);
可知道short用的也是老版本的函数指针,所以我们只需要在使用了irq_handler_t的函数改为两个参数即可,因为第三个参数struct pt_regs *regs根本没用,所以不需要这个参数!
比如
irqreturn_t short_interrupt(int irq, void *dev_id, struct pt_regs *regs)
改为
irqreturn_t short_interrupt(int irq, void *dev_id)
即可
经过修改可以完成编译,却运行不起来,IO已被其他占用。
总结:
使用diff把之前的修改好的,做个补丁吧
diff -Naur ./short.c ./../../workspace/examples/short/short.c > short.patch
cat short.patch 如下:
--- ./short.c 2014-11-03 01:51:54.385718982 -0800
+++ ./../../workspace/examples/short/short.c 2014-11-03 01:43:10.960921160 -0800
@@ -43,7 +43,7 @@
#include <asm/io.h>
#define SHORT_NR_PORTS 8/* use 8 ports by default */
-
+#define _KERNEL_2_6_32_ /* for linux kernel 2.6.32 */
/*
* all of the parameters have no "short_" prefix, to save typing when
* specifying them at load time
@@ -332,8 +332,12 @@
.open = short_open,
.release = short_release,
};
-
+#ifndef _KERNEL_2_6_32_
irqreturn_t short_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#else
+irqreturn_t short_interrupt(int irq, void *dev_id)
+#endif
+
{
struct timeval tv;
int written;
@@ -409,8 +413,12 @@
wake_up_interruptible(&short_queue); /* awake any reading process */
}
-
+#ifndef _KERNEL_2_6_32_
irqreturn_t short_wq_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#else
+irqreturn_t short_wq_interrupt(int irq, void *dev_id)
+#endif
+
{
/* Grab the current time information. */
do_gettimeofday((struct timeval *) tv_head);
@@ -427,8 +435,11 @@
/*
* Tasklet top half
*/
-
+#ifndef _KERNEL_2_6_32_
irqreturn_t short_tl_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#else
+irqreturn_t short_tl_interrupt(int irq, void *dev_id)
+#endif
{
do_gettimeofday((struct timeval *) tv_head); /* cast to stop 'volatile' warning */
short_incr_tv(&tv_head);
@@ -439,8 +450,11 @@
-
+#ifndef _KERNEL_2_6_32_
irqreturn_t short_sh_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#else
+irqreturn_t short_sh_interrupt(int irq, void *dev_id)
+#endif
{
int value, written;
struct timeval tv;
@@ -490,8 +504,11 @@
if (short_irq < 0)
printk("short: probe failed %i times, giving up\n", count);
}
-
+#ifndef _KERNEL_2_6_32_
irqreturn_t short_probing(int irq, void *dev_id, struct pt_regs *regs)
+#else
+irqreturn_t short_probing(int irq, void *dev_id)
+#endif
{
if (short_irq == 0) short_irq = irq;/* found */
if (short_irq != irq) short_irq = -irq; /* ambiguous */
@@ -510,9 +527,13 @@
* what has been acquired
*/
for (i = 0; trials[i]; i++)
+#ifndef _KERNEL_2_6_32_
tried[i] = request_irq(trials[i], short_probing,
SA_INTERRUPT, "short probe", NULL);
-
+#else
+ tried[i] = request_irq(trials[i], short_probing,
+ IRQF_DISABLED, "short probe", NULL);
+#endif
do {
short_irq = 0; /* none got, yet */
outb_p(0x10,short_base+2); /* enable */
@@ -594,8 +615,11 @@
* (unused) argument.
*/
/* this line is in short_init() */
+ #ifndef _KERNEL_2_6_32_
INIT_WORK(&short_wq, (void (*)(void *)) short_do_tasklet, NULL);
-
+ else
+ INIT_WORK(&short_wq,(void (*)(void *)) short_do_tasklet);
+ #endif
/*
* Now we deal with the interrupt: either kernel-based
* autodetection, DIY detection or default number
@@ -620,9 +644,15 @@
* force short_irq to -1.
*/
if (short_irq >= 0 && share > 0) {
+ #ifndef _KERNEL_2_6_32_
result = request_irq(short_irq, short_sh_interrupt,
SA_SHIRQ | SA_INTERRUPT,"short",
short_sh_interrupt);
+ #else
+ result = request_irq(short_irq, short_sh_interrupt,
+ IRQF_SHARED | IRQF_DISABLED,"short",
+ short_sh_interrupt);
+ #endif
if (result) {
printk(KERN_INFO "short: can't get assigned irq %i\n", short_irq);
short_irq = -1;
@@ -634,8 +664,13 @@
}
if (short_irq >= 0) {
+ #ifndef _KERNEL_2_6_32_
result = request_irq(short_irq, short_interrupt,
SA_INTERRUPT, "short", NULL);
+ #else
+ result = request_irq(short_irq, short_interrupt,
+ IRQF_DISABLED, "short", NULL);
+ #endif
if (result) {
printk(KERN_INFO "short: can't get assigned irq %i\n",
short_irq);
@@ -652,10 +687,17 @@
*/
if (short_irq >= 0 && (wq + tasklet) > 0) {
free_irq(short_irq,NULL);
+ #ifndef _KERNEL_2_6_32_
result = request_irq(short_irq,
tasklet ? short_tl_interrupt :
short_wq_interrupt,
SA_INTERRUPT,"short-bh", NULL);
+ #else
+ result = request_irq(short_irq,
+ tasklet ? short_tl_interrupt :
+ short_wq_interrupt,
+ IRQF_DISABLED,"short-bh", NULL);
+ #endif
if (result) {
printk(KERN_INFO "short-bh: can't get assigned irq %i\n",
short_irq);
//=======================================分割线==================================
liqinghan@ubuntu:~/workspace/examples/short$ sudo ./short_load
[sudo] password for liqinghan:
insmod: error inserting './short.ko': -1 No such device
liqinghan@ubuntu:~/workspace/examples/short$ tail /var/log/messages
Nov 3 17:38:35 ubuntu kernel: [ 2877.829664] short: can't get I/O port address 0x378
可以看出0x378已经被占用,
liqinghan@ubuntu:~/workspace/examples/short$ cat /proc/ioports
...
01f0-01f7 : 0000:00:07.1
01f0-01f7 : ata_piix
02f8-02ff : serial
0376-0376 : 0000:00:07.1
0376-0376 : ata_piix
0378-037a : parport0 //注:已被占用
03c0-03df : vga+
03f2-03f2 : floppy
03f4-03f5 : floppy
03f6-03f6 : 0000:00:07.1
03f6-03f6 : ata_piix
03f7-03f7 : floppy
03f8-03ff : serial
0cf0-0cf1 : pnp 00:01
0cf8-0cff : PCI conf1
1000-103f : 0000:00:07.3
...
查看没有使用的IO地址,
可以看出0x037B - 0x03C0这一段没有被占用,把 base改为 0x037B即可!
修改编译,加载模块!
liqinghan@ubuntu:~/workspace/examples/short$ cat /proc/ioports
...
01f0-01f7 : ata_piix
02f8-02ff : serial
0376-0376 : 0000:00:07.1
0376-0376 : ata_piix
0378-037a : parport0
037b-0382 : short //已经成功运行
03c0-03df : vga+
03f2-03f2 : floppy
03f4-03f5 : floppy
03f6-03f6 : 0000:00:07.1
03f6-03f6 : ata_piix
03f7-03f7 : floppy
03f8-03ff : serial
...