patch-2.3.12 linux/drivers/char/ppdev.c
Next file: linux/drivers/char/ppdev.h
Previous file: linux/drivers/char/mem.c
Back to the patch index
Back to the overall index
- Lines: 246
- Date:
Wed Jul 28 01:19:37 1999
- Orig file:
v2.3.11/linux/drivers/char/ppdev.c
- Orig date:
Wed Jul 21 15:46:48 1999
diff -u --recursive --new-file v2.3.11/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c
@@ -11,7 +11,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * A /dev/parportxy device node represents an arbitrary device ('y')
+ * A /dev/parportx device node represents an arbitrary device
* on port 'x'. The following operations are possible:
*
* open do nothing, set up default IEEE 1284 protocol to be COMPAT
@@ -30,6 +30,8 @@
* RSTATUS read_status
* NEGOT parport_negotiate
* YIELD parport_yield_blocking
+ * WCTLONIRQ on interrupt, set control lines
+ * CLRIRQ clear (and return) interrupt count
* read/write read or write in current IEEE 1284 protocol
* select wait for interrupt (in readfds)
*/
@@ -53,9 +55,13 @@
struct pp_struct {
struct pardevice * pdev;
wait_queue_head_t irq_wait;
- int got_irq;
+ atomic_t irqc;
int mode;
unsigned int flags;
+ int irqresponse;
+ unsigned char irqctl;
+ struct ieee1284_info state;
+ struct ieee1284_info saved_state;
};
/* pp_struct.flags bitfields */
@@ -85,8 +91,10 @@
{
size_t (*fn) (struct parport *, void *, size_t, int);
struct parport *port = pp->pdev->port;
+ int addr = pp->mode & IEEE1284_ADDR;
+ int mode = pp->mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
- switch (pp->mode) {
+ switch (mode) {
case IEEE1284_MODE_COMPAT:
/* This is a write-only mode. */
return -EIO;
@@ -100,7 +108,10 @@
break;
case IEEE1284_MODE_EPP:
- fn = port->ops->epp_read_data;
+ if (addr)
+ fn = port->ops->epp_read_addr;
+ else
+ fn = port->ops->epp_read_data;
break;
case IEEE1284_MODE_ECP:
@@ -128,8 +139,10 @@
{
size_t (*fn) (struct parport *, const void *, size_t, int);
struct parport *port = pp->pdev->port;
+ int addr = pp->mode & IEEE1284_ADDR;
+ int mode = pp->mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
- switch (pp->mode) {
+ switch (mode) {
case IEEE1284_MODE_NIBBLE:
case IEEE1284_MODE_BYTE:
/* Read-only modes. */
@@ -140,16 +153,25 @@
break;
case IEEE1284_MODE_EPP:
- fn = port->ops->epp_write_data;
+ if (addr)
+ fn = port->ops->epp_write_addr;
+ else
+ fn = port->ops->epp_write_data;
break;
case IEEE1284_MODE_ECP:
case IEEE1284_MODE_ECPRLE:
- fn = port->ops->ecp_write_data;
+ if (addr)
+ fn = port->ops->ecp_write_addr;
+ else
+ fn = port->ops->ecp_write_data;
break;
case IEEE1284_MODE_ECPSWE:
- fn = parport_ieee1284_ecp_write_data;
+ if (addr)
+ fn = parport_ieee1284_ecp_write_addr;
+ else
+ fn = parport_ieee1284_ecp_write_data;
break;
default:
@@ -271,7 +293,13 @@
static void pp_irq (int irq, void * private, struct pt_regs * unused)
{
struct pp_struct * pp = (struct pp_struct *) private;
- pp->got_irq = 1;
+
+ if (pp->irqresponse) {
+ parport_write_control (pp->pdev->port, pp->irqctl);
+ pp->irqresponse = 0;
+ }
+
+ atomic_inc (&pp->irqc);
wake_up_interruptible (&pp->irq_wait);
}
@@ -322,6 +350,9 @@
/* First handle the cases that don't take arguments. */
if (cmd == PPCLAIM) {
+ struct ieee1284_info *info;
+ int first_claim = 0;
+
if (pp->flags & PP_CLAIMED) {
printk (KERN_DEBUG CHRDEV
"%x: you've already got it!\n", minor);
@@ -333,6 +364,8 @@
int err = register_device (minor, pp);
if (err)
return err;
+
+ first_claim = 1;
}
parport_claim_or_block (pp->pdev);
@@ -341,6 +374,30 @@
/* For interrupt-reporting to work, we need to be
* informed of each interrupt. */
enable_irq (pp);
+
+ /* We may need to fix up the state machine. */
+ info = &pp->pdev->port->ieee1284;
+ pp->saved_state.mode = info->mode;
+ pp->saved_state.phase = info->phase;
+ if (pp->mode != info->mode) {
+ int phase = IEEE1284_PH_FWD_IDLE;
+
+ if (first_claim) {
+ info->mode = pp->mode;
+ switch (pp->mode & ~(IEEE1284_DEVICEID
+ | IEEE1284_ADDR)) {
+ case IEEE1284_MODE_NIBBLE:
+ case IEEE1284_MODE_BYTE:
+ phase = IEEE1284_PH_REV_IDLE;
+ }
+ info->phase = phase;
+ } else {
+ /* Just restore the state. */
+ info->mode = pp->state.mode;
+ info->phase = pp->state.phase;
+ }
+ }
+
return 0;
}
@@ -380,6 +437,7 @@
port = pp->pdev->port;
switch (cmd) {
+ struct ieee1284_info *info;
unsigned char reg;
unsigned char mask;
int mode;
@@ -405,6 +463,12 @@
return 0;
case PPRELEASE:
+ /* Save the state machine's state. */
+ info = &pp->pdev->port->ieee1284;
+ pp->state.mode = info->mode;
+ pp->state.phase = info->phase;
+ info->mode = pp->saved_state.mode;
+ info->phase = pp->saved_state.phase;
parport_release (pp->pdev);
pp->flags &= ~PP_CLAIMED;
return 0;
@@ -443,11 +507,36 @@
case PPNEGOT:
if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
return -EFAULT;
- /* FIXME: validate mode */
- ret = parport_negotiate (port, mode);
+ switch ((ret = parport_negotiate (port, mode))) {
+ case 0: break;
+ case -1: /* handshake failed, peripheral not IEEE 1284 */
+ ret = -EIO;
+ break;
+ case 1: /* handshake succeeded, peripheral rejected mode */
+ ret = -ENXIO;
+ break;
+ }
enable_irq (pp);
return ret;
+ case PPWCTLONIRQ:
+ if (copy_from_user (®, (unsigned char *) arg,
+ sizeof (reg)))
+ return -EFAULT;
+
+ /* Remember what to set the control lines to, for next
+ * time we get an interrupt. */
+ pp->irqctl = reg;
+ pp->irqresponse = 1;
+ return 0;
+
+ case PPCLRIRQ:
+ ret = atomic_read (&pp->irqc);
+ if (copy_to_user ((int *) arg, &ret, sizeof (ret)))
+ return -EFAULT;
+ atomic_sub (ret, &pp->irqc);
+ return 0;
+
default:
printk (KERN_DEBUG CHRDEV "%x: What? (cmd=0x%x)\n", minor,
cmd);
@@ -472,7 +561,7 @@
pp->mode = IEEE1284_MODE_COMPAT;
pp->flags = 0;
- pp->got_irq = 0;
+ atomic_set (&pp->irqc, 0);
init_waitqueue_head (&pp->irq_wait);
/* Defer the actual device registration until the first claim.
@@ -515,10 +604,10 @@
{
struct pp_struct *pp = file->private_data;
unsigned int mask = 0;
- if (pp->got_irq) {
- pp->got_irq = 0;
+
+ if (atomic_read (&pp->irqc))
mask |= POLLIN | POLLRDNORM;
- }
+
poll_wait (file, &pp->irq_wait, wait);
return mask;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)