Hi,
I'm currently using the 'linux device drivers' book to get a better understanding of drivers in linux. I also found a simple parallel port driver on the net (
Writing device drivers in Linux: A brief tutorial) and decided to try this one out.
The driver makes use of port address 0x378 and this first gave me an error since also the parport driver was using this port on my fc9 distro. Therefore I removed the ppdev, parport_pc and parport modules (i'm not sure if this is sufficient however). After this, the initialization of the driver was ok and I could find it back in /proc/ioports :
cat /proc/ioports
...
02f8-02ff : serial
0376-0376 : 0000:00:1f.1
0376-0376 : ata_piix
0378-0378 : parlelport
03c0-03df : vga+
03f0-03f1 : pnp 00:0f
...
So next step was to write to the driver and check the result :
echo -n A > /dev/parlelport
As a consequence, I should get a high value at pin2 and pin8, pin 3..7 and pin 9 should be low
After measuring I found out that all pins are high.... This is independent of the fact which character I write to the driver.
Reading back the values of the output port is done with
dd if=/dev/parlelport bs=1 count=1 | od -t x1
0000000 ff
1+0 records in
1+0 records out
1 byte (1 B) copied, 0.000611734 s, 1.6 kB/s
and gives me ff (the same value as I measure on the output port).
For some reason I'm not able to set the output port properly with this driver... Therefore I reloaded the parport driver again and I used parashell (a user program that can be used to write ports). This seems to work fine so I can conclude that my parallel port is not broken and that it has something to do with the driver itself (could be that there is a timing issue in the simple driver...).
Anyone an idea?
-----------------------------------------------------------------------------------------------------
Here's the complete code :
/* Necessary includes for drivers */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/ioport.h>
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_from/to_user */
#include <asm/io.h> /* inb, outb */
/* Function declaration of parlelport.c */
int parlelport_open(struct inode *inode, struct file *filp);
int parlelport_release(struct inode *inode, struct file *filp);
ssize_t parlelport_read(struct file *filp, char *buf,
size_t count, loff_t *f_pos);
ssize_t parlelport_write(struct file *filp, char *buf,
size_t count, loff_t *f_pos);
int parlelport_init(void);
void parlelport_exit(void);
/* Structure that declares the common */
/* file access fcuntions */
struct file_operations parlelport_fops = {
read: parlelport_read,
write: parlelport_write,
open: parlelport_open,
release: parlelport_release
};
/* Driver global variables */
/* Major number */
int parlelport_major = 247;
/* Control variable for memory */
/* reservation of the parallel port*/
int port;
ssize_t parlelport_read(struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
/* Buffer to read the device */
char parlelport_buffer;
int j;
parlelport_buffer = 'A';
printk("<1>parlelport: read value %c from port 0x378\n", parlelport_buffer);
parlelport_buffer = inb_p(0x378);
printk("<1>parlelport: read value %c from port 0x378\n", parlelport_buffer);
for (j = 7; j >= 0; j --)
{
if ( (parlelport_buffer & (1 << j)) )
printk("%d", 1);
else
printk("%d", 0);
}
printk("\n");
/* We transfer data to user space */
copy_to_user(buf,&parlelport_buffer,1);
/* We change the reading position as best suits */
if (*f_pos == 0) {
*f_pos+=1;
return 1;
} else {
return 0;
}
}
ssize_t parlelport_write( struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
char *tmp;
/* Buffer writing to the device */
char parlelport_buffer;
tmp=buf+count-1;
parlelport_buffer = '5';
printk("<1>parlelport: write value %c to port 0x378\n", parlelport_buffer);
copy_from_user(&parlelport_buffer,tmp,1);
printk("<1>parlelport: write value %c to port 0x378\n", parlelport_buffer);
outb_p(parlelport_buffer,0x378);
return 1;
}
int parlelport_open(struct inode *inode, struct file *filp) {
/* Success */
return 0;
}
int parlelport_release(struct inode *inode, struct file *filp) {
/* Success */
return 0;
}
int parlelport_init(void)
{
int result;
/* Registering device */
result = register_chrdev(parlelport_major, "parlelport",
&parlelport_fops);
if (result < 0) {
printk(
"<1>parlelport: cannot obtain major number %d\n",
parlelport_major);
return result;
}
/* Registering port */
port = check_region(0x378, 1);
if (port) {
printk("<1>parlelport: cannot reserve 0x378\n");
result = port;
goto fail;
}
request_region(0x378, 1, "parlelport");
printk("<1>Inserting parlelport module\n");
return 0;
fail:
parlelport_exit();
return result;
}
void parlelport_exit(void)
{
/* Make major number free! */
unregister_chrdev(parlelport_major, "parlelport");
/* Make port free! */
if (!port) {
release_region(0x378,1);
}
printk("<1>Removing parlelport module\n");
}
module_init(parlelport_init);
module_exit(parlelport_exit);
MODULE_LICENSE("GPL");