--- ums.c.orig 2011-05-27 06:15:17.000000000 +0300 +++ ums.c 2011-06-11 16:37:22.000000000 +0300 @@ -83,12 +83,13 @@ SYSCTL_INT(_hw_usb_ums, OID_AUTO, debug, #define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE) #define MOUSE_FLAGS (HIO_RELATIVE) +#define MOUSE_ABS_FLAGS (0) #define UMS_BUF_SIZE 8 /* bytes */ #define UMS_IFQ_MAXLEN 50 /* units */ #define UMS_BUTTON_MAX 31 /* exclusive, must be less than 32 */ #define UMS_BUT(i) ((i) < 3 ? (((i) + 2) % 3) : (i)) -#define UMS_INFO_MAX 2 /* maximum number of HID sets */ +#define UMS_INFO_MAX 3 /* maximum number of HID sets */ enum { UMS_INTR_DT, @@ -111,6 +112,11 @@ struct ums_info { #define UMS_FLAG_SBU 0x0010 /* spurious button up events */ #define UMS_FLAG_REVZ 0x0020 /* Z-axis is reversed */ #define UMS_FLAG_W_AXIS 0x0040 +#define UMS_FLAG_X_ABS 0x0100 +#define UMS_FLAG_Y_ABS 0x0200 +#define UMS_FLAG_Z_ABS 0x0400 +#define UMS_FLAG_T_ABS 0x0800 +#define UMS_FLAG_W_ABS 0x1000 uint8_t sc_iid_w; uint8_t sc_iid_x; @@ -118,6 +124,11 @@ struct ums_info { uint8_t sc_iid_z; uint8_t sc_iid_t; uint8_t sc_iid_btn[UMS_BUTTON_MAX]; + int32_t sc_prev_x; + int32_t sc_prev_y; + int32_t sc_prev_z; + int32_t sc_prev_t; + int32_t sc_prev_w; uint8_t sc_buttons; }; @@ -191,6 +202,7 @@ ums_intr_callback(struct usb_xfer *xfer, int32_t dy = 0; int32_t dz = 0; int32_t dt = 0; + int32_t temp; uint8_t i; uint8_t id; int len; @@ -236,29 +248,61 @@ ums_intr_callback(struct usb_xfer *xfer, repeat: if ((info->sc_flags & UMS_FLAG_W_AXIS) && - (id == info->sc_iid_w)) - dw += hid_get_data(buf, len, &info->sc_loc_w); + (id == info->sc_iid_w)) { + temp = hid_get_data(buf, len, &info->sc_loc_w); + if (info->sc_flags & UMS_FLAG_W_ABS) { + dw += temp - info->sc_prev_w; + info->sc_prev_w = temp; + } else + dw += temp; + } if ((info->sc_flags & UMS_FLAG_X_AXIS) && - (id == info->sc_iid_x)) - dx += hid_get_data(buf, len, &info->sc_loc_x); + (id == info->sc_iid_x)) { + temp = hid_get_data(buf, len, &info->sc_loc_x); + if (info->sc_flags & UMS_FLAG_X_ABS) { + dx += temp - info->sc_prev_x; + info->sc_prev_x = temp; + } else + dx += temp; + } if ((info->sc_flags & UMS_FLAG_Y_AXIS) && - (id == info->sc_iid_y)) - dy = -hid_get_data(buf, len, &info->sc_loc_y); + (id == info->sc_iid_y)) { + temp = hid_get_data(buf, len, &info->sc_loc_y); + if (info->sc_flags & UMS_FLAG_Y_ABS) { + dy -= temp - info->sc_prev_y; + info->sc_prev_y = temp; + } else + dy -= temp; + } if ((info->sc_flags & UMS_FLAG_Z_AXIS) && (id == info->sc_iid_z)) { - int32_t temp; temp = hid_get_data(buf, len, &info->sc_loc_z); - if (info->sc_flags & UMS_FLAG_REVZ) - temp = -temp; - dz -= temp; + if (info->sc_flags & UMS_FLAG_Z_ABS) { + if (info->sc_flags & UMS_FLAG_REVZ) + dz += temp - info->sc_prev_z; + else + dz -= temp - info->sc_prev_z; + info->sc_prev_z = temp; + } else { + if (info->sc_flags & UMS_FLAG_REVZ) + dz += temp; + else + dz -= temp; + } } if ((info->sc_flags & UMS_FLAG_T_AXIS) && - (id == info->sc_iid_t)) - dt -= hid_get_data(buf, len, &info->sc_loc_t); + (id == info->sc_iid_t)) { + temp = hid_get_data(buf, len, &info->sc_loc_t); + if (info->sc_flags & UMS_FLAG_T_ABS) { + dt -= temp - info->sc_prev_t; + info->sc_prev_t = temp; + } else + dt -= temp; + } for (i = 0; i < info->sc_buttons; i++) { uint32_t mask; @@ -405,6 +449,8 @@ ums_hid_parse(struct ums_softc *sc, devi if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) { info->sc_flags |= UMS_FLAG_X_AXIS; + } else if ((flags & MOUSE_FLAGS_MASK) == MOUSE_ABS_FLAGS) { + info->sc_flags |= UMS_FLAG_X_AXIS | UMS_FLAG_X_ABS; } } if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), @@ -412,6 +458,8 @@ ums_hid_parse(struct ums_softc *sc, devi if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) { info->sc_flags |= UMS_FLAG_Y_AXIS; + } else if ((flags & MOUSE_FLAGS_MASK) == MOUSE_ABS_FLAGS) { + info->sc_flags |= UMS_FLAG_Y_AXIS | UMS_FLAG_Y_ABS; } } /* Try the wheel first as the Z activator since it's tradition. */ @@ -423,6 +471,8 @@ ums_hid_parse(struct ums_softc *sc, devi &info->sc_iid_z)) { if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) { info->sc_flags |= UMS_FLAG_Z_AXIS; + } else if ((flags & MOUSE_FLAGS_MASK) == MOUSE_ABS_FLAGS) { + info->sc_flags |= UMS_FLAG_Z_AXIS | UMS_FLAG_Z_ABS; } /* * We might have both a wheel and Z direction, if so put @@ -434,6 +484,8 @@ ums_hid_parse(struct ums_softc *sc, devi if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) { info->sc_flags |= UMS_FLAG_W_AXIS; + } else if ((flags & MOUSE_FLAGS_MASK) == MOUSE_ABS_FLAGS) { + info->sc_flags |= UMS_FLAG_W_AXIS | UMS_FLAG_W_ABS; } } } else if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, @@ -442,6 +494,8 @@ ums_hid_parse(struct ums_softc *sc, devi if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) { info->sc_flags |= UMS_FLAG_Z_AXIS; + } else if ((flags & MOUSE_FLAGS_MASK) == MOUSE_ABS_FLAGS) { + info->sc_flags |= UMS_FLAG_Z_AXIS | UMS_FLAG_Z_ABS; } } /* @@ -459,13 +513,18 @@ ums_hid_parse(struct ums_softc *sc, devi if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) { info->sc_flags |= UMS_FLAG_T_AXIS; + } else if ((flags & MOUSE_FLAGS_MASK) == MOUSE_ABS_FLAGS) { + info->sc_flags |= UMS_FLAG_T_AXIS | UMS_FLAG_T_ABS; } } else if (hid_locate(buf, len, HID_USAGE2(HUP_CONSUMER, HUC_AC_PAN), hid_input, index, &info->sc_loc_t, &flags, &info->sc_iid_t)) { - if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) + if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) { info->sc_flags |= UMS_FLAG_T_AXIS; + } else if ((flags & MOUSE_FLAGS_MASK) == MOUSE_ABS_FLAGS) { + info->sc_flags |= UMS_FLAG_T_AXIS | UMS_FLAG_T_ABS; + } } /* figure out the number of buttons */ @@ -739,29 +798,21 @@ ums_stop_read(struct usb_fifo *fifo) #endif static void -ums_put_queue(struct ums_softc *sc, int32_t dx, int32_t dy, - int32_t dz, int32_t dt, int32_t buttons) +ums_put_queue(struct ums_softc *sc, int32_t fdx, int32_t fdy, + int32_t fdz, int32_t fdt, int32_t buttons) { + int scale; + int32_t dx, dy, dz, dt; uint8_t buf[8]; +start: if (1) { - - if (dx > 254) - dx = 254; - if (dx < -256) - dx = -256; - if (dy > 254) - dy = 254; - if (dy < -256) - dy = -256; - if (dz > 126) - dz = 126; - if (dz < -128) - dz = -128; - if (dt > 126) - dt = 126; - if (dt < -128) - dt = -128; + scale = max(max(abs(fdx) / 254, abs(fdy) / 254), + max(abs(fdz) / 126, abs(fdt) / 126)) + 1; + dx = fdx / scale; + dy = fdy / scale; + dz = fdz / scale; + dt = fdt / scale; buf[0] = sc->sc_mode.syncmask[1]; buf[0] |= (~buttons) & MOUSE_MSC_BUTTONS; @@ -778,6 +829,12 @@ ums_put_queue(struct ums_softc *sc, int3 usb_fifo_put_data_linear(sc->sc_fifo.fp[USB_FIFO_RX], buf, sc->sc_mode.packetsize, 1); + fdx -= dx; + fdy -= dy; + fdz -= dz; + fdt -= dt; + if (fdx != 0 || fdy != 0 || fdz != 0 || fdt != 0) + goto start; } else { DPRINTF("Buffer full, discarded packet\n"); }