patch-2.3.11 linux/drivers/char/ppdev.c
Next file: linux/drivers/char/sysrq.c
Previous file: linux/drivers/char/pc_keyb.c
Back to the patch index
Back to the overall index
- Lines: 393
- Date:
Sat Jul 17 21:17:21 1999
- Orig file:
v2.3.10/linux/drivers/char/ppdev.c
- Orig date:
Thu Jul 8 15:42:20 1999
diff -u --recursive --new-file v2.3.10/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c
@@ -50,14 +50,10 @@
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif
-/* The device minor encodes the parport number and (arbitrary)
- * pardevice number as (port << 4) | dev. */
-#define PP_PORT(minor) ((minor >> 4) & 0xf)
-#define PP_DEV(minor) ((minor) & 0xf)
-
struct pp_struct {
struct pardevice * pdev;
wait_queue_head_t irq_wait;
+ int got_irq;
int mode;
unsigned int flags;
};
@@ -71,7 +67,11 @@
#define PP_BUFFER_SIZE 256
#define PARDEVICE_MAX 8
-static struct pp_struct pp_table[PARPORT_MAX][PARDEVICE_MAX];
+static inline void enable_irq (struct pp_struct *pp)
+{
+ struct parport *port = pp->pdev->port;
+ port->ops->enable_irq (port);
+}
static loff_t pp_lseek (struct file * file, long long offset, int origin)
{
@@ -165,17 +165,16 @@
loff_t * ppos)
{
unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
- unsigned int portnum = PP_PORT (minor);
- unsigned int dev = PP_DEV (minor);
+ struct pp_struct *pp = file->private_data;
char * kbuffer;
ssize_t bytes_read = 0;
ssize_t got = 0;
- if (!(pp_table[portnum][dev].flags & PP_CLAIMED)) {
+ if (!(pp->flags & PP_CLAIMED)) {
/* Don't have the port claimed */
- printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n",
+ printk (KERN_DEBUG CHRDEV "%x: claim the port first\n",
minor);
- return -EPERM;
+ return -EINVAL;
}
kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL);
@@ -185,16 +184,16 @@
while (bytes_read < count) {
ssize_t need = min(count - bytes_read, PP_BUFFER_SIZE);
- got = do_read (&pp_table[portnum][dev], kbuffer, need);
+ got = do_read (pp, kbuffer, need);
- if (got < 0) {
+ if (got <= 0) {
if (!bytes_read)
bytes_read = got;
break;
}
- if (copy_to_user (kbuffer, buf + bytes_read, got)) {
+ if (copy_to_user (buf + bytes_read, kbuffer, got)) {
bytes_read = -EFAULT;
break;
}
@@ -212,6 +211,7 @@
}
kfree (kbuffer);
+ enable_irq (pp);
return bytes_read;
}
@@ -219,17 +219,16 @@
loff_t * ppos)
{
unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
- unsigned int portnum = PP_PORT (minor);
- unsigned int dev = PP_DEV (minor);
+ struct pp_struct *pp = file->private_data;
char * kbuffer;
ssize_t bytes_written = 0;
ssize_t wrote;
- if (!(pp_table[portnum][dev].flags & PP_CLAIMED)) {
+ if (!(pp->flags & PP_CLAIMED)) {
/* Don't have the port claimed */
- printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n",
+ printk (KERN_DEBUG CHRDEV "%x: claim the port first\n",
minor);
- return -EPERM;
+ return -EINVAL;
}
kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL);
@@ -244,7 +243,7 @@
break;
}
- wrote = do_write (&pp_table[portnum][dev], kbuffer, n);
+ wrote = do_write (pp, kbuffer, n);
if (wrote < 0) {
if (!bytes_written)
@@ -265,19 +264,19 @@
}
kfree (kbuffer);
+ enable_irq (pp);
return bytes_written;
}
static void pp_irq (int irq, void * private, struct pt_regs * unused)
{
struct pp_struct * pp = (struct pp_struct *) private;
+ pp->got_irq = 1;
wake_up_interruptible (&pp->irq_wait);
}
-static int register_device (int minor)
+static int register_device (int minor, struct pp_struct *pp)
{
- unsigned int portnum = PP_PORT (minor);
- unsigned int dev = PP_DEV (minor);
struct parport * port;
struct pardevice * pdev = NULL;
char *name;
@@ -287,10 +286,10 @@
if (name == NULL)
return -ENOMEM;
- sprintf (name, CHRDEV "%02x", minor);
+ sprintf (name, CHRDEV "%x", minor);
port = parport_enumerate (); /* FIXME: use attach/detach */
- while (port && port->number != portnum)
+ while (port && port->number != minor)
port = port->next;
if (!port) {
@@ -299,9 +298,9 @@
return -ENXIO;
}
- fl = (pp_table[portnum][dev].flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
+ fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
pdev = parport_register_device (port, name, NULL, NULL, pp_irq, fl,
- &pp_table[portnum][dev]);
+ pp);
if (!pdev) {
printk (KERN_WARNING "%s: failed to register device!\n", name);
@@ -309,7 +308,7 @@
return -ENXIO;
}
- pp_table[portnum][dev].pdev = pdev;
+ pp->pdev = pdev;
printk (KERN_DEBUG "%s: registered pardevice\n", name);
return 0;
}
@@ -318,36 +317,38 @@
unsigned int cmd, unsigned long arg)
{
unsigned int minor = MINOR(inode->i_rdev);
- unsigned int portnum = PP_PORT (minor);
- unsigned int dev = PP_DEV (minor);
+ struct pp_struct *pp = file->private_data;
struct parport * port;
/* First handle the cases that don't take arguments. */
if (cmd == PPCLAIM) {
- if (pp_table[portnum][dev].flags & PP_CLAIMED) {
+ if (pp->flags & PP_CLAIMED) {
printk (KERN_DEBUG CHRDEV
- "%02x: you've already got it!\n", minor);
+ "%x: you've already got it!\n", minor);
return -EINVAL;
}
/* Deferred device registration. */
- if (!pp_table[portnum][dev].pdev) {
- int err = register_device (minor);
+ if (!pp->pdev) {
+ int err = register_device (minor, pp);
if (err)
return err;
}
- parport_claim_or_block (pp_table[portnum][dev].pdev);
- pp_table[portnum][dev].flags |= PP_CLAIMED;
+ parport_claim_or_block (pp->pdev);
+ pp->flags |= PP_CLAIMED;
+
+ /* For interrupt-reporting to work, we need to be
+ * informed of each interrupt. */
+ enable_irq (pp);
return 0;
}
- port = pp_table[portnum][dev].pdev->port;
if (cmd == PPEXCL) {
- if (pp_table[portnum][dev].pdev) {
- printk (KERN_DEBUG CHRDEV "%02x: too late for PPEXCL; "
+ if (pp->pdev) {
+ printk (KERN_DEBUG CHRDEV "%x: too late for PPEXCL; "
"already registered\n", minor);
- if (pp_table[portnum][dev].flags & PP_EXCL)
+ if (pp->flags & PP_EXCL)
/* But it's not really an error. */
return 0;
/* There's no chance of making the driver happy. */
@@ -356,22 +357,33 @@
/* Just remember to register the device exclusively
* when we finally do the registration. */
- pp_table[portnum][dev].flags |= PP_EXCL;
+ pp->flags |= PP_EXCL;
+ return 0;
+ }
+
+ if (cmd == PPSETMODE) {
+ int mode;
+ if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
+ return -EFAULT;
+ /* FIXME: validate mode */
+ pp->mode = mode;
return 0;
}
/* Everything else requires the port to be claimed, so check
* that now. */
- if ((pp_table[portnum][dev].flags & PP_CLAIMED) == 0) {
- printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n",
+ if ((pp->flags & PP_CLAIMED) == 0) {
+ printk (KERN_DEBUG CHRDEV "%x: claim the port first\n",
minor);
- return -EPERM;
+ return -EINVAL;
}
+ port = pp->pdev->port;
switch (cmd) {
unsigned char reg;
unsigned char mask;
int mode;
+ int ret;
case PPRSTATUS:
reg = parport_read_status (port);
@@ -389,19 +401,12 @@
sizeof (reg));
case PPYIELD:
- parport_yield_blocking (pp_table[portnum][dev].pdev);
+ parport_yield_blocking (pp->pdev);
return 0;
case PPRELEASE:
- parport_release (pp_table[portnum][dev].pdev);
- pp_table[portnum][dev].flags &= ~PP_CLAIMED;
- return 0;
-
- case PPSETMODE:
- if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
- return -EFAULT;
- /* FIXME: validate mode */
- pp_table[portnum][dev].mode = mode;
+ parport_release (pp->pdev);
+ pp->flags &= ~PP_CLAIMED;
return 0;
case PPWCONTROL:
@@ -439,10 +444,12 @@
if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
return -EFAULT;
/* FIXME: validate mode */
- return parport_negotiate (port, mode);
+ ret = parport_negotiate (port, mode);
+ enable_irq (pp);
+ return ret;
default:
- printk (KERN_DEBUG CHRDEV "%02x: What? (cmd=0x%x\n", minor,
+ printk (KERN_DEBUG CHRDEV "%x: What? (cmd=0x%x)\n", minor,
cmd);
return -EINVAL;
}
@@ -454,24 +461,26 @@
static int pp_open (struct inode * inode, struct file * file)
{
unsigned int minor = MINOR (inode->i_rdev);
- unsigned int portnum = PP_PORT (minor);
- unsigned int dev = PP_DEV (minor);
+ struct pp_struct *pp;
- if (portnum >= PARPORT_MAX)
+ if (minor >= PARPORT_MAX)
return -ENXIO;
- if (pp_table[portnum][dev].pdev)
- return -EBUSY;
+ pp = kmalloc (GFP_KERNEL, sizeof (struct pp_struct));
+ if (!pp)
+ return -ENOMEM;
- pp_table[portnum][dev].mode = IEEE1284_MODE_COMPAT;
- pp_table[portnum][dev].flags = 0;
- init_waitqueue_head (&pp_table[portnum][dev].irq_wait);
+ pp->mode = IEEE1284_MODE_COMPAT;
+ pp->flags = 0;
+ pp->got_irq = 0;
+ init_waitqueue_head (&pp->irq_wait);
/* Defer the actual device registration until the first claim.
* That way, we know whether or not the driver wants to have
* exclusive access to the port (PPEXCL).
*/
- pp_table[portnum][dev].pdev = NULL;
+ pp->pdev = NULL;
+ file->private_data = pp;
MOD_INC_USE_COUNT;
return 0;
@@ -480,42 +489,46 @@
static int pp_release (struct inode * inode, struct file * file)
{
unsigned int minor = MINOR (inode->i_rdev);
- unsigned int portnum = PP_PORT (minor);
- unsigned int dev = PP_DEV (minor);
+ struct pp_struct *pp = file->private_data;
- if (pp_table[portnum][dev].flags & PP_CLAIMED) {
- parport_release (pp_table[portnum][dev].pdev);
- printk (KERN_DEBUG CHRDEV "%02x: released pardevice because "
+ if (pp->flags & PP_CLAIMED) {
+ parport_release (pp->pdev);
+ printk (KERN_DEBUG CHRDEV "%x: released pardevice because "
"user-space forgot\n", minor);
}
- if (pp_table[portnum][dev].pdev) {
- kfree (pp_table[portnum][dev].pdev->name);
- parport_unregister_device (pp_table[portnum][dev].pdev);
- pp_table[portnum][dev].pdev = NULL;
- printk (KERN_DEBUG CHRDEV "%02x: unregistered pardevice\n",
+ if (pp->pdev) {
+ kfree (pp->pdev->name);
+ parport_unregister_device (pp->pdev);
+ pp->pdev = NULL;
+ printk (KERN_DEBUG CHRDEV "%x: unregistered pardevice\n",
minor);
}
+ kfree (pp);
+
MOD_DEC_USE_COUNT;
return 0;
}
-#if 0
static unsigned int pp_poll (struct file * file, poll_table * wait)
{
- unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
- poll_wait (file, &pp_table[minor].irq_wait, wait);
- return 0; /* FIXME! Return value is wrong here */
+ struct pp_struct *pp = file->private_data;
+ unsigned int mask = 0;
+ if (pp->got_irq) {
+ pp->got_irq = 0;
+ mask |= POLLIN | POLLRDNORM;
+ }
+ poll_wait (file, &pp->irq_wait, wait);
+ return mask;
}
-#endif
static struct file_operations pp_fops = {
pp_lseek,
pp_read,
pp_write,
NULL, /* pp_readdir */
- NULL, /* pp_poll */
+ pp_poll,
pp_ioctl,
NULL, /* pp_mmap */
pp_open,
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)