John Coppens | 14 Feb 2013 18:46
Favicon

Parport woes

Hello people.

I have this homebrew parallel PIC programmer which I've been using for years.
With the advent of parport-less PC, I transferred the programmer to an older
PC. When I tried to run the program, I found that the programmer acted
erratically.

I wrote a small program in C, which just ioperm's the ports, writes a 
counter to the parport a number of timpes, and releases the port,
and noticed that there were glitches where the bits were set to 0. So I
modified the test program to just write 1's, at a rate of 1000/second.

On the oscilloscope I could then see that the port was regularly (about twice
per second, though not precise) cleared to 0.

I tried: rmmod'ing lp, ppdev, parport, parport_pc (in difference combinations
and one by one). I stopped cupsd. I went into the BIOS and set the parport
to basic SPP operation.

Does anyone have suggestions? Who could be clearing the parport output?
Is there any way to detect which program accesses the port?

John
Picon

не запускается parport




-- parport как запустить


_______________________________________________
Linux-parport mailing list
Linux-parport <at> lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-parport
Johann Klammer | 18 Oct 2012 07:31
Favicon

[PATCH/RFC] ppdev: Adds support for async I/O with DMA and ECP

Hello,
This patch adds AIO+ECP+DMA capability to the userspace ppdev device.
For an example on how this may be used, see:
https://github.com/klammerj/dspar/blob/master/dump/main.c

Patch is against linux 3.7.0-rc1 from kernel.org

Was once used for this piece of hardware:
https://github.com/klammerj/dspar

Had to edit the code to match current kernel sources, but had no 
opportunity to test it, as new kernel f*s up the screen here (it does 
compile).

Old code can be found here:
http://members.aon.at/~aklamme4/parport/index.html

The plip2.c does not work very well, and is not included in patch.

regards,
JK

diff -uprN prev/drivers/char/ppdev.c new/drivers/char/ppdev.c
--- prev/drivers/char/ppdev.c	2012-10-14 23:41:04.000000000 +0200
+++ new/drivers/char/ppdev.c	2012-10-16 16:03:18.000000000 +0200
 <at>  <at>  -104,6 +104,300  <at>  <at>  static inline void pp_enable_irq (struct
 	port->ops->enable_irq (port);
 }

+struct pp_ki
+{
+	int len_real;
+	void * buffer;
+	struct kiocb *cb;
+	const struct iovec *iov;
+	struct parport *pport;
+	unsigned long count;
+};
+
+
+/**
+ * pp_aio_cancel - cancel an async parport_read/write
+ * Context: !in_interrupt()
+ *
+ * May fail with -EAGAIN if transfer has already started
+ */
+static int pp_aio_cancel(struct kiocb *iocb, struct io_event *e)
+{
+	struct pp_ki * u=iocb->private;
+	e->res=0;
+	e->res2=-EAGAIN;
+	if(!u->pport->ops->cancel_transaction(u->pport, u->buffer))
+		return -EAGAIN;
+	e->res=0;
+	e->res2=-ECANCELED;
+	kfree(u->buffer);
+	kfree(u);
+	return 0;
+}
+
+/**
+ * pp_aio_read_retry - entry point for copying and returning read data
+ *
+ * The aio core sets mm context up so that copy_to_user works as expected here.
+ */
+static ssize_t pp_aio_read_retry(struct kiocb *iocb)
+{
+	struct pp_ki * u=iocb->private;
+	ssize_t			len, total;
+	void			*to_copy;
+	int			i;
+
+	total = u->len_real;
+	len = 0;
+	to_copy = u->buffer;
+	for (i=0; i < u->count; i++) {
+		ssize_t this = min((ssize_t)(u->iov[i].iov_len), total);
+
+		if (copy_to_user(u->iov[i].iov_base, to_copy, this)) {
+			if (len == 0)
+				len = -EFAULT;
+			break;
+		}
+
+		total -= this;
+		len += this;
+		to_copy += this;
+		if (total == 0)
+			break;
+	}
+	kfree(u->buffer);
+	kfree(u);
+	return len;
+}
+
+/**
+ * pp_aio_read_cb - gets called by the parport driver
+ *
+ */
+static void pp_aio_read_cb(int *data,void * buffer,int len_real)
+{
+	struct pp_ki * u=(struct pp_ki *)data;
+	struct kiocb * cb=u->cb;
+	u->len_real=len_real;	
+	cb->private=u;
+	kick_iocb(cb);
+}
+
+/**
+ * pp_aio_read - submits an async read request
+ *  <at> iocb: the aio control block to work on
+ *  <at> iov: io vector to fill
+ *  <at> count: size of the io vector
+ *  <at> o: file offset. ignored
+ * Context: !in_interrupt()
+ *
+ * Uses the async parport interface. Requires the peripheral to use ECP handshakes.
+ * Submits the request to the lowlevel parport driver,
+ * sets the retry function and returns -EIOCBRETRY.
+ * The notification callback pp_aio_read_cb() will later kick_iocb() to
+ * retry and return the read data.
+ * May return -ENOMEM if allocation of dma buffer or user data fails.
+ * May read less data than asked to if DMA memory is low or the request is too big.
+ * May return other errors if parport_submit_transaction() fails fo any reason.
+ * Page Migration would be nice.
+ */
+static ssize_t pp_aio_read (struct kiocb * iocb, const struct iovec * iov, 
+			unsigned long count, loff_t o)
+{
+	struct file* file;
+	struct pp_struct * pp;
+	struct parport *pport;
+	struct pp_ki * u;
+	char * bufptr;
+	int len,rv;
+	file=iocb->ki_filp;
+	if(!file)
+		return -EBADF;
+	pp=file->private_data;
+	if(!pp)
+		return -EBADF;
+	pport=pp->pdev->port;
+	if(!pport)
+		return -EBADF;
+	
+	if (!(pp->flags & PP_CLAIMED)) {
+		/* Don't have the port claimed */
+		printk (KERN_DEBUG CHRDEV " claim the port first\n");
+		return -EINVAL;
+	}
+	
+	if(!pport->ops->submit_transaction)
+	{
+		return -ENOSYS;
+	}
+	
+	len=iov_length(iov,count);
+	bufptr=kmalloc(len,GFP_DMA);
+	//degrade gracefully
+	while((len>PAGE_SIZE)&&(!bufptr))
+	{
+		len/=2;
+		if(len<PAGE_SIZE)
+		len=PAGE_SIZE;
+		bufptr=kmalloc(len,GFP_DMA);
+	}
+	if(!bufptr)//not even a single page
+		return -ENOMEM;
+	
+	u=kmalloc(sizeof(struct pp_ki),GFP_KERNEL);
+	if(!u)
+	{
+		kfree(bufptr);
+		return -ENOMEM;
+	}
+		
+	u->buffer=bufptr;
+	u->cb=iocb;
+	u->iov=iov;
+	u->count=count;
+	u->pport=pport;
+	iocb->private=u;
+	iocb->ki_cancel = pp_aio_cancel;
+	iocb->ki_retry=pp_aio_read_retry;
+
+	rv=pport->ops->submit_transaction(pport, bufptr, len, 0, PARPORT_AIO_ACT_ECP_R_D, (int *)u, pp_aio_read_cb);
+	if(rv)
+	{
+		kfree(bufptr);
+		kfree(u);
+		iocb->private=NULL;
+		return rv;
+	}
+	return -EIOCBRETRY;
+}
+
+/**
+ * pp_aio_write_cb - gets called by the parport driver
+ *
+ */
+static void pp_aio_write_cb(int *data,void * buf,int len_real)
+{
+	struct pp_ki * u=(struct pp_ki *)data;
+	struct kiocb * cb=u->cb;
+	u->len_real=len_real;
+	cb->private = NULL;
+	aio_complete(cb, len_real, 0);
+	kfree(u->buffer);
+	kfree(u);
+}
+
+/**
+ * pp_aio_write - submits an async write request
+ *  <at> iocb: the aio control block to work on
+ *  <at> iov: io vector to fill
+ *  <at> count: size of the io vector
+ *  <at> o: file offset. ignored
+ * Context: !in_interrupt()
+ *
+ * very similar to pp_aio_read().
+ * Does not use or need a retry.
+ */
+static ssize_t pp_aio_write (struct kiocb * iocb, const struct iovec * iov, 
+			unsigned long count, loff_t o)
+{
+	struct file* file;
+	struct pp_struct * pp;
+	struct parport *pport;
+	struct pp_ki * u;
+	ssize_t			len, total;
+	void			*to_copy;
+	int			i;
+	char * bufptr;
+	int rv;
+	file=iocb->ki_filp;
+	if(!file)
+		return -EBADF;
+	pp=file->private_data;
+	if(!pp)
+		return -EBADF;
+	pport=pp->pdev->port;
+	if(!pport)
+		return -EBADF;
+	
+	if (!(pp->flags & PP_CLAIMED)) {
+		/* Don't have the port claimed */
+		printk (KERN_DEBUG CHRDEV " claim the port first\n");
+		return -EINVAL;
+	}
+	
+	if(!pport->ops->submit_transaction)
+	{
+		return -ENOSYS;
+	}
+	
+	len=iov_length(iov,count);
+	bufptr=kmalloc(len,GFP_DMA);
+	//degrade gracefully
+	while((len>PAGE_SIZE)&&(!bufptr))
+	{
+		len/=2;
+		if(len<PAGE_SIZE)
+		len=PAGE_SIZE;
+		bufptr=kmalloc(len,GFP_DMA);
+	}
+	if(!bufptr)//not even a single page
+		return -ENOMEM;
+	
+	u=kmalloc(sizeof(struct pp_ki),GFP_KERNEL);
+	if(!u)
+	{
+		kfree(bufptr);
+		return -ENOMEM;
+	}
+		
+	u->buffer=bufptr;
+	u->cb=iocb;
+	u->iov=iov;
+	u->count=count;
+	u->pport=pport;
+	iocb->private=u;
+	iocb->ki_cancel = pp_aio_cancel;
+	iocb->ki_retry=pp_aio_read_retry;
+
+	total = len;
+	len = 0;
+	to_copy = u->buffer;
+	for (i=0; i < u->count; i++) {
+		ssize_t this = min((ssize_t)(u->iov[i].iov_len), total);
+
+		if (copy_from_user(to_copy, u->iov[i].iov_base, this)) {
+			if (len == 0)
+				len = -EFAULT;
+			break;
+		}
+
+		total -= this;
+		len += this;
+		to_copy += this;
+		if (total == 0)
+			break;
+	}
+	
+	if(len<0)
+	{
+		kfree(bufptr);
+		kfree(u);
+		iocb->private=NULL;
+		return len;
+	}
+	
+	rv=pport->ops->submit_transaction(pport, bufptr, len, 0, PARPORT_AIO_ACT_ECP_W_D, (int *)u, pp_aio_write_cb);
+	if(rv)
+	{
+		kfree(bufptr);
+		kfree(u);
+		iocb->private=NULL;
+		return rv;
+	}
+	
+	return -EIOCBQUEUED;
+}
+
 static ssize_t pp_read (struct file * file, char __user * buf, size_t count,
 			loff_t * ppos)
 {
 <at>  <at>  -750,6 +1044,8  <at>  <at>  static const struct file_operations pp_f
 	.unlocked_ioctl	= pp_ioctl,
 	.open		= pp_open,
 	.release	= pp_release,
+	.aio_read = 	pp_aio_read,
+	.aio_write = 	pp_aio_write,
 };

 static void pp_attach(struct parport *port)
diff -uprN prev/drivers/parport/parport_pc.c new/drivers/parport/parport_pc.c
--- prev/drivers/parport/parport_pc.c	2012-10-14 23:41:04.000000000 +0200
+++ new/drivers/parport/parport_pc.c	2012-10-18 07:16:58.000000000 +0200
 <at>  <at>  -892,6 +892,777  <at>  <at>  static size_t parport_pc_ecp_write_block

 	return written;
 }
+
+static int parport_end_dma(struct parport *port,struct parport_aio_te *te);
+static int parport_finish_dma(struct parport *port,struct parport_aio_te *te);
+static int parport_init_dma(struct parport *port,struct parport_aio_te *te);
+static int parport_start_dma(struct parport *port,struct parport_aio_te *te);
+
+/* ecp_forward_to_reverse - reverses link in ECP mode. AUTOFD STROBE and SELECTIN DCR Bits should be zero
before doing this
+
+Extended Capabilities Port: Specifications
+Revision 1.06
+July 14, 1993
+Microsoft Corporation
+
+page 34:
+
+1. Complete the current forward transfer.
+2. Place the ECP port into PS2 mode (001).
+3. Set the direction bit to 1 (reverse), causing the ECP port data drivers to tri-state.
+4. Set the ECP port into ECP mode (011), enabling the hardware assist.
+5. Write to the DCR, causing nInit to go low. This requests a reverse transfer from the
+   peripheral.
+6. The peripheral will drive pe low when it has started the reverse transfer. Hardware will
+   automatically move data into the ECP FIFO from the ECP data lines.
+7. Set up a ReadString or execute a ReadByte operation.
+
+number 1 and 2 should be done before calling this function
+*/
+static
+int ecp_forward_to_reverse (struct parport *port)
+{
+	int retval;
+	
+/*3. Set the direction bit to 1 (reverse), causing the ECP port data drivers to tri-state.*/
+	parport_data_reverse (port);
+
+/*4. Set the ECP port into ECP mode (011), enabling the hardware assist.*/
+	frob_econtrol (port, (7<<5), (ECR_ECP<<5));
+	
+/*5. Write to the DCR, causing nInit to go low. This requests a reverse transfer from the
+   peripheral.*/
+	parport_frob_control (port,
+			      PARPORT_CONTROL_INIT,
+			      0);
+
+/*6. The peripheral will drive pe low when it has started the reverse transfer. Hardware will
+   automatically move data into the ECP FIFO from the ECP data lines.*/
+	retval = parport_wait_peripheral (port,
+					  PARPORT_STATUS_PAPEROUT, 0);
+	
+	if (!retval) {
+		DPRINTK (KERN_DEBUG "%s: ECP direction: reverse\n",
+			 port->name);
+		port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+	} else {
+		parport_data_forward (port);
+		DPRINTK (KERN_DEBUG "%s: ECP direction: failed to reverse\n",
+			 port->name);
+		port->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN;
+	}
+
+	return retval;
+}
+
+/* ecp_reverse_to_forward - reverses link in ECP mode. AUTOFD STROBE and SELECTIN DCR Bits should be zero
before doing this
+
+Extended Capabilities Port: Specifications
+Revision 1.06
+July 14, 1993
+Microsoft Corporation
+
+page 36:
+
+Reverse to Forward Negotiation
+After the ECP port has moved data in ECP mode (011) in the reverse direction and a change of
+direction is required, the following steps must be taken:
+1. First, negotiate the state of the ECP port (the peripheral) back into forward mode. This is
+    done by setting nInit high and waiting for the state of pe go high. This causes the peripheral
+    to terminate any ongoing reverse transfer.
+2. The mode of the ECP port is changed to PS2 mode 001.
+3. The direction bit is changed to 0. At this point, the bus and the ECP port are in the
+    forward-idle state.
+*/
+
+static
+int ecp_reverse_to_forward (struct parport *port)
+{
+	int retval;
+
+	/* 1. First, negotiate the state of the ECP port (the peripheral) back into forward mode. This is
+    done by setting nInit high and waiting for the state of pe go high. This causes the peripheral
+    to terminate any ongoing reverse transfer. */
+	parport_frob_control (port,
+			      PARPORT_CONTROL_INIT,
+			      PARPORT_CONTROL_INIT);
+
+	retval = parport_wait_peripheral (port,
+					  PARPORT_STATUS_PAPEROUT,
+					  PARPORT_STATUS_PAPEROUT);
+
+	if (!retval) {
+		/* 2. The mode of the ECP port is changed to PS2 mode 001. */
+		frob_econtrol (port, (7<<5), (ECR_PS2<<5));
+
+		/* 3. The direction bit is changed to 0. At this point, the bus and the ECP port are in the
+	    forward-idle state. */
+		parport_data_forward (port);
+		DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
+			 port->name);
+		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+	} else {
+		DPRINTK (KERN_DEBUG
+			 "%s: ECP direction: failed to switch forward\n",
+			 port->name);
+		port->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN;
+	}
+
+
+	return retval;
+}
+
+/**
+ * wait_ecr - wait for flag(s) to change
+ *  <at> port the port to use
+ *  <at> which which bits to check
+ *  <at> state state to wait for
+ *  <at> timeout how long to wait in jiffies
+ * will busy wait for at least 1000 microseconds
+ */
+static int wait_ecr(struct parport *port, unsigned char which, unsigned char state, unsigned long timeout)
+{
+	unsigned char st;
+	unsigned long deadline;
+	unsigned long ctr;//timeout for busy waiting
+	deadline=jiffies+timeout;
+	st=inb (ECONTROL (port));
+	st&=which;
+	
+	ctr=0;
+	while(ctr<1000)
+	{
+		if(st==state)
+			return 0;
+		udelay(1);
+		ctr++;
+		st=inb (ECONTROL (port));
+		st&=which;
+	}
+	
+	while(st!=state)
+	{
+		DPRINTK( KERN_DEBUG "waiting\n");
+		if(time_after (jiffies, deadline))
+			return 1;
+		schedule_timeout_uninterruptible(1);
+		st=inb (ECONTROL (port));
+		st&=which;
+	}
+	return 0;
+}
+
+
+/**
+ * set_dir - changes direction appropriately
+ *  <at> port the port to work on
+ *  <at> te the transaction to set up direction for
+ * Context: !in_interrupt()
+ * 
+ * reverses the link direction according to the action code of the te. 
+ * may sleep. 
+ * Returns -EIO on error (peripheral timeout). 0 on Success
+ */
+static int set_dir(struct parport *port,struct parport_aio_te *te)
+{
+//	struct parport_pc_private *priv = port->physport->private_data;
+	if(te->flags&PARPORT_AIO_FLG_NOSETUP)
+		return 0;
+		
+	
+	if((inb (ECONTROL (port))&(7<<5))!=(ECR_ECP<<5))//to be certain state machine starts
+	{
+		parport_write_control(port,parport_read_control(port)&~(0x0B));
+	}
+	
+	if(te->action==PARPORT_AIO_ACT_ECP_W_D)
+	{
+		DPRINTK (KERN_DEBUG " te->action==PARPORT_AIO_ACT_ECP_W_D\n");
+		if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
+		{//we don't try to drain fifo here.
+			DPRINTK (KERN_DEBUG " ecp_reverse_to_forward (port)\n");
+			if (ecp_reverse_to_forward (port))
+			{
+				DPRINTK (KERN_DEBUG " failed\n");
+				return -EIO;
+			}
+		}
+		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+	}
+	else
+	{
+		DPRINTK (KERN_DEBUG " te->action!=PARPORT_AIO_ACT_ECP_W_D\n");
+		if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE)
+		{
+			unsigned char ectr;
+			DPRINTK (KERN_DEBUG " ecp_forward_to_reverse (port)\n");
+			ectr = inb (ECONTROL (port));
+			if((port->ieee1284.phase == IEEE1284_PH_FWD_IDLE)&&((ectr&(7<<5))==(ECR_ECP<<5)))
+			{//we just wrote in ECP mode. wait some time for fifo to go empty before reversing direction. If it does
not work, give warning but continue.
+				const unsigned long FLUSH_DELAY=4*HZ/100;
+				const unsigned char FIFO_EMPTY=0x01;
+				if(wait_ecr(port,FIFO_EMPTY,FIFO_EMPTY,FLUSH_DELAY))
+					printk(KERN_WARNING "Couldn't flush fifo post-write in %lu jiffies. Continuing anyway.\n",
(unsigned long)FLUSH_DELAY);
+			}
+			parport_wait_peripheral (port,
+							  PARPORT_STATUS_BUSY,
+							  PARPORT_STATUS_BUSY);
+
+			frob_econtrol (port, (7<<5), (ECR_PS2<<5));
+			if (ecp_forward_to_reverse (port))
+			{
+				DPRINTK (KERN_DEBUG " failed\n");
+				return -EIO;
+			}
+		}
+		port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+	}
+	return 0;
+}
+
+/**
+ * parport_aio_done - called from interrupt context on dma block completion.
+ *  <at> port the port to work on
+ *
+ */
+void parport_aio_done(struct parport *port)
+{
+	unsigned long flags;
+	unsigned long dmaflag,count,residue;
+	struct parport_aio_te *te;
+	struct list_head * l;
+	struct parport_pc_private *priv = port->physport->private_data;
+	if(!(inb (ECONTROL (port)) & (1<<2)))
+	{
+		return;
+	}
+	
+	spin_lock_irqsave(&(priv->aio_lock),flags);
+	if(!priv->dma_active)
+	{
+		DPRINTK (KERN_DEBUG " dma_not_active\n");
+		spin_unlock_irqrestore(&(priv->aio_lock),flags);
+		return;
+	}
+
+	outb (ECONTROL (port),0x74);
+
+	if(!del_timer(&priv->aio_action_timeout))//if we are too late
+	{
+		spin_unlock_irqrestore(&(priv->aio_lock),flags);
+		return;
+	}
+	DPRINTK (KERN_DEBUG " parport_aio_done Ok\n");
+	l=(struct list_head *)&(priv->aio_action_list);
+	if(list_empty(l))
+	{
+		DPRINTK (KERN_DEBUG " list empty\n");
+		spin_unlock_irqrestore(&(priv->aio_lock),flags);
+		return;
+	}
+
+	DPRINTK (KERN_DEBUG " first entry\n");
+	te=list_first_entry(l,struct parport_aio_te,aio_action_list);
+	
+	dmaflag = claim_dma_lock();
+
+	DPRINTK (KERN_DEBUG " disable\n");
+	disable_dma(port->dma);
+	residue = get_dma_residue(port->dma);
+	DPRINTK (KERN_DEBUG " residue: %lu\n",residue);
+
+	release_dma_lock(dmaflag);
+	count=priv->dma_blocksize-residue;
+
+	if((priv->size_done+count)<te->size_to_transfer)//another one
+	{
+		DPRINTK (KERN_DEBUG " end dma\n");
+		parport_end_dma(port,te);
+		DPRINTK (KERN_DEBUG " another one\n");
+		parport_start_dma(port,te);
+	}
+	else//next te
+	{
+		DPRINTK (KERN_DEBUG " schedule_work\n");
+		schedule_work(&priv->aio_softirq);
+	}
+	spin_unlock_irqrestore(&(priv->aio_lock),flags);
+}
+
+EXPORT_SYMBOL (parport_aio_done);
+
+/**
+ * parport_aio_soft - task for handling notifications and dma init
+ *  <at> work work item
+ */
+void parport_aio_soft(struct work_struct * work)
+{
+	struct parport_pc_private *priv = container_of(work,struct parport_pc_private,aio_softirq);
+	struct parport *port=priv->port;
+//	unsigned long flags;
+	unsigned long ret;
+	unsigned char ectr;
+	struct parport_aio_te *te;
+	struct list_head * l;
+	mutex_lock(&(priv->aio_mutex));
+	DPRINTK (KERN_DEBUG " aio_soft\n");
+	l=&(priv->aio_action_list);
+	DPRINTK (KERN_DEBUG " next_te\n");
+	te=list_first_entry(l,struct parport_aio_te,aio_action_list);
+	DPRINTK (KERN_DEBUG " list_del\n");
+	list_del(l->next);
+
+	DPRINTK (KERN_DEBUG " end dma\n");
+	parport_end_dma(port,te);
+	DPRINTK (KERN_DEBUG " finish\n");
+	parport_finish_dma(port,te);
+	priv->dma_active=0;
+	
+	if(te->notify)
+	{
+		DPRINTK (KERN_DEBUG " notify\n");
+		mutex_unlock(&(priv->aio_mutex));
+		te->notify(te->res_ptr,te->buf,te->size_done);
+		mutex_lock(&(priv->aio_mutex));
+	}
+	else if(te->res_ptr)
+	{
+		DPRINTK (KERN_DEBUG " te->res_ptr\n");
+		*(te->res_ptr)=te->size_done;
+	}
+	DPRINTK (KERN_DEBUG " kfree\n");
+	kfree(te);
+
+
+	l=&(priv->aio_action_list);
+	if(list_empty(l))
+	{
+		DPRINTK (KERN_DEBUG " list_empty, active=0\n");
+		frob_econtrol (port, (7<<5), (ECR_PS2<<5));
+		priv->dma_active=0;
+	}
+	else if(priv->dma_active==0)//if notify called submit_...
+	{
+		DPRINTK (KERN_DEBUG " next entry\n");
+		//start next
+		do{
+			te=list_first_entry(l,struct parport_aio_te,aio_action_list);
+			DPRINTK (KERN_DEBUG " init_dma\n");
+			if((ret=(set_dir(port,te)||parport_init_dma(port,te))))//assign!
+			{
+				DPRINTK (KERN_DEBUG " error, remove\n");
+				list_del(l->next);
+				if(te->notify)
+				{
+					DPRINTK (KERN_DEBUG " notify\n");
+					mutex_unlock(&(priv->aio_mutex));
+					te->notify(te->res_ptr,te->buf,0);
+					mutex_lock(&(priv->aio_mutex));
+				}
+				else if(te->res_ptr)
+				{
+					DPRINTK (KERN_DEBUG " te->res_ptr\n");
+					*(te->res_ptr)=te->size_done;
+				}
+				DPRINTK (KERN_DEBUG " kfree\n");
+				kfree(te);
+			}
+		}while((priv->dma_active==0)&&(ret!=0)&&(!list_empty(l)));
+
+		if((ret==0)&&(priv->dma_active==0))
+		{
+			DPRINTK (KERN_DEBUG " start_dma\n");
+			priv->dma_active=1;
+			parport_start_dma(port,te);
+		}
+		
+		if(ret)
+		{
+			ectr = inb (ECONTROL (port));
+			if((port->ieee1284.phase == IEEE1284_PH_FWD_IDLE)&&((ectr&(7<<5))==(ECR_ECP<<5)))
+			{//we just wrote in ECP mode. wait some time for fifo to go empty before reversing direction. If it does
not work, give warning but continue.
+				const unsigned long FLUSH_DELAY=4*HZ/100;
+				const unsigned char FIFO_EMPTY=0x01;
+				if(wait_ecr(port,FIFO_EMPTY,FIFO_EMPTY,FLUSH_DELAY))
+					printk(KERN_WARNING "Couldn't flush FIFO in %lu jiffies. Continuing anyway.\n", (unsigned long)FLUSH_DELAY);
+			}
+			frob_econtrol (port, (7<<5), (ECR_PS2<<5));
+		}
+	}
+	mutex_unlock(&(priv->aio_mutex));
+}
+
+/*disable dma
+*returns 1 if not all has been transmitted
+*/
+static int parport_end_dma(struct parport *port,struct parport_aio_te *te)
+{
+	unsigned long dmaflag;
+	unsigned long count,residue;
+	struct parport_pc_private *priv = port->physport->private_data;
+	DPRINTK (KERN_DEBUG " parport_end_dma Ok\n");
+	dmaflag = claim_dma_lock();
+
+	DPRINTK (KERN_DEBUG " disable\n");
+	disable_dma(port->dma);
+	residue = get_dma_residue(port->dma);
+	DPRINTK (KERN_DEBUG " residue: %lu\n",residue);
+
+	release_dma_lock(dmaflag);
+	count=priv->dma_blocksize-residue;
+	DPRINTK (KERN_DEBUG " count: %lu\n",count);
+	priv->dma_aio_addr+=count;//increment address
+	priv->size_done+=count;
+	DPRINTK (KERN_DEBUG " done: %i\n",priv->size_done);
+	if(residue)
+		return 1;
+	return 0;
+}
+
+/*
+dma transfer has timed out.
+*/
+void parport_aio_timeout(unsigned long p)
+{
+	struct list_head * l;
+	unsigned long flags;
+	struct parport *port=(struct parport *)p;
+	struct parport_pc_private *priv = port->physport->private_data;
+
+	outb (ECONTROL (port),0x74);
+
+	DPRINTK (KERN_DEBUG " aio_timeout\n");
+	spin_lock_irqsave(&(priv->aio_lock),flags);
+	if(!priv->dma_active)
+	{
+		DPRINTK (KERN_DEBUG " dma_not_active\n");
+		spin_unlock_irqrestore(&(priv->aio_lock),flags);
+		return;
+	}
+	l=(struct list_head *)&(priv->aio_action_list);
+	if(list_empty(l))
+	{
+		DPRINTK (KERN_DEBUG " list empty\n");
+		spin_unlock_irqrestore(&(priv->aio_lock),flags);
+		return;
+	}
+
+	DPRINTK (KERN_DEBUG " schedule_work\n");
+	schedule_work(&priv->aio_softirq);
+	spin_unlock_irqrestore(&(priv->aio_lock),flags);
+
+}
+
+
+/*finish dma
+*/
+static int parport_finish_dma(struct parport *port,struct parport_aio_te *te)
+{
+	struct device *dev = port->physport->dev;
+	struct parport_pc_private *priv = port->physport->private_data;
+	DPRINTK (KERN_DEBUG " parport_finish_dma Ok\n");
+	if (priv->dma_aio_handle) {
+		if(te->action==PARPORT_AIO_ACT_ECP_W_D)
+		{
+			DPRINTK (KERN_DEBUG " unmap, DMA_TO_DEVICE\n");
+			dma_unmap_single(dev, priv->dma_aio_handle, te->size_to_transfer, DMA_TO_DEVICE);
+		}
+		else
+		{
+			DPRINTK (KERN_DEBUG " unmap, DMA_FROM_DEVICE\n");
+			dma_unmap_single(dev, priv->dma_aio_handle, te->size_to_transfer, DMA_FROM_DEVICE);
+		}
+  }
+	DPRINTK (KERN_DEBUG " add completed request\n");
+	te->size_done=priv->size_done;
+	return 0;
+}
+
+
+/* I/O to memory, no autoinit, increment, demand mode */
+#define DMA_MODE_READ_DM		0x04
+/* memory to I/O, no autoinit, increment, demand mode */
+#define DMA_MODE_WRITE_DM		0x08
+
+/*start a dma transfer
+*/
+static int parport_start_dma(struct parport *port,struct parport_aio_te *te)
+{
+	unsigned long dmaflag;
+	size_t count;
+	struct parport_pc_private *priv = port->physport->private_data;
+	size_t left = te->size_to_transfer-priv-≥size_done;
+	size_t maxlen = 0x10000; /* max 64k per DMA transfer */
+	unsigned long start = (unsigned long) te->buf + priv->size_done;
+	unsigned long end = (unsigned long) te->buf + te->size_to_transfer - 1;
+
+	DPRINTK (KERN_DEBUG " parport_start_dma Ok\n");
+
+	count = left;
+	if ((start ^ end) & ~0xffffUL)
+	{
+		maxlen = 0x10000 - (start & 0xffff);
+		DPRINTK (KERN_DEBUG " buffer crosses 64k boundary, maxlen:%i\n",maxlen);
+	}
+	if (count > maxlen)
+	{
+		DPRINTK (KERN_DEBUG " count > maxlen ... count=maxlen\n");
+		count = maxlen;
+	}
+	priv->dma_blocksize = count;
+
+	dump_parport_state ("Before",port);
+
+	dmaflag = claim_dma_lock();
+	DPRINTK (KERN_DEBUG " disable_dma\n");
+	disable_dma(port->dma);
+	DPRINTK (KERN_DEBUG " clear_dma\n");
+	clear_dma_ff(port->dma);
+	if(te->action==PARPORT_AIO_ACT_ECP_W_D)
+	{
+		DPRINTK (KERN_DEBUG " set_dma_mode (write)\n");
+		set_dma_mode(port->dma, DMA_MODE_WRITE);
+	}
+	else
+	{
+		DPRINTK (KERN_DEBUG " set_dma_mode (read)\n");
+		set_dma_mode(port->dma, DMA_MODE_READ);
+	}
+	DPRINTK (KERN_DEBUG " set_dma_addr: %i, %x\n",port->dma, priv->dma_aio_addr);
+	set_dma_addr(port->dma, priv->dma_aio_addr);
+	DPRINTK (KERN_DEBUG " set_dma_count: %i\n", count);
+	set_dma_count(port->dma, count);
+
+	/* set ECP mode, disable(set) serviceIntr, disable dma, disable(set) err intr*/
+	DPRINTK (KERN_DEBUG " frob_econtrol....\n");
+	frob_econtrol (port, (7<<5)|(1<<3)|(1<<2)|(1<<4),(ECR_ECP<<5)|(1<<2)|(1<<4));
+
+	DPRINTK (KERN_DEBUG " frob_econtrol\n");
+	/* Set DMA mode */
+	frob_econtrol (port, 1<<3, 1<<3);
+
+	/* Clear serviceIntr */
+	frob_econtrol (port, 1<<2, 0);
+
+
+	DPRINTK (KERN_DEBUG " enable\n");
+	enable_dma(port->dma);
+	release_dma_lock(dmaflag);
+
+/*	DPRINTK (KERN_DEBUG " autofd dwn\n");
+	parport_frob_control (port,
+			       PARPORT_CONTROL_AUTOFD,
+			       0);*/
+	
+	dump_parport_state ("After",port);
+	
+	DPRINTK (KERN_DEBUG " init_timer\n");
+	init_timer(&priv->aio_action_timeout);
+	priv->aio_action_timeout.expires=jiffies+(PARPORT_INACTIVITY_O_NONBLOCK*count/10)+10*HZ/100;
+	DPRINTK (KERN_DEBUG " expires:%lu\n",priv->aio_action_timeout.expires);
+	priv->aio_action_timeout.data=(unsigned long)port;
+	priv->aio_action_timeout.function=parport_aio_timeout;
+	add_timer(&priv->aio_action_timeout);
+	return 0;
+}
+
+//dma transfer one time (per te)initialisation
+static int parport_init_dma(struct parport *port,struct parport_aio_te *te)
+{
+	struct parport_pc_private *priv = port->physport->private_data;
+	struct device *dev = port->physport->dev;
+	size_t count;
+	size_t left = te->size_to_transfer;
+	unsigned long end = (unsigned long) te->buf + te->size_to_transfer - 1;
+
+	DPRINTK (KERN_DEBUG " parport_init_dma Ok\n");
+	priv->size_done=0;
+	dump_parport_state (" Before Init",port);
+
+	/* We don't want to be interrupted every ack. */
+	DPRINTK (KERN_DEBUG " parport_pc_disable_irq (port)\n");
+	parport_pc_disable_irq (port);
+	/* set ECP mode, disable(set) serviceIntr, disable dma, disable(set) err intr*/
+	DPRINTK (KERN_DEBUG " frob_econtrol....\n");
+//	frob_econtrol (port, (7<<5)|(1<<3)|(1<<2)|(1<<4),(ECR_PS2<<5)|(1<<2)|(1<<4));
+//	frob_econtrol (port, (7<<5)|(1<<3)|(1<<2)|(1<<4),(ECR_ECP<<5)|(1<<2)|(1<<4));
+	
+	//set 1284 active
+	//do this before
+//	parport_frob_control (port,
+ 	//					PARPORT_CONTROL_SELECT,
+		//	       0);
+
+	count=left;
+	if (end < MAX_DMA_ADDRESS) {
+		if(te->action==PARPORT_AIO_ACT_ECP_W_D)
+		{
+			DPRINTK (KERN_DEBUG " dma_map... DMA_TO_DEVICE\n");
+			priv->dma_aio_addr = priv->dma_aio_handle = dma_map_single(dev, (void *)te->buf,
te->size_to_transfer, DMA_TO_DEVICE);
+		}
+		else
+		{
+			DPRINTK (KERN_DEBUG " dma_map... DMA_FROM_DEVICE\n");
+			priv->dma_aio_addr = priv->dma_aio_handle = dma_map_single(dev, (void *)te->buf,
te->size_to_transfer, DMA_FROM_DEVICE);
+		}
+		if(dma_mapping_error(dev,priv->dma_aio_handle))
+		{
+			DPRINTK (KERN_DEBUG " failed\n");
+			return -EFAULT;
+		}
+  } else {
+		DPRINTK (KERN_DEBUG " error: DMA Buffer not valid\n");
+		return -EFAULT;
+	}
+	DPRINTK (KERN_DEBUG " first_byte:0x%02x\n",te->buf[0]);
+//	schedule_delayed_work(&priv->aio_action_timeout,(PARPORT_INACTIVITY_O_NONBLOCK*te->size_to_transfer/10)+1);
+	return 0;
+}
+
+/** 
+ * parport_submit_transaction - submit a buffer for async read or write
+ *  <at> port the port to write or read
+ *  <at> buf must be a pointer to a buffer suitable for DMA transfer.
+ *  <at> len the length of the buffer
+ *  <at> flags PARPORT_AIO_FLG_NOSETUP won't setup direction or Signals before starting transfer. 
+ * Has to be done manually. May be necessary for unusual setups (host2host). Use with caution.
+ * The lowest 4 bits of DCR must be 0000 or 0100 for the ecp state machine to start. 
+ * With PARPORT_AIO_FLG_NOSETUP this will _not_ be set up on first transfer(PS2 -> ECP) and has to be done before.
+ *  <at> action_code may be PARPORT_AIO_ACT_ECP_W_D or PARPORT_AIO_ACT_ECP_R_D
+ *  <at> complete if not NULL and if notify is NULL this should point to an integer. 
+ * It will be written to -1 by this function, and after the transfer completes 
+ * will hold the number of bytes successfully transferred. can be used for polling
while(complete!=-1)... 
+ * If notify is not NULL complete will _not_ be written to but acts as user data to the notify function.
+ *  <at> notify a notification callback. Is called from a work_queue (process context). A driver may use it to
trigger actions on transfer completion.
+ * The arguments to notify() are the complete pointer, the buffer address and the length of the data
successfully transferred.
+ * multiple transfers may be submitted without waiting for completion of previous ones. they will be
started(and finished) in the order they were submitted in.
+ *
+ * submit_transaction() returns -EINVAL if the action code is invalid, 
+ * -ENOMEM if the transaction could not be allocated, -EIO if there was a problem setting up the initial link direction.
+ * and 0 on successful queueing of the request. Notification will occur in the last case _only_.
+ */
+int parport_submit_transaction (struct parport *port, const void *buf,
+				  size_t len, int flags, int action_code, int * complete,void (*notify)(int *data,void * buf,int len_real))
+{
+	unsigned long iflags;
+	int ret;
+	struct parport_pc_private *priv = port->physport->private_data;
+	struct parport_aio_te * te=NULL;
+	struct list_head * l=NULL;
+	if((action_code<0)||(action_code>=PARPORT_AIO_ACT_BAD))
+		return -EINVAL;
+	//ready
+	te = kmalloc(sizeof(struct parport_aio_te), GFP_KERNEL);
+	if(!te)
+		return -ENOMEM;
+	DPRINTK (KERN_DEBUG " parport_submit_transaction Ok\n");
+	te->buf=(char *)buf;
+	te->size_to_transfer=len;
+	te->size_done=0;
+	te->action=action_code;
+	te->flags=flags;
+	te->res_ptr=complete;
+	te->notify=notify;//	PARPORT_INIT_TE(te)
+	if((!te->notify)&&(te->res_ptr))
+		*(te->res_ptr)=-1;
+
+	mutex_lock(&(priv->aio_mutex));
+	spin_lock_irqsave(&(priv->aio_lock),iflags);
+//	act=priv->dma_active;
+//	spin_unlock_irqrestore(&(priv->aio_lock),iflags);
+
+	//spin_lock_irqsave(&(priv->aio_lock),iflags);
+	//set
+	DPRINTK (KERN_DEBUG " list_add_tail\n");
+	list_add_tail(&te->aio_action_list, &priv->aio_action_list);
+	//go
+	if(priv->dma_active) {
+		DPRINTK (KERN_DEBUG " dma already active\n");
+		spin_unlock_irqrestore(&(priv->aio_lock),iflags);
+		mutex_unlock(&(priv->aio_mutex));
+		return 0;
+	}
+	else 
+	{
+		//ok there is no dma going on so we are the only ones accessing this data... or not?
+		spin_unlock_irqrestore(&(priv->aio_lock),iflags);
+		l=&(priv->aio_action_list);
+		if(list_empty(l))	{
+			DPRINTK (KERN_DEBUG " list empty\n");
+			mutex_unlock(&(priv->aio_mutex));
+			return 0;
+		}
+		DPRINTK (KERN_DEBUG " get first entry\n");
+		te=list_first_entry(l,struct parport_aio_te,aio_action_list);
+		
+		//we need to be able to sleep here (for set_dir())
+		if((ret=(set_dir(port,te)||parport_init_dma(port,te))))//assign!
+		{
+			//remove
+			list_del(l->next);
+			frob_econtrol (port, (7<<5), (ECR_PS2<<5));
+			DPRINTK (KERN_DEBUG " error, remove\n");
+			priv->dma_active=0;
+			DPRINTK (KERN_DEBUG " kfree\n");
+			kfree(te);
+			mutex_unlock(&(priv->aio_mutex));
+			return ret;
+		}
+		spin_lock_irqsave(&(priv->aio_lock),iflags);
+		priv->dma_active=1;
+		DPRINTK (KERN_DEBUG " dma_active=1\n");
+		parport_start_dma(port,te);
+		spin_unlock_irqrestore(&(priv->aio_lock),iflags);
+	}
+
+	mutex_unlock(&(priv->aio_mutex));
+	return 0;
+}
+
+/**
+ * parport_cancel_transaction - will remove the first te with matching buf ptr. will not notify of
cancelled transfers.
+ *  <at> port port to work on
+ *  <at> buf the pointer to look for (they'd better be unique)
+ *
+ * returns 1 if inactive queued transfer was removed
+ * returns 0 if nothing was removed. either it was not found or already started
+ */
+int parport_cancel_transaction (struct parport *port, const void *buf)
+{
+	unsigned long flags;
+	struct parport_pc_private *priv = port->physport->private_data;
+	struct parport_aio_te * te;
+	struct list_head * l;
+	mutex_lock(&(priv->aio_mutex));
+	spin_lock_irqsave(&(priv->aio_lock),flags);
+	list_for_each(l, &(priv->aio_action_list))
+	{
+		te=list_entry(l,struct parport_aio_te,aio_action_list);
+		if(te->buf==buf)
+		{
+			if(l==priv->aio_action_list.next)//already active
+			{
+				spin_unlock_irqrestore(&(priv->aio_lock),flags);
+				mutex_unlock(&(priv->aio_mutex));
+				return 0;
+			}
+			else
+			{
+				//remove
+				list_del(l);
+				kfree(te);
+				spin_unlock_irqrestore(&(priv->aio_lock),flags);
+				mutex_unlock(&(priv->aio_mutex));
+				return 1;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&(priv->aio_lock),flags);
+	mutex_unlock(&(priv->aio_mutex));
+	return 0;
+}
+
+
 #endif /* IEEE 1284 support */
 #endif /* Allowed to use FIFO/DMA */

 <at>  <at>  -1986,6 +2757,14  <at>  <at>  static int parport_dma_probe(struct parp
 	return p->dma;
 }

+irqreturn_t parport_pc_irq_handler(int irq, void *dev_id)
+{
+	struct parport *port = dev_id;
+	parport_aio_done(port);
+	return parport_irq_handler(irq,dev_id);
+}
+
+
 /* --- Initialisation code -------------------------------- */

 static LIST_HEAD(ports_list);
 <at>  <at>  -2046,6 +2825,17  <at>  <at>  struct parport *parport_pc_probe_port(un
 	INIT_LIST_HEAD(&priv->list);
 	priv->port = p;

+	priv->dma_active=\
+	priv->dma_aio_addr=\
+	priv->dma_aio_handle=\
+	priv->dma_blocksize=\
+	priv->size_done=0;
+
+	INIT_LIST_HEAD(&priv->aio_action_list);
+	spin_lock_init(&priv->aio_lock);
+	mutex_init(&priv->aio_mutex);
+	INIT_WORK(&priv->aio_softirq,parport_aio_soft);
+	
 	p->dev = dev;
 	p->base_hi = base_hi;
 	p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT;
 <at>  <at>  -2157,7 +2947,7  <at>  <at>  struct parport *parport_pc_probe_port(un
 		EPP_res = NULL;
 	}
 	if (p->irq != PARPORT_IRQ_NONE) {
-		if (request_irq(p->irq, parport_irq_handler,
+		if (request_irq(p->irq, parport_pc_irq_handler,
 				 irqflags, p->name, p)) {
 			printk(KERN_WARNING "%s: irq %d in use, "
 				"resorting to polled operation\n",
 <at>  <at>  -2187,6 +2977,10  <at>  <at>  struct parport *parport_pc_probe_port(un
 						p->name);
 					free_dma(p->dma);
 					p->dma = PARPORT_DMA_NONE;
+				}	else {
+					printk("async ops available\n");
+					p->ops->submit_transaction=parport_submit_transaction;
+					p->ops->cancel_transaction=parport_cancel_transaction;
 				}
 			}
 		}
diff -uprN prev/drivers/parport/share.c new/drivers/parport/share.c
--- prev/drivers/parport/share.c	2012-10-14 23:41:04.000000000 +0200
+++ new/drivers/parport/share.c	2012-10-16 16:14:36.000000000 +0200
 <at>  <at>  -64,6 +64,12  <at>  <at>  static size_t dead_write (struct parport
 { return 0; }
 static size_t dead_read (struct parport *p, void *b, size_t l, int f)
 { return 0; }
+int dead_submit(struct parport *port, const void *buf,
+				  size_t len, int flags, int action_code, int * complete,void (*notify)(int *data,void * buf,int len_real))
+				  { return -ENODEV;}
+int dead_cancel(struct parport *port, const void *buf)
+				  { return -ENODEV;}
+
 static struct parport_operations dead_ops = {
 	.write_data	= dead_write_lines,	/* data */
 	.read_data	= dead_read_lines,
 <at>  <at>  -93,6 +99,9  <at>  <at>  static struct parport_operations dead_op
 	.ecp_read_data	= dead_read,
 	.ecp_write_addr	= dead_write,

+ 	.submit_transaction=dead_submit,/* async */
+ 	.cancel_transaction=dead_cancel,
+
 	.compat_write_data	= dead_write,	/* compat */
 	.nibble_read_data	= dead_read,	/* nibble */
 	.byte_read_data		= dead_read,	/* byte */
diff -uprN prev/include/linux/parport.h new/include/linux/parport.h
--- prev/include/linux/parport.h	2012-10-14 23:41:04.000000000 +0200
+++ new/include/linux/parport.h	2012-10-16 16:22:25.000000000 +0200
 <at>  <at>  -103,6 +103,19  <at>  <at>  struct parport_operations {
 	size_t (*ecp_write_addr) (struct parport *port, const void *buf,
 				  size_t len, int flags);

+/* action values describe what to do */
+#define PARPORT_AIO_ACT_ECP_W_D 0
+#define PARPORT_AIO_ACT_ECP_R_D 1
+#define PARPORT_AIO_ACT_BAD 2
+	
+/* flags */
+#define PARPORT_AIO_FLG_NOSETUP (1<<4)
+
+	int (*submit_transaction) (struct parport *port, const void *buf,
+				  size_t len, int flags, int action_code, int * complete,void (*notify)(int *data,void * buf,int len_real));
+				  
+	int (*cancel_transaction) (struct parport *port, const void *buf);
+	
 	size_t (*compat_write_data) (struct parport *port, const void *buf,
 				     size_t len, int flags);
 	size_t (*nibble_read_data) (struct parport *port, void *buf,
diff -uprN prev/include/linux/parport_pc.h new/include/linux/parport_pc.h
--- prev/include/linux/parport_pc.h	2012-10-14 23:41:04.000000000 +0200
+++ new/include/linux/parport_pc.h	2012-10-16 15:14:05.000000000 +0200
 <at>  <at>  -2,6 +2,7  <at>  <at> 
 #define __LINUX_PARPORT_PC_H

 #include <asm/io.h>
+#include <linux/interrupt.h>

 /* --- register definitions ------------------------------- */

 <at>  <at>  -14,6 +15,24  <at>  <at> 
 #define CONTROL(p)  ((p)->base    + 0x2)
 #define STATUS(p)   ((p)->base    + 0x1)
 #define DATA(p)     ((p)->base    + 0x0)
+/**parport asynchronous transaction entry- they are organised as a first in first out queue
+ */
+struct parport_aio_te{
+	/* links us to the list */
+	struct list_head aio_action_list;
+	/* the buffer pointer */
+	char * buf;
+	/* how much is left, how much is done. We memorize the latter to return in the notification */
+	size_t size_to_transfer,size_done;
+	/* what to do see parport.h*/
+	int action;
+	/* flags, ignored */
+	int flags;
+	/* user data or notification var, may be NULL */
+	int * res_ptr;
+	/* notification callback, may be NULL */
+	void (*notify)(int *data,void * buf,int len_real);
+};

 struct parport_pc_private {
 	/* Contents of CTR. */
 <at>  <at>  -40,6 +59,26  <at>  <at>  struct parport_pc_private {
 	dma_addr_t dma_handle;
 	struct list_head list;
 	struct parport *port;
+
+	/* whether dma is currently going on */
+	int dma_active;
+	/* size of current block */
+	int dma_blocksize;
+	/* dma_address(variable) and handle */
+	dma_addr_t dma_aio_addr, dma_aio_handle;
+	/* accumulated size for current transfer*/
+	size_t size_done;
+	
+	/* work_struct to notify, start next transfer etc */
+	struct work_struct aio_softirq;
+	/* timeout if something goes wrong */
+	struct timer_list aio_action_timeout;
+	/* list(queue) of all (pending and active) transaction states for this port */
+	struct list_head aio_action_list;
+	/* protects accesses to this structure (especially dma_active) */
+	spinlock_t aio_lock;
+	/* protects against concurrent accesses between work_structs */
+	struct mutex aio_mutex;
 };

 struct parport_pc_via_data
_______________________________________________
Linux-parport mailing list
Linux-parport <at> lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-parport
Andre Puschmann | 25 Jun 2012 10:08
Picon
Picon
Favicon
Gravatar

IRQ storm from Express card parallel port

Hi,

I've been looking at using a Express card to parallel port adapter to
connect an external device to a PC without on-board parallel port. I got
an adapter from Delock [1] which seems to work fine at first glance.
Unfortunately, the IRQ handling seems to have problems. Whenever I
trigger the first IRQ (I've just shortened pin 10 and ground), I receive
an infinite number of IRQ from the parallel port which only stop after
unloading the kernel modules. The testing code [2] works fine on another
machine with on-board parallel port. I am using the standard Ubuntu
12.04 LTS kernel (3.2.0-25). I am wondering whether anybody else has
observed such a strange behaviour before? It might be also related to
Guan Xin's post "[BUG] IRQ storm from linux/drivers/char/ppdev.c".

Thanks
Andre

[1] http://www.delock.de/produkte/F_263_Parallel_66220/merkmale.html
[2] https://github.com/andrepuschmann/lptirq
John Heim | 26 Feb 2012 00:40

calling request_resource

I’m sorry this is a little off topic but I’m pretty desperate. I need to find out where I can get help fixing a bug in a kernel module for a serial device. The bug is in the driver for a speech synthesizer. I’ve already emailed the original developer and he is not interested in continuing to work on the driver.  I’m blind and I need my hardware speech synthesizer to work.
 
I’ve traced the bug to code that calls the function request_resource. The code for the request_region function says its copyright Linus Torvalds so I’m guessing its part of the linux core functions. Below is a code snippet that is like the code that is failing. An error code of –16 is always returned.  According to the comments in the driver module, this code is supposed to “steal” the serial port.   But it gets the -16 error code and errors out. 
 
int error;
struct resource myres;
myres.name = "ltlk";
myres.start = 0x3F8;
    myres.end = 0x3FF;
    myres.flags = IORESOURCE_BUSY;
    error = request_resource (&ioport_resource, &myres);
 
The actual code is in drivers/staging/speakup/synth.c. Its not exactly like the code snippet above but it does exactly the same thing. I pasted this code into the module, recompiled the kernel, and it has all the same values and has the same result. So if anyone could tell me what’s wrong with the above code, I could probably fix the real code.But if you want to look at the real code its in the kernel code in drivers/staging/speakup/synth.c.
 
The code in the driver module has not changed. They must have changed something elsewhere in the kernel code that broke this module. I don’t know exactly when it started happening but it was sometime after 2.6.32 and before 2.6.37.  The problem applies only to 64 bit hardware but it doesn’t matter if the kernel is compiled for 686 or amd64. So, for example, I can get speech with the 32-bit version of the  grml live CD on a 32 bit machine but not on a 64 bit machine. And I can’t get speech at all with the 64 bit grml CD. Same is true for stock debian kernels and kernels I compile myself.  But a 2.6.32-amd64 stock debian kernel does work.
 
 
 
_______________________________________________
Linux-parport mailing list
Linux-parport <at> lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-parport
Martin Mokrejs | 9 Feb 2012 14:08
Picon

Documentation/parport.txt imprements

Hi,
  I am trying to get my HP OfficeJet R45 printer+scanner working under
Linux via Express Card 34mm from Axago based on MosChip 9901/9912.
Hmm, well lspci says NetMos while it looks it is MosChip instead (compare
with drivers at http://vbs.ddns.com.br:8000/drives/Drives/DRIVER LPT1/ ).

11:00.0 Serial controller: NetMos Technology Device 9912
11:00.1 Serial controller: NetMos Technology Device 9912
11:00.2 Parallel controller: NetMos Technology Device 9912

11:00.0 Serial controller: NetMos Technology Device 9912 (prog-if 02 [16550])
        Subsystem: Device a000:1000
        Physical Slot: 7
        Flags: fast devsel, IRQ 19
        I/O ports at c000 [size=8]
        Memory at f6c00000 (32-bit, non-prefetchable) [size=4K]
        Memory at f6c01000 (32-bit, non-prefetchable) [size=4K]
        Capabilities: [50] MSI: Enable- Count=1/8 Maskable- 64bit+
        Capabilities: [78] Power Management version 3
        Capabilities: [80] Express Legacy Endpoint, MSI 00
        Capabilities: [100] Virtual Channel
        Capabilities: [800] Advanced Error Reporting
        Kernel driver in use: serial

11:00.1 Serial controller: NetMos Technology Device 9912 (prog-if 02 [16550])
        Subsystem: Device a000:1000
        Physical Slot: 7
        Flags: fast devsel, IRQ 16
        I/O ports at c008 [size=8]
        Memory at f6c02000 (32-bit, non-prefetchable) [size=4K]
        Memory at f6c03000 (32-bit, non-prefetchable) [size=4K]
        Capabilities: [50] MSI: Enable- Count=1/8 Maskable- 64bit+
        Capabilities: [78] Power Management version 3
        Capabilities: [80] Express Legacy Endpoint, MSI 00
        Capabilities: [100] Advanced Error Reporting
        Kernel driver in use: serial

11:00.2 Parallel controller: NetMos Technology Device 9912 (prog-if 03 [IEEE1284])
        Subsystem: Device a000:2000
        Physical Slot: 7
        Flags: fast devsel, IRQ 17
        I/O ports at c010 [size=8]
        I/O ports at c018 [size=8]
        Memory at f6c04000 (32-bit, non-prefetchable) [size=4K]
        Memory at f6c05000 (32-bit, non-prefetchable) [size=4K]
        Capabilities: [50] MSI: Enable- Count=1/1 Maskable- 64bit+
        Capabilities: [78] Power Management version 3
        Capabilities: [80] Express Legacy Endpoint, MSI 00
        Capabilities: [100] Advanced Error Reporting
        Kernel driver in use: parport_serial
        Kernel modules: parport_serial

The printer works but scanning worked just once in ECP mode. I couldn't
get the card to be showing EPP mode. In the ends, I found the patch at
http://lists.infradead.org/pipermail/linux-parport/2010-April/000688.html
and can confirm this enabled me to get EPP detected (the patch applies to
linux-3.2.2 with some large offset of the latter diff region, is just a
one-line change so can be done manually).

  So, after reading the MAINTAINERS file I see parport support is "orphaned",
great. :(

  I need some clarifications. ;)

1. Documentation/parport.txt seems to refer to kernel 2.2 or 2.4 syntax and
module names and I am just lost what option arguments are existing in 2.6
kernel (ooops, 3.2 already). For example, I think some arguments are valid
now for parport and parport_pc module but what is valid for parport_serial
I do not know. Would you please give me a couple of examples?

insmod complains on me that the argument is unsupported too often.

2. I happened to try xsane under the following situations but it could never
communicate to the scanner:

Feb  7 20:37:41 vostro kernel: parport_serial 0000:11:00.2: PCI INT C -> GSI 17 (level, low) -> IRQ 17
Feb  7 20:37:41 vostro kernel: parport1: PC-style at 0xc010 (0xc018), irq 17 [PCSPP,TRISTATE]
Feb  7 20:37:41 vostro kernel: parport1: Printer, HEWLETT-PACKARD OFFICEJET R45
Feb  7 20:37:41 vostro kernel: lp1: using parport1 (interrupt-driven).
Feb  7 20:42:06 vostro xsane: hpaio: hpaioScannerToSaneError: sclError=1. 
Feb  7 20:43:39 vostro xsane: failed to open scan channel: scan/sane/hpaio.c 659 
Feb  7 20:43:39 vostro xsane: sane_hpaio_cancel: already cancelled! 
Feb  7 20:45:22 vostro kernel: ppdev: user-space parallel port driver
Feb  7 20:45:45 vostro kernel: parport0: PC-style at 0xc010 (0xc018), irq 17 [PCSPP,TRISTATE]
Feb  7 20:45:45 vostro kernel: parport0: Printer, HEWLETT-PACKARD OFFICEJET R45
Feb  7 20:46:16 vostro hp-toolbox: hp-toolbox(UI)[5591]: warning: Supplies information not available
for this device.
Feb  7 20:50:11 vostro kernel: ppdev: user-space parallel port driver
Feb  7 20:50:31 vostro kernel: parport0: PC-style at 0xc010 (0xc018), irq 17, using FIFO [PCSPP,TRISTATE,COMPAT,ECP]
Feb  7 20:50:31 vostro kernel: parport0: Printer, HEWLETT-PACKARD OFFICEJET R45
Feb  7 20:51:07 vostro xsane: hpaio: hpaioScannerToSaneError: sclError=1. 
Feb  7 20:52:43 vostro kernel: ppdev: user-space parallel port driver
Feb  7 20:52:59 vostro hp-toolbox: hp-toolbox(UI)[10483]: warning: Supplies information not available
for this device.
Feb  7 20:53:01 vostro hp-toolbox: hp-toolbox(UI)[10483]: warning: Supplies information not available
for this device.
Feb  7 20:53:41 vostro kernel: parport0: PC-style at 0xc010, irq 17 [PCSPP,TRISTATE,EPP]
Feb  7 20:53:42 vostro kernel: parport0: Printer, HEWLETT-PACKARD OFFICEJET R45
Feb  7 20:54:22 vostro xsane: hpaio: hpaioScannerToSaneError: sclError=1. 
Feb  7 21:05:24 vostro kernel: ppdev: user-space parallel port driver
Feb  7 21:05:41 vostro kernel: parport0: PC-style at 0xc010, irq 17 [PCSPP,TRISTATE,EPP]
Feb  7 21:05:41 vostro kernel: parport0: Printer, HEWLETT-PACKARD OFFICEJET R45
Feb  7 21:07:36 vostro xsane: failed to open scan channel: scan/sane/hpaio.c 659 
Feb  7 21:19:39 vostro kernel: parport_pc: dma specified without base address.  Use 'io=' to specify one
Feb  7 21:19:39 vostro kernel: ppdev: user-space parallel port driver
Feb  7 21:22:06 vostro kernel: parport0: PC-style at 0xc010, irq 17 [PCSPP,TRISTATE,EPP]
Feb  7 21:22:06 vostro kernel: parport0: Printer, HEWLETT-PACKARD OFFICEJET R45
Feb  7 21:23:55 vostro xsane: invalid SclInquire(cmd=2a86,param=18) exp(len=6)/act(len=0):
scan/sane/scl.c 258 
Feb  7 21:23:55 vostro xsane: exp: 
Feb  7 21:23:55 vostro xsane: act: 

Yesterday once it used ECP but still, no scanning:

Feb  6 15:20:45 vostro kernel: pciehp 0000:00:1c.7:pcie04: Card present on Slot(7)
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.0: BAR 1: assigned [mem 0xf6c00000-0xf6c00fff]
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.0: BAR 1: set to [mem 0xf6c00000-0xf6c00fff] (PCI address [0xf6c00000-0xf6c00fff])
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.0: BAR 5: assigned [mem 0xf6c01000-0xf6c01fff]
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.0: BAR 5: set to [mem 0xf6c01000-0xf6c01fff] (PCI address [0xf6c01000-0xf6c01fff])
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.1: BAR 1: assigned [mem 0xf6c02000-0xf6c02fff]
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.1: BAR 1: set to [mem 0xf6c02000-0xf6c02fff] (PCI address [0xf6c02000-0xf6c02fff])
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.1: BAR 5: assigned [mem 0xf6c03000-0xf6c03fff]
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.1: BAR 5: set to [mem 0xf6c03000-0xf6c03fff] (PCI address [0xf6c03000-0xf6c03fff])
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.2: BAR 2: assigned [mem 0xf6c04000-0xf6c04fff]
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.2: BAR 2: set to [mem 0xf6c04000-0xf6c04fff] (PCI address [0xf6c04000-0xf6c04fff])
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.2: BAR 5: assigned [mem 0xf6c05000-0xf6c05fff]
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.2: BAR 5: set to [mem 0xf6c05000-0xf6c05fff] (PCI address [0xf6c05000-0xf6c05fff])
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.0: BAR 0: assigned [io  0xc000-0xc007]
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.0: BAR 0: set to [io  0xc000-0xc007] (PCI address [0xc000-0xc007])
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.1: BAR 0: assigned [io  0xc008-0xc00f]
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.1: BAR 0: set to [io  0xc008-0xc00f] (PCI address [0xc008-0xc00f])
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.2: BAR 0: assigned [io  0xc010-0xc017]
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.2: BAR 0: set to [io  0xc010-0xc017] (PCI address [0xc010-0xc017])
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.2: BAR 1: assigned [io  0xc018-0xc01f]
Feb  6 15:20:46 vostro kernel: pci 0000:11:00.2: BAR 1: set to [io  0xc018-0xc01f] (PCI address [0xc018-0xc01f])
Feb  6 15:20:46 vostro kernel: pcieport 0000:00:1c.7: PCI bridge to [bus 11-16]
Feb  6 15:20:46 vostro kernel: pcieport 0000:00:1c.7:   bridge window [io  0xc000-0xdfff]
Feb  6 15:20:46 vostro kernel: pcieport 0000:00:1c.7:   bridge window [mem 0xf6c00000-0xf7cfffff]
Feb  6 15:20:46 vostro kernel: pcieport 0000:00:1c.7:   bridge window [mem 0xf0000000-0xf10fffff 64bit pref]
Feb  6 15:20:46 vostro kernel: serial 0000:11:00.0: enabling device (0100 -> 0103)
Feb  6 15:20:46 vostro kernel: serial 0000:11:00.0: PCI INT A -> GSI 19 (level, low) -> IRQ 19
Feb  6 15:20:46 vostro kernel: 0000:11:00.0: ttyS0 at I/O 0xc000 (irq = 19) is a ST16650V2
Feb  6 15:20:47 vostro kernel: serial 0000:11:00.1: enabling device (0100 -> 0103)
Feb  6 15:20:47 vostro kernel: serial 0000:11:00.1: PCI INT B -> GSI 16 (level, low) -> IRQ 16
Feb  6 15:20:47 vostro kernel: 0000:11:00.1: ttyS1 at I/O 0xc008 (irq = 16) is a ST16650V2
Feb  6 15:20:47 vostro kernel: ppdev: user-space parallel port driver
Feb  6 15:20:47 vostro kernel: parport_serial 0000:11:00.2: enabling device (0100 -> 0103)
Feb  6 15:20:47 vostro kernel: parport_serial 0000:11:00.2: PCI INT C -> GSI 17 (level, low) -> IRQ 17
Feb  6 15:20:47 vostro kernel: parport0: PC-style at 0xc010 (0xc018), irq 17, using FIFO [PCSPP,TRISTATE,COMPAT,ECP]
Feb  6 15:20:47 vostro kernel: parport0: Printer, HEWLETT-PACKARD OFFICEJET R45
Feb  6 15:21:00 vostro hp-toolbox: hp-toolbox[3797]: warning: Fax disabled.
Feb  6 15:21:00 vostro hp-toolbox: hp-toolbox[3797]: warning: Fax disabled.
Feb  6 15:21:00 vostro hp-toolbox: hp-toolbox[3797]: warning: Please install version 2.0+ of Reportlab
for coverpage support.
Feb  6 15:24:19 vostro hp-scan: hp-scan[3836]: warning: No destinations specified. Adding 'file'
destination by default.
Feb  6 15:24:30 vostro hp-scan: failed to open scan channel: scan/sane/hpaio.c 659 
Feb  6 15:26:53 vostro hp-scan: hp-scan[3994]: warning: No destinations specified. Adding 'file'
destination by default.
Feb  6 15:27:03 vostro hp-scan: failed to open scan channel: scan/sane/hpaio.c 659 
Feb  6 15:28:36 vostro xsane: failed to open scan channel: scan/sane/hpaio.c 659 
Feb  6 15:30:21 vostro xsane: failed to open scan channel: scan/sane/hpaio.c 659 
Feb  6 15:35:34 vostro kernel: lp0: using parport0 (interrupt-driven).
Feb  6 15:38:20 vostro hp-scan: hp-scan[25326]: warning: No destinations specified. Adding 'file'
destination by default.
Feb  6 15:38:22 vostro hp-scan: hpaio: hpaioScannerToSaneError: sclError=1. 
Feb  6 15:51:01 vostro hp-scan: hp-scan[5610]: warning: No destinations specified. Adding 'file'
destination by default.
Feb  6 15:52:00 vostro kernel: <30>udevd[13659]: starting version 171
Feb  6 15:52:32 vostro hp-scan: failed to open scan channel: scan/sane/hpaio.c 659 
Feb  6 15:55:52 vostro hp-check: hp-check[5400]: warning: Printer is not HPLIP installed. Printers must
use the hp: or hpfax: CUP
S backend to function in HPLIP.
Feb  6 15:58:33 vostro kernel: lp0: ECP mode
Feb  6 16:02:02 vostro hp-scan: hp-scan[16385]: warning: No destinations specified. Adding 'file'
destination by default.
Feb  6 16:03:34 vostro hp-scan: failed to open scan channel: scan/sane/hpaio.c 659 
Feb  6 16:04:18 vostro xsane: hpaio: hpaioScannerToSaneError: sclError=1. 
Feb  6 16:05:35 vostro hp-toolbox: hp-toolbox(UI)[8696]: warning: Supplies information not available
for this device.
Feb  6 16:06:37 vostro xsane: invalid SclInquire(cmd=2a86,param=18) exp(len=6)/act(len=0):
scan/sane/scl.c 258 
Feb  6 16:06:37 vostro xsane: exp: 
Feb  6 16:06:37 vostro xsane: act: 

Once I even saw (note the "Feb  5 13:47:59 vostro kernel: , using FIFO [PCSPP,TRISTATE,COMPAT,ECP]"):

Feb  5 13:47:58 vostro kernel: pciehp 0000:00:1c.7:pcie04: Card present on Slot(7)
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.0: BAR 1: assigned [mem 0xf6c00000-0xf6c00fff]
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.0: BAR 1: set to [mem 0xf6c00000-0xf6c00fff] (PCI address [0xf6c00000-0xf6c00fff])
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.0: BAR 5: assigned [mem 0xf6c01000-0xf6c01fff]
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.0: BAR 5: set to [mem 0xf6c01000-0xf6c01fff] (PCI address [0xf6c01000-0xf6c01fff])
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.1: BAR 1: assigned [mem 0xf6c02000-0xf6c02fff]
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.1: BAR 1: set to [mem 0xf6c02000-0xf6c02fff] (PCI address [0xf6c02000-0xf6c02fff])
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.1: BAR 5: assigned [mem 0xf6c03000-0xf6c03fff]
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.1: BAR 5: set to [mem 0xf6c03000-0xf6c03fff] (PCI address [0xf6c03000-0xf6c03fff])
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.2: BAR 2: assigned [mem 0xf6c04000-0xf6c04fff]
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.2: BAR 2: set to [mem 0xf6c04000-0xf6c04fff] (PCI address [0xf6c04000-0xf6c04fff])
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.2: BAR 5: assigned [mem 0xf6c05000-0xf6c05fff]
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.2: BAR 5: set to [mem 0xf6c05000-0xf6c05fff] (PCI address [0xf6c05000-0xf6c05fff])
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.0: BAR 0: assigned [io  0xc000-0xc007]
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.0: BAR 0: set to [io  0xc000-0xc007] (PCI address [0xc000-0xc007])
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.1: BAR 0: assigned [io  0xc008-0xc00f]
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.1: BAR 0: set to [io  0xc008-0xc00f] (PCI address [0xc008-0xc00f])
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.2: BAR 0: assigned [io  0xc010-0xc017]
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.2: BAR 0: set to [io  0xc010-0xc017] (PCI address [0xc010-0xc017])
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.2: BAR 1: assigned [io  0xc018-0xc01f]
Feb  5 13:47:59 vostro kernel: pci 0000:11:00.2: BAR 1: set to [io  0xc018-0xc01f] (PCI address [0xc018-0xc01f])
Feb  5 13:47:59 vostro kernel: pcieport 0000:00:1c.7: PCI bridge to [bus 11-16]
Feb  5 13:47:59 vostro kernel: pcieport 0000:00:1c.7:   bridge window [io  0xc000-0xdfff]
Feb  5 13:47:59 vostro kernel: pcieport 0000:00:1c.7:   bridge window [mem 0xf6c00000-0xf7cfffff]
Feb  5 13:47:59 vostro kernel: pcieport 0000:00:1c.7:   bridge window [mem 0xf0000000-0xf10fffff 64bit pref]
Feb  5 13:47:59 vostro kernel: serial 0000:11:00.0: enabling device (0100 -> 0103)
Feb  5 13:47:59 vostro kernel: serial 0000:11:00.0: PCI INT A -> GSI 19 (level, low) -> IRQ 19
Feb  5 13:47:59 vostro kernel: 0000:11:00.0: ttyS0 at I/O 0xc000 (irq = 19) is a ST16650V2
Feb  5 13:47:59 vostro kernel: serial 0000:11:00.1: enabling device (0100 -> 0103)
Feb  5 13:47:59 vostro kernel: serial 0000:11:00.1: PCI INT B -> GSI 16 (level, low) -> IRQ 16
Feb  5 13:47:59 vostro kernel: 0000:11:00.1: ttyS1 at I/O 0xc008 (irq = 16) is a ST16650V2
Feb  5 13:47:59 vostro kernel: parport_serial 0000:11:00.2: enabling device (0100 -> 0103)
Feb  5 13:47:59 vostro kernel: parport_serial 0000:11:00.2: PCI INT C -> GSI 17 (level, low) -> IRQ 17
Feb  5 13:47:59 vostro kernel: parport0: PC-style at 0xc010 (0xc018), irq 17
Feb  5 13:47:59 vostro kernel: ppdev: user-space parallel port driver
Feb  5 13:47:59 vostro kernel: , using FIFO [PCSPP,TRISTATE,COMPAT,ECP]
Feb  5 13:47:59 vostro kernel: parport0: Printer, HEWLETT-PACKARD OFFICEJET R45
Feb  5 13:48:26 vostro kernel: lp0: using parport0 (interrupt-driven).

3. It seems the file Documentation/parport.txt could document ECPSPP mode, if
I got it right from drivers/parport/parport_pc.c? Or is only for the VIA chipset
(look for ecpspp)?

4. Documentation/parport.txt says:

<quote>
o polling
o interrupt-driven, protocol in software
o interrupt-driven, protocol in hardware using PIO
o interrupt-driven, protocol in hardware using DMA

The kernel messages that parport_pc logs give an indication of which
code path is being used. (They could be a lot better actually..)

For normal printer protocol, having IEEE 1284 modes enabled or not
should not make a difference.

To turn off the 'protocol in hardware' code paths, disable
CONFIG_PARPORT_PC_FIFO.  Note that when they are enabled they are not
necessarily _used_; it depends on whether the hardware is available,
enabled by the BIOS, and detected by the driver.

So, to start with, disable CONFIG_PARPORT_PC_FIFO, and load parport_pc
with 'irq=none'. See if printing works then.  It really should,
because this is the simplest code path.
</quote>

Would somebody tell me how can I enable/disable these features on the
insmod() commandline? Also, correlate the 'protocols' to HPLIP
requirements mentioned below and correlate with syslog lines from my
system shown above (non-FIFO, FIFO, ECP negotiated)? I just do not know
which is ECP software mode, ECP hardware mode, which is the COMPAT and
which is EPP. Just translate the below text into module arguments. ;-)

<quote>
# Sometimes DMA doesn't work well (i.e. avoid the ECP+DMA mode), see
# https://bugzilla.novell.com/show_bug.cgi?id=116655
#
# http://comments.gmane.org/gmane.comp.printing.hplip.user/3004
# alias
# http://www.mail-archive.com/hplip-help <at> lists.sourceforge.net/msg02954.html
#
# For the OfficeJet Pro 1150C, HPLIP will print over the parallel port
# using "compatibility mode". This is the default IEEE 1284 mode. This is
# why printing normally works.
#
# Scanning requires MLC transport support. MLC is a multi-channel
# transport protocol and for parallel ports MLC will only  run over IEEE
# 1284 ECP mode. HPLIP only supports Software ECP mode, the lowest common
# denominator. HPLIP does not use hardware ECP. This means parport DMA and
# interrupts are not used by HPLIP.
#
# Based on your syslog output ppdev/parport is not allowing HPLIP to set
# Software ECP mode and that is why your scan job fails.
#
# Now if your ppdev/parport kernel modules are loaded correctly, I don't
# know why Software ECP mode is not available. This may be a kernel or
# BIOS issue.
#
#http://hplip.sourceforge.net/tech_docs/index.html
</quote>

Thank you very much for your time,
Martin
Dr.Alexander | 9 Dec 2011 10:09

How to get exclusive access to parports?

Hello list,

I'm trying to get access to the parallel port of a machine to do some signalling for data acquisition.

The machine runs with Xubuntu 10.04 and has one parallel port which gets listed as parport0.

Since the whole thing is somewhat time-critical, I'd like to prevent other processes from accessing the
port, and try to achieve this with the following code snippet:

int port = args(1).int_value(); //Passed from outside, usually 0.
int status, capabilities;

//This usually succeeds, so non-exclusive is never tried.
status = ieee1284_open( ports.portv [ port ], F1284_EXCL, &capabilities );
if ( status != E1284_OK ) {
	warning ( "Could not open the port in exclusive mode, trying non-exlusive mode" );

	status = ieee1284_open( ports.portv [ port ], 0, &capabilities );
}

//This usually never happens.
if ( status != E1284_OK )
	error ( "Could not open the port in non-exclusive mode!" );

	else if ( !capabilities & CAP1284_RAW )
	error ( "Cannot get raw access for parallel port!" );

//This fails regularly when F1284_EXCL is used.
else {
	status = ieee1284_claim( ports.portv [ port ] );

	octave_stdout << status << std::endl;
	octave_stdout << strerror ( errno ) << std::endl;

	if ( status != E1284_OK )
		error ( "Could not claim port after opening!" );

//Other unrelated stuff snipped.

Opening the port with F1284_EXCL works, but claiming it afterwards fails with a status of -8 and "No such
device or address" as the error string.

Opening the port WITHOUT F1284_EXCL works too, as does claiming it afterwards.

What else could be the reason for such strange behaviour?

Thank you in advance,

	Alex

--

-- 
          Dr. Alexander Klein, Diplom-Mathematiker

Physiologisches Institut       |               TransMIT Zentrum
Raum 543                       |        für Numerische Methoden
Aulweg 129                     |          Heinrich-Buff-Ring 44
35392 Giessen                  |                  35392 Giessen
Christian | 13 Nov 2011 12:55
Picon

Don't catch any/valid IRQ on PCI Parport devices

Hello,
For me there is a long time problem in getting a valid or working IRQ on
PCI LPT Cards for my project.
I have a selfmade so called LPR2DMX - Interface, which is supported from
the DMX4Linux Driver. This driver is no longer developed since Kernel
2.5.x. I made a few chances to get working this Driver as a modul for
Kernel 2.6.38.7 and all works fine for some LPT-ISA Cards. But it don't
works for any PCI-Card I have. It seems there is a problem to get an
IRQ-Line, unfortanetly i get no errors.

What Information do you need to help me by this Problem.

Chris
Dr. Alexander Klein | 10 Aug 2011 14:18
Picon

Using libieee1284 with Ubuntu

Hello,

I'm trying to do some signalling via the parallel port on a Xubuntu  
10.04 machine. I lashed up a small test from the libieee1284 man  
pages, but there are some problems remaining:

1. The program will only run as root, or else ieee1284_open will  
return E1284_INIT right away.

2. Only the lower four bits are available for output. Trying to write  
something larger than 31 to the port results in the warning "use  
ieee1284_data_dir to change data line direction!", but  
ieee1284_data_dir with either 0 or 255 as an argument didn't seem to  
change anything.

What else could I try?

Kind regards,

	Alex
--

-- 
           Dr. Alexander Klein, Diplom-Mathematiker

Physiologisches Institut       |               TransMIT Zentrum
Raum 543                       |        für Numerische Methoden
Aulweg 129                     |          Heinrich-Buff-Ring 44
35392 Giessen                  |                  35392 Giessen
snidely stinkfinger | 2 Aug 2011 04:40
Picon
Favicon

(no subject)

http://historygems.com/googlesearch.php
_______________________________________________
Linux-parport mailing list
Linux-parport <at> lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-parport
snidely stinkfinger | 2 Aug 2011 03:23
Picon
Favicon

(no subject)

http://tampabaylipos.com/googlesearch.php
_______________________________________________
Linux-parport mailing list
Linux-parport <at> lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-parport

Gmane