Hi! I've checked in the BIOS of the box that the parallel port (only one) is indeed: base address = 0x378 irq = 7 mode:bi-directional mode I try to write a parallel port kernel module that is able to out all 1 to the output port of the parallel port, which is connected to a dummy device that all output port is connected to ground via a set of LED diode and the most significant bit of the parallel port is also connected to the interrupt pin, which will trigger an interrupt, as described in chapter 9 (communicating with hardware) of the book "Linux Device Drivers (3rd ed)" I have already unloaded parport, lp,. parport_pc and one more modules that are automatically loaded in the kernel and /proc/ioports now shows that 0x378 to 0x37a is unoccupied. Then I load my module, which request_region(tem_base, PORT_SIZE, "tem") at the beginning of init. If error occurs, abort, but if successful, then I try to set all output bits on by: mb(); outb_p(0xFF, tem_base); mb(); The module loads successfully and /proc/ioports shows that 0x378 to 0x37a is now occupied by my module. However the LED of my dummy module fails to glow. What else do I need to do to write to the output port? However when the original system-provided modules are not unloaded, I can successfully turn on all LEDs from the user space by executing this program: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <asm/io.h> #define base 0x378 /* printer port base address */ #define value 255 /* numeric value to send to printer port */ int main(int argc, char **argv) { if (ioperm(base,1,1)) fprintf(stderr, "Couldn't get the port at %x\n", base), exit(1); outb(value, base); } Here is the sourcecode of my toy module: #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/list.h> #include <asm/uaccess.h> #include <linux/slab.h> #include <linux/mm.h> #include <linux/proc_fs.h> #include <linux/wait.h> #include <linux/interrupt.h> #include <asm/system.h> #include <asm/io.h> #include <linux/ioport.h> #define PORT_SIZE 3 struct cdev *tem_dev; MODULE_LICENSE("GPL"); MODULE_AUTHOR("codemaster"); MODULE_DESCRIPTION("dummy parport module"); /** * module_param interface is provided for specifying the tem_major, * tem_minor and tem_dev_count variables, but this customarization is not yet * supported and therefore will be reset to default values at the beginning * of the tem_init_module function. */ int tem_major; /* major number of module */ int tem_minor; /* minor number of module */ int tem_dev_count; /* number of devices */ dev_t dev; /* the device */ module_param(tem_major, int, S_IRUGO); MODULE_PARM_DESC(tem_major, "major number"); module_param(tem_minor, int, S_IRUGO); MODULE_PARM_DESC(tem_minor, "minor number"); module_param(tem_dev_count, int, S_IRUGO); MODULE_PARM_DESC(tem_dev_count, "number of devices"); unsigned long tem_base = 0x378; /* module_param(tem_base, unsigned long, S_IRUGO); */ /** * This function opens the virtual disk, if it is opened in the write-only * mode, all memory pages will be freed. */ int tem_open(struct inode *inode, struct file *filp) { return 0; /* success */ } /** * This function releases the virtual disk, but nothing needs to be done * in this case. */ int tem_release (struct inode *inode, struct file *filp) { return 0; } ssize_t tem_read (struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { printk(KERN_WARNING "in tem_read"); return count; } /** * This function writes from the user buffer to the virtual disk of this * module */ ssize_t tem_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { return count; } /** * The ioctl function, which nothing needs to be done in this case. */ int tem_ioctl (struct inode *inode, struct file *filp, unsigned cmd, unsigned long arg) { return 0; } struct file_operations tem_fops = { .owner = THIS_MODULE, .read = tem_read, .write = tem_write, .ioctl = tem_ioctl, .open = tem_open, .release = tem_release, }; /** * Initialise the module and create the master device */ int __init tem_init_module(void){ int result; /* initialization of tem global variables, which resets values possibily modified by module_param, which modifications are currently not yet supported */ tem_major = 0; tem_minor = 0; tem_dev_count = 1; if (NULL == request_region(tem_base, PORT_SIZE, "tem")) { printk(KERN_WARNING "mod_tem: can't get I/O port address 0x%03lx\n", tem_base); return -EBUSY; /* return -ENODEV; */ } mb(); outb_p(0xFF, tem_base); /* to set all output bits in base_addr to high */ mb(); dev = MKDEV(tem_major, tem_minor); if (tem_major) { result = register_chrdev_region(dev, tem_dev_count, "tem"); } else { result = alloc_chrdev_region(&dev, tem_minor, tem_dev_count, "tem"); tem_major = MAJOR(dev); } if (result < 0) { printk(KERN_WARNING "mod_tem: can't get major number\n"); release_region(tem_base, PORT_SIZE); return result; } tem_dev = cdev_alloc(); tem_dev->ops = &tem_fops; tem_dev->owner = THIS_MODULE; result = cdev_add(tem_dev, dev, tem_dev_count); if (result < 0) { printk(KERN_WARNING "mod_tem: can't add tem to the system\n"); unregister_chrdev_region(dev, tem_dev_count); release_region(tem_base, PORT_SIZE); return result; } printk(KERN_WARNING "Hello world from Template Module\n"); return 0; } /** * Finalise the module */ void __exit tem_exit_module(void){ cdev_del(tem_dev); unregister_chrdev_region(dev, tem_dev_count); release_region(tem_base, PORT_SIZE); printk(KERN_WARNING "Good bye from Template Module\n"); } module_init(tem_init_module); module_exit(tem_exit_module); Thanks!
#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/list.h> #include <asm/uaccess.h> #include <linux/slab.h> #include <linux/mm.h> #include <linux/proc_fs.h> #include <linux/wait.h> #include <linux/interrupt.h> #include <asm/system.h> #include <asm/io.h> #include <linux/ioport.h> #define PORT_SIZE 3 struct cdev *tem_dev; MODULE_LICENSE("GPL"); MODULE_AUTHOR("abc"); MODULE_DESCRIPTION("dummy parport module"); /** * module_param interface is provided for specifying the tem_major, * tem_minor and tem_dev_count variables, but this customarization is not yet * supported and therefore will be reset to default values at the beginning * of the tem_init_module function. */ int tem_major; /* major number of module */ int tem_minor; /* minor number of module */ int tem_dev_count; /* number of devices */ dev_t dev; /* the device */ module_param(tem_major, int, S_IRUGO); MODULE_PARM_DESC(tem_major, "major number"); module_param(tem_minor, int, S_IRUGO); MODULE_PARM_DESC(tem_minor, "minor number"); module_param(tem_dev_count, int, S_IRUGO); MODULE_PARM_DESC(tem_dev_count, "number of devices"); unsigned long tem_base = 0x378; /* module_param(tem_base, unsigned long, S_IRUGO); */ /** * This function opens the virtual disk, if it is opened in the write-only * mode, all memory pages will be freed. */ int tem_open(struct inode *inode, struct file *filp) { return 0; /* success */ } /** * This function releases the virtual disk, but nothing needs to be done * in this case. */ int tem_release (struct inode *inode, struct file *filp) { return 0; } ssize_t tem_read (struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { printk(KERN_WARNING "in tem_read"); return count; } /** * This function writes from the user buffer to the virtual disk of this * module */ ssize_t tem_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { return count; } /** * The ioctl function, which nothing needs to be done in this case. */ int tem_ioctl (struct inode *inode, struct file *filp, unsigned cmd, unsigned long arg) { return 0; } struct file_operations tem_fops = { .owner = THIS_MODULE, .read = tem_read, .write = tem_write, .ioctl = tem_ioctl, .open = tem_open, .release = tem_release, }; /** * Initialise the module and create the master device */ int __init tem_init_module(void){ int result; /* initialization of tem global variables, which resets values possibily modified by module_param, which modifications are currently not yet supported */ tem_major = 0; tem_minor = 0; tem_dev_count = 1; if (NULL == request_region(tem_base, PORT_SIZE, "tem")) { printk(KERN_WARNING "mod_tem: can't get I/O port address 0x%03lx\n", tem_base); return -EBUSY; /* return -ENODEV; */ } mb(); outb_p(0xFF, tem_base); /* to set all output bits in base_addr to high */ mb(); dev = MKDEV(tem_major, tem_minor); if (tem_major) { result = register_chrdev_region(dev, tem_dev_count, "tem"); } else { result = alloc_chrdev_region(&dev, tem_minor, tem_dev_count, "tem"); tem_major = MAJOR(dev); } if (result < 0) { printk(KERN_WARNING "mod_tem: can't get major number\n"); release_region(tem_base, PORT_SIZE); return result; } tem_dev = cdev_alloc(); tem_dev->ops = &tem_fops; tem_dev->owner = THIS_MODULE; result = cdev_add(tem_dev, dev, tem_dev_count); if (result < 0) { printk(KERN_WARNING "mod_tem: can't add tem to the system\n"); unregister_chrdev_region(dev, tem_dev_count); release_region(tem_base, PORT_SIZE); return result; } printk(KERN_WARNING "Hello world from Template Module\n"); return 0; } /** * Finalise the module */ void __exit tem_exit_module(void){ cdev_del(tem_dev); unregister_chrdev_region(dev, tem_dev_count); release_region(tem_base, PORT_SIZE); printk(KERN_WARNING "Good bye from Template Module\n"); } module_init(tem_init_module); module_exit(tem_exit_module);
Attachment:
Makefile
Description: Binary data
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <asm/io.h> #define base 0x378 /* printer port base address */ #define value 255 /* numeric value to send to printer port */ int main(int argc, char **argv) { if (ioperm(base,1,1)) fprintf(stderr, "Couldn't get the port at %x\n", base), exit(1); outb(value, base); }