|
我的
驱动程序:
#include <linux/module.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/poll.h>
#if defined(CONFIG_MODVERSIONS) &&!defined(MODVERSIONS)
#include <linux/modversions.h>
#define MODVERSIONS
#endif
#define __NO_VERSION__
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#define GFN_MAJOR 254
#define BASE 0x26a
#define LDATAPORT (BASE)
#define MDATAPORT (BASE+1)
#define HDATAPORT (BASE+2)
#define MYIRQ 9
static DECLARE_WAIT_QUEUE_HEAD(my_wait_queue);
static volatile int waiting_for_irq;
static void isr(int irq, void *dev_id, struct pt_regs *regs)
{
if(irq != MYIRQ)
{
printk(KERN_INFO "Stray Interrupt from IRQ %d\n",irq);
return;
}
/*outb(0, CONPORT); // Disable further interrupts from Parallel port*/
disable_irq(MYIRQ);
if(!waiting_for_irq)
{
printk(KERN_INFO "unexpected Interrupt from %d\n",irq);
return;
}
waiting_for_irq = 0;
wake_up_interruptible(&my_wait_queue);
printk(KERN_INFO "ISR: Done Interrupt from IRQ %d\n",irq);
}
static ssize_t
gfn_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
printk(KERN_INFO "Sorry,this operation isn't supported.\n");
return -EINVAL;
}
static ssize_t gfn_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
u8 data;
unsigned long flags;
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
printk(KERN_INFO "READ: Process going to Sleep ...\n");
enable_irq(MYIRQ);
save_flags(flags);
cli();
waiting_for_irq = 1; /* atomic copy */
restore_flags(flags);
/*outb(IRQENBIT, CONPORT); // Enable Interrupt from port*/
interruptible_sleep_on(&my_wait_queue);
/*sleep_on(&my_wait_queue); */
data = inb(LDATAPORT);
/*data[1] = inb(MDATAPORT);
data[2] = inb(HDATAPORT); */ // read the printer status port
printk(KERN_INFO "Woken up. data = %x hex\n", data); // for debugging only
// transfer data from kernel address space to user address space
if(copy_to_user( buffer, &data, sizeof(u)) return -EFAULT;
return sizeof(u;
}
static int gfn_open(struct inode * inode, struct file * file)
{
printk(KERN_INFO "GFN open: Usage = %d\n", MOD_IN_USE);
MOD_INC_USE_COUNT;
return 0;
}
static int gfn_release(struct inode * inode, struct file * file)
{
MOD_DEC_USE_COUNT;
printk(KERN_INFO "GFN release: Usage = %d\n", MOD_IN_USE);
return 0;
}
struct file_operations gfn_fops = {
owner: THIS_MODULE,
open: gfn_open,
release: gfn_release,
write: gfn_write,
read: gfn_read
};
int init_module(void)
{
int result;
result=check_region(BASE,16);
if(result)
{
printk(KERN_INFO "short: can't get I/O port address 0x%1x\n",BASE);
return result;
}
if (register_chrdev(GFN_MAJOR,"gfn",&gfn_fops)) {
printk("gfn: Failed to get major %d\n", GFN_MAJOR);
return -EIO;
}
request_region(BASE, 16,"gfn");
if(request_irq(MYIRQ, isr, SA_INTERRUPT, "gfn", NULL) ) {
printk("mkscc: Failed to get IRQ %d\n",MYIRQ);
return -EIO;
}
disable_irq(MYIRQ);// disable Interrupt from port*/
printk(KERN_INFO "Registered device gfn: major %d\n",GFN_MAJOR);
return 0;
}
void cleanup_module(void)
{
free_irq(MYIRQ, NULL);
release_region(BASE,16);
printk(KERN_INFO "Freed resources: MOD_IN_USE = %d\n", MOD_IN_USE);
unregister_chrdev(GFN_MAJOR,"gfn");
printk(KERN_INFO "Unregistered device gfn: major %d\n",GFN_MAJOR);
}
MODULE_LICENSE("GPL");
/********testdrv.c 测试程序*/
#include <stdio.h>
//#include <sys/ioctl.h>
#include <fcntl.h>
int handle;
int main()
{
int data;
handle = open("/dev/testsleepdrv", O_RDWR);
if(handle > 0)
printf("GFN Driver opened %d\n", handle);
else
{
printf("Error opening GFN\n");
exit(1);
}
data=0;
printf("Going to call GFN read. Will sleep....");
if(read(handle, &data, 1, 0) < 0)
printf("Error reading GFN\n");
printf("Woken Up. Printer Status = %x hex\n",data&255);
return 0;
}
/*********************/
编译:gcc -O2 -D__KERNEL__ -DMODULE -I/usr/src/linux/include -c mydriver.c
gcc ./testdrv.c
mknod /dev/testsleepdrv c 254 0
insmod ./mydriver.o
./testdrv.o
提示
Process going to Sleep
Unable to handle kernel NULL pointer dereference at virtual address 00000
......
segment fault .....
interrupt
我的内核是2.4.30,该如何使用interruptible_sleep_on,wait_up_interruptible |
|