📄 shortbak.c
字号:
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h> /* printk() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/delay.h> /* udelay */
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/tqueue.h>
#include <asm/io.h>
#include "sysdep.h"
#define SHORT_NR_PORTS 1 /* use 8 ports by default */
static int major = 0; /* dynamic by default */
MODULE_PARM(major, "i");
/* default is the first printer port on PC's. "short_base" is there too
because it's what we want to use in the code */
static unsigned long base = 0x378;
MODULE_PARM(base, "l");
/* The interrupt line is undefined by default. "short_irq" is as above */
static int irq = 7;
MODULE_PARM(irq, "i");
MODULE_AUTHOR ("Alessandro Rubini");
DECLARE_WAIT_QUEUE_HEAD(short_queue);
int short_open (struct inode *inode, struct file *filp)
{
MOD_INC_USE_COUNT;
return 0;
}
int short_release (struct inode *inode, struct file *filp)
{
MOD_DEC_USE_COUNT;
return 0;
}
ssize_t do_short_read (struct inode *inode, struct file *filp, char *buf,
size_t count, loff_t *f_pos)
{
int retval = count;
unsigned long=base;
unsigned char *kbuf,*ptr;
interruptible_sleep_on(&short_queue);
kbuf=kmalloc(count, GFP_KERNEL);
if (!kbuf) return -ENOMEM;
ptr=kbuf
while (count--) {
*(ptr++) = inb(address);
rmb();
}
if ( (retval > 0) && copy_to_user(buf, kbuf, retval))
retval = -EFAULT;
kfree(kbuf);
return retval;
}
ssize_t short_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
return do_short_read(filp->f_dentry->d_inode, filp, buf, count, f_pos);
}
ssize_t do_short_write (struct inode *inode, struct file *filp, const char *buf,
size_t count, loff_t *f_pos)
{
int retval = count;
unsigned long address = base;
unsigned char *kbuf=kmalloc(count, GFP_KERNEL), *ptr;
if (!kbuf) return -ENOMEM;
if (copy_from_user(kbuf, buf, count))
return -EFAULT;
ptr=kbuf;
while (count--) {
outb(*(ptr++), address);
wmb();
}
kfree(kbuf);
return retval;
}
ssize_t short_write(struct file *filp, const char *buf, size_t count,
loff_t *f_pos)
{
return do_short_write(filp->f_dentry->d_inode, filp, buf, count, f_pos);
}
void short_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
wake_up_interruptible(&short_queue); /* awake any reading process */
}
struct file_operations short_fops = {
read: short_read,
write: short_write,
open: short_open,
release: short_release,
};
int short_init(void)
{
int result;
short_base=base;
short_irq=irq;
SET_MODULE_OWNER(&short_fops);
result=check_region(short_base,SHORT_NR_PORTS);
if (result) {
printk(KERN_INFO "short: can't get I/O port address 0x%lx\n",short_base);
return result;
}
request_region(short_base, SHORT_NR_PORTS, "short");
result = register_chrdev(major, "short", &short_fops);
if (result<0) {
printk(KERN_INFO "short: can't get major number\n");
release_region(short_base,SHORT_NR_PORTS);
return result;
}
if (major == 0) major = result; /* dynamic */
if (short_irq >= 0) {
result = request_irq(short_irq, short_interrupt,
SA_INTERRUPT, "short", NULL);
if (result) {
printk(KERN_INFO "short: can't get assigned irq %i\n",
short_irq);
short_irq = -1;
}
else { /* actually enable it -- assume this *is* a parallel port */
outb(0x10,short_base+2);
}
}
return 0;
}
void short_cleanup(void)
{
if (short_irq >= 0) {
outb(0x0, short_base + 2); /* disable the interrupt */
free_irq(short_irq, NULL);
}
unregister_chrdev(major, "short");
release_region(short_base,SHORT_NR_PORTS);
}
module_init(short_init);
module_exit(short_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -