Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 9 Dec 2009 21:47:42 +0000 (UTC)
From:      Andrew Thompson <thompsa@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r200314 - in stable/8/sys: conf dev/usb/input modules/usb modules/usb/atp
Message-ID:  <200912092147.nB9LlgLX039541@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: thompsa
Date: Wed Dec  9 21:47:42 2009
New Revision: 200314
URL: http://svn.freebsd.org/changeset/base/200314

Log:
  MFC r199086,199151,199680,199948,200241
  
   Driver for the Apple Touchpad present on MacBook (non-Pro & Pro).
  
  Submitted by:	Rohit Grover <rgrover1 at gmail.com>

Added:
  stable/8/sys/dev/usb/input/atp.c
     - copied, changed from r199086, head/sys/dev/usb/input/atp.c
  stable/8/sys/modules/usb/atp/
     - copied from r199086, head/sys/modules/usb/atp/
Modified:
  stable/8/sys/conf/files
  stable/8/sys/modules/usb/Makefile
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)

Modified: stable/8/sys/conf/files
==============================================================================
--- stable/8/sys/conf/files	Wed Dec  9 21:39:43 2009	(r200313)
+++ stable/8/sys/conf/files	Wed Dec  9 21:47:42 2009	(r200314)
@@ -1669,6 +1669,7 @@ dev/usb/misc/udbp.c		optional udbp
 #
 # USB input drivers
 #
+dev/usb/input/atp.c		optional atp
 dev/usb/input/uhid.c		optional uhid
 dev/usb/input/ukbd.c		optional ukbd
 dev/usb/input/ums.c		optional ums

Copied and modified: stable/8/sys/dev/usb/input/atp.c (from r199086, head/sys/dev/usb/input/atp.c)
==============================================================================
--- head/sys/dev/usb/input/atp.c	Mon Nov  9 15:59:09 2009	(r199086, copy source)
+++ stable/8/sys/dev/usb/input/atp.c	Wed Dec  9 21:47:42 2009	(r200314)
@@ -193,21 +193,50 @@ SYSCTL_UINT(_hw_usb_atp, OID_AUTO, pspan
     &atp_pspan_max_width, 4,
     "maximum allowed width (in sensors) for pressure-spans");
 
+/* We support three payload protocols */
+typedef enum {
+	ATP_PROT_GEYSER1,
+	ATP_PROT_GEYSER2,
+	ATP_PROT_GEYSER3,
+} atp_protocol;
 
 /* Define the various flavours of devices supported by this driver. */
 enum {
 	ATP_DEV_PARAMS_0,
+	ATP_DEV_PARAMS_PBOOK,
+	ATP_DEV_PARAMS_PBOOK_15A,
+	ATP_DEV_PARAMS_PBOOK_17,
 	ATP_N_DEV_PARAMS
 };
 struct atp_dev_params {
 	u_int            data_len;   /* for sensor data */
 	u_int            n_xsensors;
 	u_int            n_ysensors;
+	atp_protocol     prot;
 } atp_dev_params[ATP_N_DEV_PARAMS] = {
 	[ATP_DEV_PARAMS_0] = {
 		.data_len   = 64,
 		.n_xsensors = 20,
-		.n_ysensors = 10
+		.n_ysensors = 10,
+		.prot       = ATP_PROT_GEYSER3
+	},
+	[ATP_DEV_PARAMS_PBOOK] = {
+		.data_len   = 81,
+		.n_xsensors = 16,
+		.n_ysensors = 16,
+		.prot       = ATP_PROT_GEYSER1
+	},
+	[ATP_DEV_PARAMS_PBOOK_15A] = {
+		.data_len   = 64,
+		.n_xsensors = 15,
+		.n_ysensors = 9,
+		.prot       = ATP_PROT_GEYSER2
+	},
+	[ATP_DEV_PARAMS_PBOOK_17] = {
+		.data_len   = 81,
+		.n_xsensors = 26,
+		.n_ysensors = 16,
+		.prot       = ATP_PROT_GEYSER1
 	},
 };
 
@@ -226,6 +255,19 @@ static const struct usb_device_id atp_de
 	{ USB_VPI(USB_VENDOR_APPLE, 0x0229, ATP_DEV_PARAMS_0) },
 	{ USB_VPI(USB_VENDOR_APPLE, 0x022a, ATP_DEV_PARAMS_0) },
 	{ USB_VPI(USB_VENDOR_APPLE, 0x022b, ATP_DEV_PARAMS_0) },
+
+	/* 12 inch PowerBook and iBook */
+	{ USB_VPI(USB_VENDOR_APPLE, 0x030a, ATP_DEV_PARAMS_PBOOK) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x030b, ATP_DEV_PARAMS_PBOOK) },
+
+	/* 15 inch PowerBook */
+	{ USB_VPI(USB_VENDOR_APPLE, 0x020e, ATP_DEV_PARAMS_PBOOK) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x020f, ATP_DEV_PARAMS_PBOOK) },
+	{ USB_VPI(USB_VENDOR_APPLE, 0x0215, ATP_DEV_PARAMS_PBOOK_15A) },
+
+	/* 17 inch PowerBook */
+	{ USB_VPI(USB_VENDOR_APPLE, 0x020d, ATP_DEV_PARAMS_PBOOK_17) },
+
 };
 
 /*
@@ -299,6 +341,7 @@ typedef struct atp_stroke {
 
 enum {
 	ATP_INTR_DT,
+	ATP_RESET,
 	ATP_N_TRANSFER,
 };
 
@@ -321,6 +364,7 @@ struct atp_softc {
 #define ATP_ENABLED            0x01
 #define ATP_ZOMBIES_EXIST      0x02
 #define ATP_DOUBLE_TAP_DRAG    0x04
+#define ATP_VALID              0x08
 
 	u_int                  sc_left_margin;
 	u_int                  sc_right_margin;
@@ -378,21 +422,22 @@ static struct usb_fifo_methods atp_fifo_
 /* device initialization and shutdown */
 static usb_error_t   atp_req_get_report(struct usb_device *udev, void *data);
 static int           atp_set_device_mode(device_t dev, interface_mode mode);
+static void          atp_reset_callback(struct usb_xfer *, usb_error_t);
 static int           atp_enable(struct atp_softc *sc);
 static void          atp_disable(struct atp_softc *sc);
 static int           atp_softc_populate(struct atp_softc *);
 static void          atp_softc_unpopulate(struct atp_softc *);
 
 /* sensor interpretation */
-static __inline void atp_interpret_sensor_data(const int8_t *, u_int, u_int,
-			 int *);
+static __inline void atp_interpret_sensor_data(const int8_t *, u_int, atp_axis,
+			 int *, atp_protocol);
 static __inline void atp_get_pressures(int *, const int *, const int *, int);
 static void          atp_detect_pspans(int *, u_int, u_int, atp_pspan *,
 			 u_int *);
 
 /* movement detection */
 static boolean_t     atp_match_stroke_component(atp_stroke_component *,
-			 const atp_pspan *);
+                         const atp_pspan *, atp_stroke_type);
 static void          atp_match_strokes_against_pspans(struct atp_softc *,
 			 atp_axis, atp_pspan *, u_int, u_int);
 static boolean_t     atp_update_strokes(struct atp_softc *,
@@ -413,6 +458,7 @@ static boolean_t     atp_compute_stroke_
 /* tap detection */
 static __inline void atp_setup_reap_time(struct atp_softc *, struct timeval *);
 static void          atp_reap_zombies(struct atp_softc *, u_int *, u_int *);
+static void          atp_convert_to_slide(struct atp_softc *, atp_stroke *);
 
 /* updating fifo */
 static void          atp_reset_buf(struct atp_softc *sc);
@@ -458,6 +504,40 @@ atp_set_device_mode(device_t dev, interf
 	return (0);
 }
 
+void
+atp_reset_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+	usb_device_request_t   req;
+	struct usb_page_cache *pc;
+	struct atp_softc      *sc = usbd_xfer_softc(xfer);
+
+	switch (USB_GET_STATE(xfer)) {
+	case USB_ST_SETUP:
+		sc->sc_mode_bytes[0] = RAW_SENSOR_MODE;
+		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
+		req.bRequest = UR_SET_REPORT;
+		USETW2(req.wValue,
+		    (uint8_t)0x03 /* type */, (uint8_t)0x00 /* id */);
+		USETW(req.wIndex, 0);
+		USETW(req.wLength, MODE_LENGTH);
+
+		pc = usbd_xfer_get_frame(xfer, 0);
+		usbd_copy_in(pc, 0, &req, sizeof(req));
+		pc = usbd_xfer_get_frame(xfer, 1);
+		usbd_copy_in(pc, 0, sc->sc_mode_bytes, MODE_LENGTH);
+
+		usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
+		usbd_xfer_set_frame_len(xfer, 1, MODE_LENGTH);
+		usbd_xfer_set_frames(xfer, 2);
+		usbd_transfer_submit(xfer);
+		break;
+
+	case USB_ST_TRANSFERRED:
+	default:
+		break;
+	}
+}
+
 static int
 atp_enable(struct atp_softc *sc)
 {
@@ -483,7 +563,7 @@ atp_disable(struct atp_softc *sc)
 {
 	atp_softc_unpopulate(sc);
 
-	sc->sc_state &= ~ATP_ENABLED;
+	sc->sc_state &= ~(ATP_ENABLED | ATP_VALID);
 	DPRINTFN(ATP_LLEVEL_INFO, "disabled atp\n");
 }
 
@@ -623,25 +703,42 @@ atp_softc_unpopulate(struct atp_softc *s
  *       raw sensor data from the USB packet.
  *   num
  *       The number of elements in the array 'arr'.
- *   di_start
- *       The index of the first data element to be interpreted for
- *       this sensor array--i.e. when called to interpret the Y
- *       sensors, di_start passed in as 2, which is the index of Y1 in
- *       the raw data.
+ *   axis
+ *       Axis of data to fetch
  *   arr
  *       The array to be initialized with the readings.
+ *   prot
+ *       The protocol to use to interpret the data
  */
 static __inline void
-atp_interpret_sensor_data(const int8_t *sensor_data, u_int num, u_int di_start,
-    int	*arr)
+atp_interpret_sensor_data(const int8_t *sensor_data, u_int num, atp_axis axis,
+    int	*arr, atp_protocol prot)
 {
 	u_int i;
 	u_int di;   /* index into sensor data */
 
-	for (i = 0, di = di_start; i < num; /* empty */ ) {
-		arr[i++] = sensor_data[di++];
-		arr[i++] = sensor_data[di++];
-		di++;
+	switch (prot) {
+	case ATP_PROT_GEYSER1:
+		/*
+		 * For Geyser 1, the sensors are laid out in pairs
+		 * every 5 bytes.
+		 */
+		for (i = 0, di = (axis == Y) ? 1 : 2; i < 8; di += 5, i++) {
+			arr[i] = sensor_data[di];
+			arr[i+8] = sensor_data[di+2];
+			if (axis == X && num > 16)
+				arr[i+16] = sensor_data[di+40];
+		}
+
+		break;
+	case ATP_PROT_GEYSER2:
+	case ATP_PROT_GEYSER3:
+		for (i = 0, di = (axis == Y) ? 2 : 20; i < num; /* empty */ ) {
+			arr[i++] = sensor_data[di++];
+			arr[i++] = sensor_data[di++];
+			di++;
+		}
+		break;
 	}
 }
 
@@ -783,23 +880,43 @@ atp_detect_pspans(int *p, u_int num_sens
  */
 static boolean_t
 atp_match_stroke_component(atp_stroke_component *component,
-    const atp_pspan *pspan)
+    const atp_pspan *pspan, atp_stroke_type stroke_type)
 {
-	int delta_mickeys = pspan->loc - component->loc;
+	int   delta_mickeys;
+	u_int min_pressure;
+
+	delta_mickeys = pspan->loc - component->loc;
 
 	if (abs(delta_mickeys) > atp_max_delta_mickeys)
 		return (FALSE); /* the finger span is too far out; no match */
 
 	component->loc          = pspan->loc;
+
+	/*
+	 * A sudden and significant increase in a pspan's cumulative
+	 * pressure indicates the incidence of a new finger
+	 * contact. This usually revises the pspan's
+	 * centre-of-gravity, and hence the location of any/all
+	 * matching stroke component(s). But such a change should
+	 * *not* be interpreted as a movement.
+	 */
+        if (pspan->cum > ((3 * component->cum_pressure) >> 1))
+		delta_mickeys = 0;
+
 	component->cum_pressure = pspan->cum;
 	if (pspan->cum > component->max_cum_pressure)
 		component->max_cum_pressure = pspan->cum;
 
 	/*
-	 * If the cumulative pressure drops below a quarter of the max,
-	 * then disregard the component's movement.
+	 * Disregard the component's movement if its cumulative
+	 * pressure drops below a fraction of the maximum; this
+	 * fraction is determined based on the stroke's type.
 	 */
-	if (component->cum_pressure < (component->max_cum_pressure >> 2))
+	if (stroke_type == ATP_STROKE_TOUCH)
+		min_pressure = (3 * component->max_cum_pressure) >> 2;
+	else
+		min_pressure = component->max_cum_pressure >> 2;
+	if (component->cum_pressure < min_pressure)
 		delta_mickeys = 0;
 
 	component->delta_mickeys = delta_mickeys;
@@ -834,7 +951,8 @@ atp_match_strokes_against_pspans(struct 
 				continue; /* skip matched pspans */
 
 			if (atp_match_stroke_component(
-				    &stroke->components[axis], &pspans[j])) {
+				    &stroke->components[axis], &pspans[j],
+				    stroke->type)) {
 				/* There is a match. */
 				stroke->components[axis].matched = TRUE;
 
@@ -969,19 +1087,23 @@ atp_update_strokes(struct atp_softc *sc,
 		for (i = 0; i < sc->sc_n_strokes; i++) {
 			atp_stroke *stroke = &sc->sc_strokes[i];
 
-			printf(" %s%clc:%u,dm:%d,pnd:%d,mv:%d%c"
-			    ",%clc:%u,dm:%d,pnd:%d,mv:%d%c",
+			printf(" %s%clc:%u,dm:%d,pnd:%d,cum:%d,max:%d,mv:%d%c"
+			    ",%clc:%u,dm:%d,pnd:%d,cum:%d,max:%d,mv:%d%c",
 			    (stroke->flags & ATSF_ZOMBIE) ? "zomb:" : "",
 			    (stroke->type == ATP_STROKE_TOUCH) ? '[' : '<',
 			    stroke->components[X].loc,
 			    stroke->components[X].delta_mickeys,
 			    stroke->components[X].pending,
+			    stroke->components[X].cum_pressure,
+			    stroke->components[X].max_cum_pressure,
 			    stroke->components[X].movement,
 			    (stroke->type == ATP_STROKE_TOUCH) ? ']' : '>',
 			    (stroke->type == ATP_STROKE_TOUCH) ? '[' : '<',
 			    stroke->components[Y].loc,
 			    stroke->components[Y].delta_mickeys,
 			    stroke->components[Y].pending,
+			    stroke->components[Y].cum_pressure,
+			    stroke->components[Y].max_cum_pressure,
 			    stroke->components[Y].movement,
 			    (stroke->type == ATP_STROKE_TOUCH) ? ']' : '>');
 		}
@@ -1122,51 +1244,94 @@ atp_advance_stroke_state(struct atp_soft
 	if (atp_compute_stroke_movement(stroke))
 		*movement = TRUE;
 
+	if (stroke->type != ATP_STROKE_TOUCH)
+		return;
+
 	/* Convert touch strokes to slides upon detecting movement or age. */
-	if (stroke->type == ATP_STROKE_TOUCH) {
-		struct timeval tdiff;
+	if (stroke->cum_movement >= atp_slide_min_movement) {
+		atp_convert_to_slide(sc, stroke);
+	} else {
+		/* If a touch stroke is found to be older than the
+		 * touch-timeout threshold, it should be converted to
+		 * a slide; except if there is a co-incident sibling
+		 * with a later creation time.
+		 *
+		 * When multiple fingers make contact with the
+		 * touchpad, they are likely to be separated in their
+		 * times of incidence.  During a multi-finger tap,
+		 * therefore, the last finger to make
+		 * contact--i.e. the one with the latest
+		 * 'ctime'--should be used to determine how the
+		 * touch-siblings get treated; otherwise older
+		 * siblings may lapse the touch-timeout and get
+		 * converted into slides prematurely.  The following
+		 * loop determines if there exists another touch
+		 * stroke with a larger 'ctime' than the current
+		 * stroke (NOTE: zombies with a larger 'ctime' are
+		 * also considered) .
+		 */
 
-		/* Compute the stroke's age. */
-		getmicrotime(&tdiff);
-		if (timevalcmp(&tdiff, &stroke->ctime, >))
-			timevalsub(&tdiff, &stroke->ctime);
-		else {
-			/*
-			 * If we are here, it is because getmicrotime
-			 * reported the current time as being behind
-			 * the stroke's start time; getmicrotime can
-			 * be imprecise.
-			 */
-			tdiff.tv_sec  = 0;
-			tdiff.tv_usec = 0;
-		}
+		u_int i;
+		for (i = 0; i < sc->sc_n_strokes; i++) {
+			if ((&sc->sc_strokes[i] == stroke) ||
+			    (sc->sc_strokes[i].type != ATP_STROKE_TOUCH))
+				continue;
 
-		if ((tdiff.tv_sec > (atp_touch_timeout / 1000000)) ||
-		    ((tdiff.tv_sec == (atp_touch_timeout / 1000000)) &&
-			(tdiff.tv_usec > atp_touch_timeout)) ||
-		    (stroke->cum_movement >= atp_slide_min_movement)) {
-			/* Switch this stroke to being a slide. */
-			stroke->type = ATP_STROKE_SLIDE;
-
-			/* Are we at the beginning of a double-click-n-drag? */
-			if ((sc->sc_n_strokes == 1) &&
-			    ((sc->sc_state & ATP_ZOMBIES_EXIST) == 0) &&
-			    timevalcmp(&stroke->ctime, &sc->sc_reap_time, >)) {
-				struct timeval delta;
-				struct timeval window = {
-					atp_double_tap_threshold / 1000000,
-					atp_double_tap_threshold % 1000000
-				};
-
-				delta = stroke->ctime;
-				timevalsub(&delta, &sc->sc_reap_time);
-				if (timevalcmp(&delta, &window, <=))
-					sc->sc_state |= ATP_DOUBLE_TAP_DRAG;
+			if (timevalcmp(&sc->sc_strokes[i].ctime,
+				&stroke->ctime, >))
+				break;
+		}
+		if (i == sc->sc_n_strokes) {
+			/* Found no other touch stroke with a larger 'ctime'. */
+			struct timeval tdiff;
+
+			/* Compute the stroke's age. */
+			getmicrotime(&tdiff);
+			if (timevalcmp(&tdiff, &stroke->ctime, >))
+				timevalsub(&tdiff, &stroke->ctime);
+			else {
+				/*
+				 * If we are here, it is because getmicrotime
+				 * reported the current time as being behind
+				 * the stroke's start time; getmicrotime can
+				 * be imprecise.
+				 */
+				tdiff.tv_sec  = 0;
+				tdiff.tv_usec = 0;
 			}
+
+			if ((tdiff.tv_sec > (atp_touch_timeout / 1000000)) ||
+			    ((tdiff.tv_sec == (atp_touch_timeout / 1000000)) &&
+				(tdiff.tv_usec >=
+				    (atp_touch_timeout % 1000000))))
+				atp_convert_to_slide(sc, stroke);
 		}
 	}
 }
 
+/* Switch a given touch stroke to being a slide. */
+void
+atp_convert_to_slide(struct atp_softc *sc, atp_stroke *stroke)
+{
+	stroke->type = ATP_STROKE_SLIDE;
+
+	/* Are we at the beginning of a double-click-n-drag? */
+	if ((sc->sc_n_strokes == 1) &&
+	    ((sc->sc_state & ATP_ZOMBIES_EXIST) == 0) &&
+	    timevalcmp(&stroke->ctime, &sc->sc_reap_time, >)) {
+		struct timeval delta;
+		struct timeval window = {
+			atp_double_tap_threshold / 1000000,
+			atp_double_tap_threshold % 1000000
+		};
+
+		delta = stroke->ctime;
+		timevalsub(&delta, &sc->sc_reap_time);
+		if (timevalcmp(&delta, &window, <=))
+			sc->sc_state |= ATP_DOUBLE_TAP_DRAG;
+	}
+}
+
 /*
  * Terminate a stroke. While SLIDE strokes are dropped, TOUCH strokes
  * are retained as zombies so as to reap all their siblings together;
@@ -1455,6 +1620,14 @@ static const struct usb_config atp_confi
 		.bufsize   = 0, /* use wMaxPacketSize */
 		.callback  = &atp_intr,
 	},
+	[ATP_RESET] = {
+		.type      = UE_CONTROL,
+		.endpoint  = 0, /* Control pipe */
+		.direction = UE_DIR_ANY,
+		.bufsize = sizeof(struct usb_device_request) + MODE_LENGTH,
+		.callback  = &atp_reset_callback,
+		.interval = 0,  /* no pre-delay */
+	},
 };
 
 static int
@@ -1469,10 +1642,7 @@ atp_probe(device_t self)
 	    (uaa->info.bInterfaceProtocol != UIPROTO_MOUSE))
 		return (ENXIO);
 
-	if (usbd_lookup_id_by_uaa(atp_devs, sizeof(atp_devs), uaa) == 0)
-		return BUS_PROBE_SPECIFIC;
-	else
-		return ENXIO;
+	return (usbd_lookup_id_by_uaa(atp_devs, sizeof(atp_devs), uaa));
 }
 
 static int
@@ -1482,12 +1652,6 @@ atp_attach(device_t dev)
 	struct usb_attach_arg *uaa = device_get_ivars(dev);
 	usb_error_t            err;
 
-	/* ensure that the probe was successful */
-	if (uaa->driver_info >= ATP_N_DEV_PARAMS) {
-		DPRINTF("device probe returned bad id: %lu\n",
-		    uaa->driver_info);
-		return (ENXIO);
-	}
 	DPRINTFN(ATP_LLEVEL_INFO, "sc=%p\n", sc);
 
 	sc->sc_dev        = dev;
@@ -1566,7 +1730,6 @@ static int
 atp_detach(device_t dev)
 {
 	struct atp_softc *sc;
-	int err;
 
 	sc = device_get_softc(dev);
 	if (sc->sc_state & ATP_ENABLED) {
@@ -1581,12 +1744,6 @@ atp_detach(device_t dev)
 
 	mtx_destroy(&sc->sc_mutex);
 
-	err = atp_set_device_mode(dev, HID_MODE);
-	if (err != 0) {
-		DPRINTF("failed to reset mode to 'HID' (%d)\n", err);
-		return (err);
-	}
-
 	return (0);
 }
 
@@ -1613,7 +1770,7 @@ atp_intr(struct usb_xfer *xfer, usb_erro
 			    len, sc->sc_params->data_len);
 			len = sc->sc_params->data_len;
 		}
-		if (len == 0)
+		if (len < sc->sc_params->data_len)
 			goto tr_setup;
 
 		pc = usbd_xfer_get_frame(xfer, 0);
@@ -1621,9 +1778,11 @@ atp_intr(struct usb_xfer *xfer, usb_erro
 
 		/* Interpret sensor data */
 		atp_interpret_sensor_data(sc->sensor_data,
-		    sc->sc_params->n_xsensors, 20, sc->cur_x);
+		    sc->sc_params->n_xsensors, X, sc->cur_x,
+		    sc->sc_params->prot);
 		atp_interpret_sensor_data(sc->sensor_data,
-		    sc->sc_params->n_ysensors, 2,  sc->cur_y);
+		    sc->sc_params->n_ysensors, Y,  sc->cur_y,
+		    sc->sc_params->prot);
 
 		/*
 		 * If this is the initial update (from an untouched
@@ -1632,11 +1791,14 @@ atp_intr(struct usb_xfer *xfer, usb_erro
 		 * be used as pressure readings subsequently.
 		 */
 		status_bits = sc->sensor_data[sc->sc_params->data_len - 1];
-		if (status_bits & ATP_STATUS_BASE_UPDATE) {
+		if ((sc->sc_params->prot == ATP_PROT_GEYSER3 &&
+		    (status_bits & ATP_STATUS_BASE_UPDATE)) ||
+		    !(sc->sc_state & ATP_VALID)) {
 			memcpy(sc->base_x, sc->cur_x,
 			    sc->sc_params->n_xsensors * sizeof(*(sc->base_x)));
 			memcpy(sc->base_y, sc->cur_y,
 			    sc->sc_params->n_ysensors * sizeof(*(sc->base_y)));
+			sc->sc_state |= ATP_VALID;
 			goto tr_setup;
 		}
 
@@ -1757,8 +1919,23 @@ atp_intr(struct usb_xfer *xfer, usb_erro
 			sc->sc_idlecount++;
 			if (sc->sc_idlecount >= ATP_IDLENESS_THRESHOLD) {
 				DPRINTFN(ATP_LLEVEL_INFO, "idle\n");
-				atp_set_device_mode(sc->sc_dev,RAW_SENSOR_MODE);
+
+				/*
+				 * Use the last frame before we go idle for
+				 * calibration on pads which do not send
+				 * calibration frames.
+				 */
+				if (sc->sc_params->prot < ATP_PROT_GEYSER3) {
+					memcpy(sc->base_x, sc->cur_x,
+					    sc->sc_params->n_xsensors *
+					    sizeof(*(sc->base_x)));
+					memcpy(sc->base_y, sc->cur_y,
+					    sc->sc_params->n_ysensors *
+					    sizeof(*(sc->base_y)));
+				}
+
 				sc->sc_idlecount = 0;
+				usbd_transfer_start(sc->sc_xfer[ATP_RESET]);
 			}
 		} else {
 			sc->sc_idlecount = 0;
@@ -1770,7 +1947,7 @@ atp_intr(struct usb_xfer *xfer, usb_erro
 		if (usb_fifo_put_bytes_max(
 			    sc->sc_fifo.fp[USB_FIFO_RX]) != 0) {
 			usbd_xfer_set_frame_len(xfer, 0,
-			    usbd_xfer_max_len(xfer));
+			    sc->sc_params->data_len);
 			usbd_transfer_submit(xfer);
 		}
 		break;

Modified: stable/8/sys/modules/usb/Makefile
==============================================================================
--- stable/8/sys/modules/usb/Makefile	Wed Dec  9 21:39:43 2009	(r200313)
+++ stable/8/sys/modules/usb/Makefile	Wed Dec  9 21:47:42 2009	(r200314)
@@ -28,7 +28,7 @@
 SUBDIR = usb
 SUBDIR += ehci musb ohci uhci uss820dci ${_at91dci} ${_atmegadci}
 SUBDIR += rum uath upgt ural zyd ${_urtw}
-SUBDIR += uhid ukbd ums udbp ufm
+SUBDIR += atp uhid ukbd ums udbp ufm
 SUBDIR += ucom u3g uark ubsa ubser uchcom ucycom ufoma uftdi ugensa uipaq ulpt \
 	  umct umodem umoscom uplcom uslcom uvisor uvscom
 SUBDIR += uether aue axe cdce cue kue rue udav



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200912092147.nB9LlgLX039541>