fails to write to the dummy network device by outb_p(0xff, 0x378) on the parallel port after successfully enabling request_region

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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);
}

[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux