[Linux-parport] My own driver...
hinko.kocevar at cetrtapot.si
hinko.kocevar at cetrtapot.si
Tue Jan 31 11:22:15 EST 2006
Hi,
I'm trying out the driver that came with LDD3 as an example. It is
called short.c. It implements basic LPT port access for read/write every
bit(pin that is).
I can't seem to get any valid info to/from the port if using this
short.c driver - if using parport and parport_pc I can set pins from
userspace just fine..
Here is code for kernel module, let me know if you spot what am I missing:
#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.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/kdev_t.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/poll.h>
#include <linux/wait.h>
#include <asm/io.h>
#define SHORT_NR_PORTS 8 /* use 8 ports by default */
/*
* all of the parameters have no "short_" prefix, to save typing when
* specifying them at load time
*/
static int major = 0; /* dynamic by default */
/* 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;
unsigned long short_base = 0;
MODULE_AUTHOR ("Alessandro Rubini");
MODULE_LICENSE("Dual BSD/GPL");
int short_open (struct inode *inode, struct file *filp)
{
return 0;
}
int short_release (struct inode *inode, struct file *filp)
{
return 0;
}
/* first, the port-oriented device */
ssize_t do_short_read (struct inode *inode, struct file *filp, char
__user *buf,
size_t count, loff_t *f_pos)
{
int retval = count, minor = iminor (inode);
unsigned long port = short_base + (minor&0x0f);
unsigned char *kbuf = kmalloc(count, GFP_KERNEL), *ptr;
if (!kbuf)
return -ENOMEM;
ptr = kbuf;
printk("do_short_read: ");
while (count--) {
*(ptr++) = inb(port);
rmb();
printk(" 0x%x", *(ptr-1));
}
printk("\n");
if ((retval > 0) && copy_to_user(buf, kbuf, retval))
retval = -EFAULT;
kfree(kbuf);
return retval;
}
ssize_t short_read(struct file *filp, char __user *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 __user *buf,
size_t count, loff_t *f_pos)
{
int retval = count, minor = iminor(inode);
unsigned long port = short_base + (minor&0x0f);
unsigned char *kbuf = kmalloc(count, GFP_KERNEL), *ptr;
if (!kbuf)
return -ENOMEM;
if (copy_from_user(kbuf, buf, count))
return -EFAULT;
ptr = kbuf;
printk("do_short_write: ");
while (count--) {
outb(*(ptr++), port);
wmb();
printk(" 0x%x", *(ptr-1));
}
printk("\n");
kfree(kbuf);
return retval;
}
ssize_t short_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
{
return do_short_write(filp->f_dentry->d_inode, filp, buf, count,
f_pos);
}
unsigned int short_poll(struct file *filp, poll_table *wait)
{
return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
}
struct file_operations short_fops = {
.owner = THIS_MODULE,
.read = short_read,
.write = short_write,
.poll = short_poll,
.open = short_open,
.release = short_release,
};
/* Finally, init and cleanup */
int short_init(void)
{
int result;
/*
* first, sort out the base/short_base ambiguity: we'd better
* use short_base in the code, for clarity, but allow setting
* just "base" at load time. Same for "irq".
*/
short_base = base;
if (! request_region(short_base, SHORT_NR_PORTS, "short")) {
printk(KERN_INFO "short: can't get I/O port address 0x%lx\n",
short_base);
return -ENODEV;
}
/* Here we register our device - should not fail thereafter */
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); /* FIXME - use-mem
case? */
return result;
}
if (major == 0) major = result; /* dynamic */
printk("SHORT: Registered driver, result=%d\n", result);
return 0;
}
void short_cleanup(void)
{
printk("SHORT: UN-register driver\n");
unregister_chrdev(major, "short");
release_region(short_base,SHORT_NR_PORTS);
}
module_init(short_init);
module_exit(short_cleanup);
best regards,
hinko
--
ČETRTA POT, d.o.o., Kranj
Planina 3
4000 Kranj
Slovenija
Tel. +386 (0) 4 280 66 37
E-mail: hinko.kocevar at cetrtapot.si
Http: www.cetrtapot.si
More information about the Linux-parport
mailing list