Re: ucb1x00 audio & zaurus touchscreen

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Pavel Machek wrote:
> Hi!
> 
> First, I'd like to ask: what is status of ucb1x00 audio in 2.6? I do
> have .c file here, but do not have corresponding header files...
> 
> Then, I'd like to announce that I finally got touchscreen to somehow
> work. Patch is very ugly and adds filtering into kernel (no-no), but
> does the trick, and can even coexist with battery reading code. [Don't
> bother commenting on style of this patch, it is for ilustration, I'd
> not be crazy enough to try to push it.]

This is what I have lurking in an equally hacky state.
%description
This is a really nasty hack which I used simply to verify that
the touchscreen hardware on the GX533 worked correctly. It came
from a bit-rotted patch found on the L-K mailing list and war forcefully
forward ported to the current tree. It needs some serious cleaning up
before it gets used...

It hangs when you close the input device because semaphores and kthread_stop
cannot play nice together.
%patch
Index: linux-2.6-working/drivers/mfd/Kconfig
===================================================================
--- linux-2.6-working.orig/drivers/mfd/Kconfig	2006-03-01 13:39:20.000000000 +0000
+++ linux-2.6-working/drivers/mfd/Kconfig	2006-03-01 13:39:20.000000000 +0000
@@ -26,4 +26,7 @@
 	tristate "Touchscreen interface support"
 	depends on MCP_UCB1200 && INPUT
 
+config UCB1400_TS
+	tristate "UCB1400 Touchscreen support"
+
 endmenu
Index: linux-2.6-working/drivers/mfd/Makefile
===================================================================
--- linux-2.6-working.orig/drivers/mfd/Makefile	2006-03-01 13:39:20.000000000 +0000
+++ linux-2.6-working/drivers/mfd/Makefile	2006-03-01 13:39:20.000000000 +0000
@@ -11,3 +11,6 @@
 ifeq ($(CONFIG_SA1100_ASSABET),y)
 obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-assabet.o
 endif
+
+ucb1400-core-y 			:= ucb1x00-core.o
+obj-$(CONFIG_UCB1400_TS)	+= ucb1400-core.o ucb1x00-ts.o
Index: linux-2.6-working/drivers/mfd/ucb1x00-core.c
===================================================================
--- linux-2.6-working.orig/drivers/mfd/ucb1x00-core.c	2006-03-01 13:37:51.000000000 +0000
+++ linux-2.6-working/drivers/mfd/ucb1x00-core.c	2006-03-06 11:21:33.000000000 +0000
@@ -27,10 +27,17 @@
 #include <linux/mutex.h>
 
 #include <asm/dma.h>
+#ifdef CONFIG_ARCH_ARM
 #include <asm/hardware.h>
+#endif
 
 #include "ucb1x00.h"
 
+/* NO_IRQ is ARM only? probe_irq_off returns 0 if no IRQ found on i386 */
+#ifndef NO_IRQ
+#define NO_IRQ 0
+#endif
+
 static DEFINE_MUTEX(ucb1x00_mutex);
 static LIST_HEAD(ucb1x00_drivers);
 static LIST_HEAD(ucb1x00_devices);
@@ -58,9 +65,9 @@
 	spin_lock_irqsave(&ucb->io_lock, flags);
 	ucb->io_dir |= out;
 	ucb->io_dir &= ~in;
+	spin_unlock_irqrestore(&ucb->io_lock, flags);
 
 	ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
-	spin_unlock_irqrestore(&ucb->io_lock, flags);
 }
 
 /**
@@ -86,9 +93,9 @@
 	spin_lock_irqsave(&ucb->io_lock, flags);
 	ucb->io_out |= set;
 	ucb->io_out &= ~clear;
+	spin_unlock_irqrestore(&ucb->io_lock, flags);
 
 	ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
-	spin_unlock_irqrestore(&ucb->io_lock, flags);
 }
 
 /**
@@ -162,6 +169,7 @@
 unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync)
 {
 	unsigned int val;
+	unsigned int timeout = 50;
 
 	if (sync)
 		adc_channel |= UCB_ADC_SYNC_ENA;
@@ -169,14 +177,12 @@
 	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel);
 	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel | UCB_ADC_START);
 
-	for (;;) {
+	do {
 		val = ucb1x00_reg_read(ucb, UCB_ADC_DATA);
 		if (val & UCB_ADC_DAT_VAL)
 			break;
-		/* yield to other processes */
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(1);
-	}
+		udelay(1);
+	} while (--timeout);
 
 	return UCB_ADC_DAT(val);
 }
@@ -249,13 +255,13 @@
 		irq = ucb->irq_handler + idx;
 		ret = -EBUSY;
 
-		spin_lock_irq(&ucb->lock);
+		down(&ucb->lock);
 		if (irq->fn == NULL) {
 			irq->devid = devid;
 			irq->fn = fn;
 			ret = 0;
 		}
-		spin_unlock_irq(&ucb->lock);
+		up(&ucb->lock);
 	}
 	return ret;
 }
@@ -272,10 +278,8 @@
  */
 void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
 {
-	unsigned long flags;
-
 	if (idx < 16) {
-		spin_lock_irqsave(&ucb->lock, flags);
+		down(&ucb->lock);
 
 		ucb1x00_enable(ucb);
 		if (edges & UCB_RISING) {
@@ -287,7 +291,7 @@
 			ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
 		}
 		ucb1x00_disable(ucb);
-		spin_unlock_irqrestore(&ucb->lock, flags);
+		up(&ucb->lock);
 	}
 }
 
@@ -301,22 +305,23 @@
  */
 void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
 {
-	unsigned long flags;
-
 	if (idx < 16) {
-		spin_lock_irqsave(&ucb->lock, flags);
-
-		ucb1x00_enable(ucb);
-		if (edges & UCB_RISING) {
+		down(&ucb->lock);
+		/* This can't be right. Can it? */
+		if (edges & UCB_RISING)
+			ucb->irq_ris_enbl |= 1 << idx;
+		if (edges & UCB_FALLING)
+			ucb->irq_fal_enbl |= 1 << idx;
+		if (edges & UCB_RISING)
 			ucb->irq_ris_enbl &= ~(1 << idx);
-			ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
-		}
-		if (edges & UCB_FALLING) {
+		if (edges & UCB_FALLING)
 			ucb->irq_fal_enbl &= ~(1 << idx);
-			ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
-		}
+		up(&ucb->lock);
+
+		ucb1x00_enable(ucb);
+		ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
+		ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
 		ucb1x00_disable(ucb);
-		spin_unlock_irqrestore(&ucb->lock, flags);
 	}
 }
 
@@ -344,21 +349,22 @@
 	irq = ucb->irq_handler + idx;
 	ret = -ENOENT;
 
-	spin_lock_irq(&ucb->lock);
+	down(&ucb->lock);
 	if (irq->devid == devid) {
 		ucb->irq_ris_enbl &= ~(1 << idx);
 		ucb->irq_fal_enbl &= ~(1 << idx);
 
-		ucb1x00_enable(ucb);
-		ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
-		ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
-		ucb1x00_disable(ucb);
-
 		irq->fn = NULL;
 		irq->devid = NULL;
 		ret = 0;
 	}
-	spin_unlock_irq(&ucb->lock);
+	up(&ucb->lock);
+
+	ucb1x00_enable(ucb);
+	ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
+	ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
+	ucb1x00_disable(ucb);
+
 	return ret;
 
 bad:
@@ -478,7 +484,8 @@
 	mcp_enable(mcp);
 	id = mcp_reg_read(mcp, UCB_ID);
 
-	if (id != UCB_ID_1200 && id != UCB_ID_1300) {
+	if (id != UCB_ID_1200 && id != UCB_ID_1300 &&
+		id != UCB_ID_1400 && id != UCB_ID_1400_BUGGY) {
 		printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
 		goto err_disable;
 	}
@@ -494,7 +501,7 @@
 	ucb->cdev.dev = &mcp->attached_device;
 	strlcpy(ucb->cdev.class_id, "ucb1x00", sizeof(ucb->cdev.class_id));
 
-	spin_lock_init(&ucb->lock);
+	init_MUTEX(&ucb->lock);
 	spin_lock_init(&ucb->io_lock);
 	sema_init(&ucb->adc_sem, 1);
 
@@ -502,17 +509,15 @@
 	ucb->mcp = mcp;
 	ucb->irq = ucb1x00_detect_irq(ucb);
 	if (ucb->irq == NO_IRQ) {
-		printk(KERN_ERR "UCB1x00: IRQ probe failed\n");
-		ret = -ENODEV;
-		goto err_free;
-	}
-
-	ret = request_irq(ucb->irq, ucb1x00_irq, SA_TRIGGER_RISING,
-			  "UCB1x00", ucb);
-	if (ret) {
-		printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
-			ucb->irq, ret);
-		goto err_free;
+		printk(KERN_WARNING "UCB1x00: IRQ probe failed -- using polled mode\n");
+	} else {
+		ret = request_irq(ucb->irq, ucb1x00_irq, SA_TRIGGER_RISING,
+				  "UCB1x00", ucb);
+		if (ret) {
+			printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
+			       ucb->irq, ret);
+			goto err_free;
+		}
 	}
 
 	mcp_set_drvdata(mcp, ucb);
@@ -531,7 +536,8 @@
 	goto out;
 
  err_irq:
-	free_irq(ucb->irq, ucb);
+	if (ucb->irq != NO_IRQ)
+		free_irq(ucb->irq, ucb);
  err_free:
 	kfree(ucb);
  err_disable:
@@ -553,7 +559,8 @@
 	}
 	mutex_unlock(&ucb1x00_mutex);
 
-	free_irq(ucb->irq, ucb);
+	if (ucb->irq != NO_IRQ)
+		free_irq(ucb->irq, ucb);
 	class_device_unregister(&ucb->cdev);
 }
 
Index: linux-2.6-working/drivers/mfd/ucb1x00-ts.c
===================================================================
--- linux-2.6-working.orig/drivers/mfd/ucb1x00-ts.c	2006-03-01 13:37:51.000000000 +0000
+++ linux-2.6-working/drivers/mfd/ucb1x00-ts.c	2006-03-06 11:21:33.000000000 +0000
@@ -35,18 +35,23 @@
 
 #include <asm/dma.h>
 #include <asm/semaphore.h>
+#ifdef CONFIG_ARM
 #include <asm/arch/collie.h>
 #include <asm/mach-types.h>
+#else
+#define machine_is_collie() 0
+#include <asm-arm/arch-sa1100/collie.h>
+#endif
 
 #include "ucb1x00.h"
 
-
 struct ucb1x00_ts {
 	struct input_dev	*idev;
 	struct ucb1x00		*ucb;
 
-	wait_queue_head_t	irq_wait;
+	struct semaphore	irq_wait;
 	struct task_struct	*rtask;
+
 	u16			x_res;
 	u16			y_res;
 
@@ -77,10 +82,12 @@
  */
 static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts)
 {
-	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
-			UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
-			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
-			UCB_TS_CR_MODE_INT);
+	int val = UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
+		  UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
+		  UCB_TS_CR_MODE_INT;
+	if (ts->ucb->id == UCB_ID_1400_BUGGY)
+		val &= ~(UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW);
+	ucb1x00_reg_write(ts->ucb, UCB_TS_CR, val);
 }
 
 /*
@@ -172,7 +179,7 @@
 	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
 			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
 			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-	return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
+	return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSMX, ts->adcsync);
 }
 
 /*
@@ -184,28 +191,27 @@
 	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
 			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
 			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-	return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
+	return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSMX, ts->adcsync);
 }
 
 static inline int ucb1x00_ts_pen_down(struct ucb1x00_ts *ts)
 {
 	unsigned int val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR);
 	if (machine_is_collie())
-		return (!(val & (UCB_TS_CR_TSPX_LOW)));
+		return val & (UCB_TS_CR_TSPX_LOW);
 	else
-		return (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW));
+		return !(val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW));
 }
 
 /*
  * This is a RT kernel thread that handles the ADC accesses
  * (mainly so we can use semaphores in the UCB1200 core code
- * to serialise accesses to the ADC).
+ * to serialise accesses to the ADC).  The UCB1400 access
+ * functions are expected to be able to sleep as well.
  */
 static int ucb1x00_thread(void *_ts)
 {
 	struct ucb1x00_ts *ts = _ts;
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
 	int valid;
 
 	/*
@@ -217,10 +223,9 @@
 
 	valid = 0;
 
-	add_wait_queue(&ts->irq_wait, &wait);
 	while (!kthread_should_stop()) {
 		unsigned int x, y, p;
-		signed long timeout;
+		int is_pen_down;
 
 		ts->restart = 0;
 
@@ -229,24 +234,31 @@
 		x = ucb1x00_ts_read_xpos(ts);
 		y = ucb1x00_ts_read_ypos(ts);
 		p = ucb1x00_ts_read_pressure(ts);
-
 		/*
-		 * Switch back to interrupt mode.
+		 * Switch back to interrupt/pen detect mode.
 		 */
 		ucb1x00_ts_mode_int(ts);
+
 		ucb1x00_adc_disable(ts->ucb);
 
-		msleep(10);
+		msleep(1);
 
 		ucb1x00_enable(ts->ucb);
+		is_pen_down = ucb1x00_ts_pen_down(ts);
+		ucb1x00_disable(ts->ucb);
+		if (is_pen_down) {
+			/*
+			 * Filtering is policy.  Policy belongs in user
+			 * space.  We therefore leave it to user space
+			 * to do any filtering they please.
+			 */
+			if (!ts->restart) {
+				ucb1x00_ts_evt_add(ts, p, x, y);
+				valid = 1;
+			}
 
-
-		if (ucb1x00_ts_pen_down(ts)) {
-			set_task_state(tsk, TASK_INTERRUPTIBLE);
-
-			ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING);
-			ucb1x00_disable(ts->ucb);
-
+			schedule_timeout_interruptible(1);
+		} else {
 			/*
 			 * If we spat out a valid sample set last time,
 			 * spit out a "pen off" sample here.
@@ -256,31 +268,26 @@
 				valid = 0;
 			}
 
-			timeout = MAX_SCHEDULE_TIMEOUT;
-		} else {
-			ucb1x00_disable(ts->ucb);
-
 			/*
-			 * Filtering is policy.  Policy belongs in user
-			 * space.  We therefore leave it to user space
-			 * to do any filtering they please.
+			 * Since ucb1x00_enable_irq() might sleep due
+			 * to the way the UCB1400 regs are accessed, we
+			 * can't use set_task_state() before that call,
+			 * and not changing state before enabling the
+			 * interrupt is racy.  A semaphore solves all
+			 * those issues quite nicely.
 			 */
-			if (!ts->restart) {
-				ucb1x00_ts_evt_add(ts, p, x, y);
-				valid = 1;
+			if (ts->ucb->irq) {
+				ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX,
+						   machine_is_collie() ? UCB_RISING : UCB_FALLING);
+				down_interruptible(&ts->irq_wait);
+			} else {
+				schedule_timeout_interruptible(msecs_to_jiffies(100));
 			}
-
-			set_task_state(tsk, TASK_INTERRUPTIBLE);
-			timeout = HZ / 100;
 		}
 
 		try_to_freeze();
-
-		schedule_timeout(timeout);
 	}
 
-	remove_wait_queue(&ts->irq_wait, &wait);
-
 	ts->rtask = NULL;
 	return 0;
 }
@@ -293,7 +300,7 @@
 {
 	struct ucb1x00_ts *ts = id;
 	ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
-	wake_up(&ts->irq_wait);
+	up(&ts->irq_wait);
 }
 
 static int ucb1x00_ts_open(struct input_dev *idev)
@@ -303,7 +310,7 @@
 
 	BUG_ON(ts->rtask);
 
-	init_waitqueue_head(&ts->irq_wait);
+	sema_init(&ts->irq_wait, 0);
 	ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
 	if (ret < 0)
 		goto out;
@@ -337,9 +344,11 @@
 {
 	struct ucb1x00_ts *ts = idev->private;
 
+	printk(KERN_DEBUG "ucb1x00_ts_close: stop thread\n");
 	if (ts->rtask)
 		kthread_stop(ts->rtask);
 
+	printk(KERN_DEBUG "ucb1x00_ts_close: free irq and clear CR\n");
 	ucb1x00_enable(ts->ucb);
 	ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
 	ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
@@ -358,7 +367,7 @@
 		 * after sleep.
 		 */
 		ts->restart = 1;
-		wake_up(&ts->irq_wait);
+		up(&ts->irq_wait);
 	}
 	return 0;
 }
Index: linux-2.6-working/drivers/mfd/ucb1x00.h
===================================================================
--- linux-2.6-working.orig/drivers/mfd/ucb1x00.h	2006-01-03 03:21:10.000000000 +0000
+++ linux-2.6-working/drivers/mfd/ucb1x00.h	2006-03-03 16:03:27.000000000 +0000
@@ -10,8 +10,47 @@
 #ifndef UCB1200_H
 #define UCB1200_H
 
+#if 1 // def CONFIG_ARCH_PXA
+
+/* ucb1400 aclink register mappings: */
+
+#define UCB_IO_DATA	0x5a
+#define UCB_IO_DIR	0x5c
+#define UCB_IE_RIS	0x5e
+#define UCB_IE_FAL	0x60
+#define UCB_IE_STATUS	0x62
+#define UCB_IE_CLEAR	0x62
+#define UCB_TS_CR	0x64
+#define UCB_ADC_CR	0x66
+#define UCB_ADC_DATA	0x68
+#define UCB_ID		0x7e /* 7c is mfr id, 7e part id (from aclink spec) */
+
+#define UCB_ADC_DAT(x)		((x) & 0x3ff)
+
+#else
+
+/* ucb1x00 SIB register mappings: */
+
 #define UCB_IO_DATA	0x00
 #define UCB_IO_DIR	0x01
+#define UCB_IE_RIS	0x02
+#define UCB_IE_FAL	0x03
+#define UCB_IE_STATUS	0x04
+#define UCB_IE_CLEAR	0x04
+#define UCB_TC_A	0x05
+#define UCB_TC_B	0x06
+#define UCB_AC_A	0x07
+#define UCB_AC_B	0x08
+#define UCB_TS_CR	0x09
+#define UCB_ADC_CR	0x0a
+#define UCB_ADC_DATA	0x0b
+#define UCB_ID		0x0c
+#define UCB_MODE	0x0d
+
+#define UCB_ADC_DAT(x)		(((x) & 0x7fe0) >> 5)
+
+#endif
+
 
 #define UCB_IO_0		(1 << 0)
 #define UCB_IO_1		(1 << 1)
@@ -24,10 +63,6 @@
 #define UCB_IO_8		(1 << 8)
 #define UCB_IO_9		(1 << 9)
 
-#define UCB_IE_RIS	0x02
-#define UCB_IE_FAL	0x03
-#define UCB_IE_STATUS	0x04
-#define UCB_IE_CLEAR	0x04
 #define UCB_IE_ADC		(1 << 11)
 #define UCB_IE_TSPX		(1 << 12)
 #define UCB_IE_TSMX		(1 << 13)
@@ -36,11 +71,9 @@
 
 #define UCB_IRQ_TSPX		12
 
-#define UCB_TC_A	0x05
 #define UCB_TC_A_LOOP		(1 << 7)	/* UCB1200 */
 #define UCB_TC_A_AMPL		(1 << 7)	/* UCB1300 */
 
-#define UCB_TC_B	0x06
 #define UCB_TC_B_VOICE_ENA	(1 << 3)
 #define UCB_TC_B_CLIP		(1 << 4)
 #define UCB_TC_B_ATT		(1 << 6)
@@ -49,14 +82,11 @@
 #define UCB_TC_B_IN_ENA		(1 << 14)
 #define UCB_TC_B_OUT_ENA	(1 << 15)
 
-#define UCB_AC_A	0x07
-#define UCB_AC_B	0x08
 #define UCB_AC_B_LOOP		(1 << 8)
 #define UCB_AC_B_MUTE		(1 << 13)
 #define UCB_AC_B_IN_ENA		(1 << 14)
 #define UCB_AC_B_OUT_ENA	(1 << 15)
 
-#define UCB_TS_CR	0x09
 #define UCB_TS_CR_TSMX_POW	(1 << 0)
 #define UCB_TS_CR_TSPX_POW	(1 << 1)
 #define UCB_TS_CR_TSMY_POW	(1 << 2)
@@ -72,7 +102,6 @@
 #define UCB_TS_CR_TSPX_LOW	(1 << 12)
 #define UCB_TS_CR_TSMX_LOW	(1 << 13)
 
-#define UCB_ADC_CR	0x0a
 #define UCB_ADC_SYNC_ENA	(1 << 0)
 #define UCB_ADC_VREFBYP_CON	(1 << 1)
 #define UCB_ADC_INP_TSPX	(0 << 2)
@@ -87,15 +116,13 @@
 #define UCB_ADC_START		(1 << 7)
 #define UCB_ADC_ENA		(1 << 15)
 
-#define UCB_ADC_DATA	0x0b
 #define UCB_ADC_DAT_VAL		(1 << 15)
-#define UCB_ADC_DAT(x)		(((x) & 0x7fe0) >> 5)
 
-#define UCB_ID		0x0c
 #define UCB_ID_1200		0x1004
 #define UCB_ID_1300		0x1005
+#define UCB_ID_1400		0x4304
+#define UCB_ID_1400_BUGGY	0x4303	/* fake ID */
 
-#define UCB_MODE	0x0d
 #define UCB_MODE_DYN_VFLAG_ENA	(1 << 12)
 #define UCB_MODE_AUD_OFF_CAN	(1 << 13)
 
@@ -107,11 +134,14 @@
 };
 
 struct ucb1x00 {
-	spinlock_t		lock;
-	struct mcp		*mcp;
+	struct mcp		*mcp;	/* this needs to be first */
+	struct semaphore	lock;
 	unsigned int		irq;
 	struct semaphore	adc_sem;
 	spinlock_t		io_lock;
+	wait_queue_head_t	irq_wait;
+	struct completion	complete;
+	struct task_struct	*irq_task;
 	u16			id;
 	u16			io_dir;
 	u16			io_out;

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux