Subject: i2c device interrupt handlers
To: None <tech-kern@NetBSD.org>
From: Jared D. McNeill <jmcneill@invisible.ca>
List: tech-kern
Date: 02/05/2007 08:40:03
--Apple-Mail-3--897924955
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
charset=US-ASCII;
delsp=yes;
format=flowed
Heyas folks --
NetBSD/xbox requires some magic to happen in an interrupt handler to
prevent the machine from resetting when the eject button is pressed.
Since iic_exec *may* sleep, I've created a separate kthread to
actually run the interrupt handlers and wake it up on an smbus
interrupt.
Something has gone wrong though; in the original non-kthread
implementation I had, I was successfully trapping the interrupt and
responding in time, and I could eject / close the tray (the system
would freeze shortly after, but at least wouldn't reset). Now with
this kthread implementation, the system resets immediately after I
press the eject button.
Is there something obviously wrong with my logic here? Patch is
attached.
Cheers,
Jared
--Apple-Mail-3--897924955
Content-Transfer-Encoding: 7bit
Content-Type: application/octet-stream;
x-unix-mode=0644;
name=i2c-intr.patch
Content-Disposition: attachment;
filename=i2c-intr.patch
Index: i2c.c
===================================================================
RCS file: /cvsroot/src/sys/dev/i2c/i2c.c,v
retrieving revision 1.10
diff -u -r1.10 i2c.c
--- i2c.c 16 Nov 2006 01:32:50 -0000 1.10
+++ i2c.c 5 Feb 2007 13:33:58 -0000
@@ -40,6 +40,10 @@
#include <sys/device.h>
#include <sys/event.h>
#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/kthread.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
#include <dev/i2c/i2cvar.h>
@@ -99,6 +103,47 @@
}
static void
+iic_smbus_intr_thread1(void *aux)
+{
+ i2c_tag_t ic;
+ struct ic_intr_list *il;
+ int rv;
+
+ ic = (i2c_tag_t)aux;
+ ic->ic_running = 1;
+ ic->ic_pending = 0;
+
+ printf("iic_smbus_intr_thread1: started\n");
+ while (ic->ic_running) {
+ if (ic->ic_pending == 0)
+ rv = tsleep(ic, PZERO, "iicintr", hz);
+ if (ic->ic_pending > 0) {
+ LIST_FOREACH(il, &(ic->ic_list), il_next) {
+ (*il->il_intr)(il->il_intrarg);
+ }
+ ic->ic_pending--;
+ }
+ }
+
+ kthread_exit(0);
+}
+
+static void
+iic_smbus_intr_thread(void *aux)
+{
+ i2c_tag_t ic;
+ int rv;
+
+ ic = (i2c_tag_t)aux;
+
+ rv = kthread_create1(iic_smbus_intr_thread1, ic, &ic->ic_intr_thread,
+ "%s", ic->ic_devname);
+ if (rv)
+ printf("%s: unable to create intr thread\n", ic->ic_devname);
+}
+
+
+static void
iic_attach(struct device *parent, struct device *self, void *aux)
{
struct iic_softc *sc = device_private(self);
@@ -109,6 +154,9 @@
sc->sc_tag = iba->iba_tag;
sc->sc_type = iba->iba_type;
+ sc->sc_tag->ic_devname = self->dv_xname;
+
+ kthread_create(iic_smbus_intr_thread, sc->sc_tag);
/*
* Attach all i2c devices described in the kernel
@@ -117,5 +165,45 @@
config_search_ia(iic_search, self, "iic", NULL);
}
+void *
+iic_smbus_intr_establish(i2c_tag_t ic, int (*intr)(void *), void *intrarg)
+{
+ struct ic_intr_list *il;
+
+ il = malloc(sizeof(struct ic_intr_list), M_DEVBUF, M_WAITOK);
+ if (il == NULL)
+ return NULL;
+
+ il->il_intr = intr;
+ il->il_intrarg = intrarg;
+
+ LIST_INSERT_HEAD(&(ic->ic_list), il, il_next);
+
+ return il;
+}
+
+void
+iic_smbus_intr_disestablish(i2c_tag_t ic, void *hdl)
+{
+ struct ic_intr_list *il;
+
+ il = (struct ic_intr_list *)hdl;
+
+ LIST_REMOVE(il, il_next);
+ free(il, M_DEVBUF);
+
+ return;
+}
+
+int
+iic_smbus_intr(i2c_tag_t ic)
+{
+
+ ic->ic_pending++;
+ wakeup(ic);
+
+ return 1;
+}
+
CFATTACH_DECL(iic, sizeof(struct iic_softc),
iic_match, iic_attach, NULL, NULL);
Index: i2cvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/i2c/i2cvar.h,v
retrieving revision 1.4
diff -u -r1.4 i2cvar.h
--- i2cvar.h 26 Jun 2006 18:19:40 -0000 1.4
+++ i2cvar.h 5 Feb 2007 13:33:58 -0000
@@ -48,6 +48,12 @@
#define I2C_F_POLL 0x08 /* poll, don't sleep */
#define I2C_F_PEC 0x10 /* smbus packet error checking */
+struct ic_intr_list {
+ LIST_ENTRY(ic_intr_list) il_next;
+ int (*il_intr)(void *);
+ void *il_intrarg;
+};
+
/*
* This structure provides the interface between the i2c framework
* and the underlying i2c controller.
@@ -88,6 +94,12 @@
int (*ic_initiate_xfer)(void *, i2c_addr_t, int);
int (*ic_read_byte)(void *, uint8_t *, int);
int (*ic_write_byte)(void *, uint8_t, int);
+
+ LIST_HEAD(, ic_intr_list) ic_list;
+ int ic_running;
+ int ic_pending;
+ struct proc *ic_intr_thread;
+ const char *ic_devname;
} *i2c_tag_t;
/* I2C bus types */
@@ -154,4 +166,8 @@
int iic_smbus_block_write(i2c_tag_t, i2c_addr_t, uint8_t, uint8_t *,
size_t, int);
+void * iic_smbus_intr_establish(i2c_tag_t, int (*)(void *), void *);
+void iic_smbus_intr_disestablish(i2c_tag_t, void *);
+int iic_smbus_intr(i2c_tag_t);
+
#endif /* _DEV_I2C_I2CVAR_H_ */
--Apple-Mail-3--897924955--