#define TEGRA_WIN_FLAG_ENABLED (1 << 0)
#define TEGRA_WIN_FLAG_BLEND_PREMULT (1 << 1)
#define TEGRA_WIN_FLAG_BLEND_COVERAGE (1 << 2)
+#define TEGRA_WIN_FLAG_INVERT_H (1 << 3)
+#define TEGRA_WIN_FLAG_INVERT_V (1 << 4)
+#define TEGRA_WIN_FLAG_TILED (1 << 5)
#define TEGRA_WIN_BLEND_FLAGS_MASK \
(TEGRA_WIN_FLAG_BLEND_PREMULT | TEGRA_WIN_FLAG_BLEND_COVERAGE)
struct tegra_sdhci_platform_data {
const char *clk_id;
int force_hs;
+ int rt_disable;
int cd_gpio;
int wp_gpio;
int power_gpio;
enum tegra_usb_phy_mode mode;
void *config;
struct otg_transceiver *ulpi;
+ int initialized;
};
struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs,
#include <asm/mach-types.h>
#include <mach/usb_phy.h>
#include <mach/iomap.h>
+#include <mach/pinmux.h>
#define ULPI_VIEWPORT 0x170
+#define ULPI_WAKEUP (1 << 31)
+#define ULPI_RUN (1 << 30)
+#define ULPI_RD_WR (1 << 29)
#define USB_PORTSC1 0x184
#define USB_PORTSC1_PTS(x) (((x) & 0x3) << 30)
#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3)
#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4)
#define USB_SUSP_CLR (1 << 5)
+#define USB_CLKEN (1 << 6)
#define USB_PHY_CLK_VALID (1 << 7)
#define UTMIP_RESET (1 << 11)
#define UHSIC_RESET (1 << 11)
static int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
{
- unsigned long timeout = 2000;
+ unsigned long timeout = 2500;
do {
if ((readl(reg) & mask) == result)
return 0;
}
if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
- USB_PHY_CLK_VALID))
+ USB_PHY_CLK_VALID) < 0)
pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
}
udelay(10);
}
+static void ulpi_phy_restore_start(struct tegra_usb_phy *phy,
+ enum tegra_usb_phy_port_speed port_speed)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ /*Tristate ulpi interface before USB controller resume*/
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, TEGRA_TRI_TRISTATE);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, TEGRA_TRI_TRISTATE);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, TEGRA_TRI_TRISTATE);
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val &= ~ULPI_OUTPUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+}
+
+static void ulpi_phy_restore_end(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_OUTPUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, TEGRA_TRI_NORMAL);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, TEGRA_TRI_NORMAL);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, TEGRA_TRI_NORMAL);
+}
+
static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
{
int ret;
void __iomem *base = phy->regs;
struct tegra_ulpi_config *config = phy->config;
- gpio_direction_output(config->reset_gpio, 0);
- msleep(5);
- gpio_direction_output(config->reset_gpio, 1);
-
clk_enable(phy->clk);
msleep(1);
+ if (!phy->initialized) {
+ phy->initialized = 1;
+ gpio_direction_output(config->reset_gpio, 0);
+ msleep(5);
+ gpio_direction_output(config->reset_gpio, 1);
+ }
+
val = readl(base + USB_SUSP_CTRL);
val |= UHSIC_RESET;
writel(val, base + USB_SUSP_CTRL);
val |= ULPI_PHY_ENABLE;
writel(val, base + USB_SUSP_CTRL);
+ val = readl(base + USB_SUSP_CTRL);
+ val |= USB_SUSP_CLR;
+ writel(val, base + USB_SUSP_CTRL);
+
+ if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ USB_PHY_CLK_VALID) < 0)
+ pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+
+ if (utmi_wait_register(base + USB_SUSP_CTRL, USB_CLKEN, USB_CLKEN) < 0)
+ pr_err("%s: timeout waiting for AHB clock\n", __func__);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_SUSP_CLR;
+ writel(val, base + USB_SUSP_CTRL);
+
val = 0;
writel(val, base + ULPI_TIMING_CTRL_1);
val |= USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN;
writel(val, base + USB_PORTSC1);
- val = readl(base + USB_SUSP_CTRL);
- val |= USB_SUSP_CLR;
- writel(val, base + USB_SUSP_CTRL);
- udelay(100);
-
- val = readl(base + USB_SUSP_CTRL);
- val &= ~USB_SUSP_CLR;
- writel(val, base + USB_SUSP_CTRL);
-
return 0;
}
{
unsigned long val;
void __iomem *base = phy->regs;
- struct tegra_ulpi_config *config = phy->config;
+ int ret;
+
+ /* Disable VbusValid, SessEnd comparators */
+ ret = otg_io_write(phy->ulpi, 0x00, 0x0D);
+ if (ret)
+ pr_err("%s: ulpi write 0x0D failed\n", __func__);
+
+ ret = otg_io_write(phy->ulpi, 0x00, 0x10);
+ if (ret)
+ pr_err("%s: ulpi write 0x10 failed\n", __func__);
+
+ /* Disable IdFloat comparator */
+ ret = otg_io_write(phy->ulpi, 0x00, 0x19);
+ if (ret)
+ pr_err("%s: ulpi write 0x19 failed\n", __func__);
+
+ ret = otg_io_write(phy->ulpi, 0x00, 0x1D);
+ if (ret)
+ pr_err("%s: ulpi write 0x1D failed\n", __func__);
/* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB
* Controller to immediately bring the ULPI PHY out of low power
val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN);
writel(val, base + USB_PORTSC1);
- gpio_direction_output(config->reset_gpio, 0);
+ /* Put the PHY in the low power mode */
+ val = readl(base + USB_PORTSC1);
+ val |= USB_PORTSC1_PHCD;
+ writel(val, base + USB_PORTSC1);
+
+ if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0)
+ pr_err("%s: timeout waiting for phy to stop\n", __func__);
+
clk_disable(phy->clk);
}
phy->regs = regs;
phy->config = config;
phy->mode = phy_mode;
+ phy->initialized = 0;
if (!phy->config) {
if (phy_is_ulpi(phy)) {
{
if (!phy_is_ulpi(phy))
utmi_phy_restore_start(phy, port_speed);
+ else
+ ulpi_phy_restore_start(phy, port_speed);
}
void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy)
{
if (!phy_is_ulpi(phy))
utmi_phy_restore_end(phy);
+ else
+ ulpi_phy_restore_end(phy);
}
void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy)
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) },
#define USB_VENDOR_ID_APPLE 0x05ac
#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d
+#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f
#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214
* Apple "Magic" Wireless Mouse driver
*
* Copyright (c) 2010 Michael Poole <mdpoole@troilus.org>
+ * Copyright (c) 2010 Chase Douglas <chase.douglas@canonical.com>
*/
/*
module_param(report_undeciphered, bool, 0644);
MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event");
-#define TOUCH_REPORT_ID 0x29
+#define TRACKPAD_REPORT_ID 0x28
+#define MOUSE_REPORT_ID 0x29
+#define DOUBLE_REPORT_ID 0xf7
/* These definitions are not precise, but they're close enough. (Bits
* 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem
* to be some kind of bit mask -- 0x20 may be a near-field reading,
#define SCROLL_ACCEL_DEFAULT 7
+/* Single touch emulation should only begin when no touches are currently down.
+ * This is true when single_touch_id is equal to NO_TOUCHES. If multiple touches
+ * are down and the touch providing for single touch emulation is lifted,
+ * single_touch_id is equal to SINGLE_TOUCH_UP. While single touch emulation is
+ * occuring, single_touch_id corresponds with the tracking id of the touch used.
+ */
+#define NO_TOUCHES -1
+#define SINGLE_TOUCH_UP -2
+
/**
* struct magicmouse_sc - Tracks Magic Mouse-specific data.
* @input: Input device through which we report events.
* @quirks: Currently unused.
- * @last_timestamp: Timestamp from most recent (18-bit) touch report
- * (units of milliseconds over short windows, but seems to
- * increase faster when there are no touches).
- * @delta_time: 18-bit difference between the two most recent touch
- * reports from the mouse.
* @ntouches: Number of touches in most recent touch report.
* @scroll_accel: Number of consecutive scroll motions.
* @scroll_jiffies: Time of last scroll motion.
struct input_dev *input;
unsigned long quirks;
- int last_timestamp;
- int delta_time;
int ntouches;
int scroll_accel;
unsigned long scroll_jiffies;
short scroll_x;
short scroll_y;
u8 size;
- u8 down;
} touches[16];
int tracking_ids[16];
+ int single_touch_id;
};
static int magicmouse_firm_touch(struct magicmouse_sc *msc)
static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tdata)
{
struct input_dev *input = msc->input;
- __s32 x_y = tdata[0] << 8 | tdata[1] << 16 | tdata[2] << 24;
- int misc = tdata[5] | tdata[6] << 8;
- int id = (misc >> 6) & 15;
- int x = x_y << 12 >> 20;
- int y = -(x_y >> 20);
- int down = (tdata[7] & TOUCH_STATE_MASK) != TOUCH_STATE_NONE;
+ int id, x, y, size, orientation, touch_major, touch_minor, state, down;
+
+ if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
+ id = (tdata[6] << 2 | tdata[5] >> 6) & 0xf;
+ x = (tdata[1] << 28 | tdata[0] << 20) >> 20;
+ y = -((tdata[2] << 24 | tdata[1] << 16) >> 20);
+ size = tdata[5] & 0x3f;
+ orientation = (tdata[6] >> 2) - 32;
+ touch_major = tdata[3];
+ touch_minor = tdata[4];
+ state = tdata[7] & TOUCH_STATE_MASK;
+ down = state != TOUCH_STATE_NONE;
+ } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+ id = (tdata[7] << 2 | tdata[6] >> 6) & 0xf;
+ x = (tdata[1] << 27 | tdata[0] << 19) >> 19;
+ y = -((tdata[3] << 30 | tdata[2] << 22 | tdata[1] << 14) >> 19);
+ size = tdata[6] & 0x3f;
+ orientation = (tdata[7] >> 2) - 32;
+ touch_major = tdata[4];
+ touch_minor = tdata[5];
+ state = tdata[8] & TOUCH_STATE_MASK;
+ down = state != TOUCH_STATE_NONE;
+ }
/* Store tracking ID and other fields. */
msc->tracking_ids[raw_id] = id;
msc->touches[id].x = x;
msc->touches[id].y = y;
- msc->touches[id].size = misc & 63;
+ msc->touches[id].size = size;
/* If requested, emulate a scroll wheel by detecting small
* vertical touch motions.
int step_y = msc->touches[id].scroll_y - y;
/* Calculate and apply the scroll motion. */
- switch (tdata[7] & TOUCH_STATE_MASK) {
+ switch (state) {
case TOUCH_STATE_START:
msc->touches[id].scroll_x = x;
msc->touches[id].scroll_y = y;
}
}
+ if (down) {
+ msc->ntouches++;
+ if (msc->single_touch_id == NO_TOUCHES)
+ msc->single_touch_id = id;
+ } else if (msc->single_touch_id == id)
+ msc->single_touch_id = SINGLE_TOUCH_UP;
+
/* Generate the input events for this touch. */
if (report_touches && down) {
- int orientation = (misc >> 10) - 32;
-
- msc->touches[id].down = 1;
-
input_report_abs(input, ABS_MT_TRACKING_ID, id);
- input_report_abs(input, ABS_MT_TOUCH_MAJOR, tdata[3]);
- input_report_abs(input, ABS_MT_TOUCH_MINOR, tdata[4]);
+ input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major);
+ input_report_abs(input, ABS_MT_TOUCH_MINOR, touch_minor);
input_report_abs(input, ABS_MT_ORIENTATION, orientation);
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
- if (report_undeciphered)
- input_event(input, EV_MSC, MSC_RAW, tdata[7]);
+ if (report_undeciphered) {
+ if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
+ input_event(input, EV_MSC, MSC_RAW, tdata[7]);
+ else /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+ input_event(input, EV_MSC, MSC_RAW, tdata[8]);
+ }
input_mt_sync(input);
}
{
struct magicmouse_sc *msc = hid_get_drvdata(hdev);
struct input_dev *input = msc->input;
- int x, y, ts, ii, clicks, last_up;
+ int x = 0, y = 0, ii, clicks = 0, npoints;
switch (data[0]) {
- case 0x10:
- if (size != 6)
+ case TRACKPAD_REPORT_ID:
+ /* Expect four bytes of prefix, and N*9 bytes of touch data. */
+ if (size < 4 || ((size - 4) % 9) != 0)
return 0;
- x = (__s16)(data[2] | data[3] << 8);
- y = (__s16)(data[4] | data[5] << 8);
+ npoints = (size - 4) / 9;
+ msc->ntouches = 0;
+ for (ii = 0; ii < npoints; ii++)
+ magicmouse_emit_touch(msc, ii, data + ii * 9 + 4);
+
+ /* We don't need an MT sync here because trackpad emits a
+ * BTN_TOUCH event in a new frame when all touches are released.
+ */
+ if (msc->ntouches == 0)
+ msc->single_touch_id = NO_TOUCHES;
+
clicks = data[1];
+
+ /* The following bits provide a device specific timestamp. They
+ * are unused here.
+ *
+ * ts = data[1] >> 6 | data[2] << 2 | data[3] << 10;
+ */
break;
- case TOUCH_REPORT_ID:
+ case MOUSE_REPORT_ID:
/* Expect six bytes of prefix, and N*8 bytes of touch data. */
if (size < 6 || ((size - 6) % 8) != 0)
return 0;
- ts = data[3] >> 6 | data[4] << 2 | data[5] << 10;
- msc->delta_time = (ts - msc->last_timestamp) & 0x3ffff;
- msc->last_timestamp = ts;
- msc->ntouches = (size - 6) / 8;
- for (ii = 0; ii < msc->ntouches; ii++)
+ npoints = (size - 6) / 8;
+ msc->ntouches = 0;
+ for (ii = 0; ii < npoints; ii++)
magicmouse_emit_touch(msc, ii, data + ii * 8 + 6);
- if (report_touches) {
- last_up = 1;
- for (ii = 0; ii < ARRAY_SIZE(msc->touches); ii++) {
- if (msc->touches[ii].down) {
- last_up = 0;
- msc->touches[ii].down = 0;
- }
- }
- if (last_up) {
- input_mt_sync(input);
- }
- }
+ if (report_touches && msc->ntouches == 0)
+ input_mt_sync(input);
/* When emulating three-button mode, it is important
* to have the current touch information before
x = (int)(((data[3] & 0x0c) << 28) | (data[1] << 22)) >> 22;
y = (int)(((data[3] & 0x30) << 26) | (data[2] << 22)) >> 22;
clicks = data[3];
+
+ /* The following bits provide a device specific timestamp. They
+ * are unused here.
+ *
+ * ts = data[3] >> 6 | data[4] << 2 | data[5] << 10;
+ */
+ break;
+ case DOUBLE_REPORT_ID:
+ /* Sometimes the trackpad sends two touch reports in one
+ * packet.
+ */
+ magicmouse_raw_event(hdev, report, data + 2, data[1]);
+ magicmouse_raw_event(hdev, report, data + 2 + data[1],
+ size - 2 - data[1]);
break;
- case 0x20: /* Theoretically battery status (0-100), but I have
- * never seen it -- maybe it is only upon request.
- */
- case 0x60: /* Unknown, maybe laser on/off. */
- case 0x61: /* Laser reflection status change.
- * data[1]: 0 = spotted, 1 = lost
- */
default:
return 0;
}
- magicmouse_emit_buttons(msc, clicks & 3);
- input_report_rel(input, REL_X, x);
- input_report_rel(input, REL_Y, y);
+ if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
+ magicmouse_emit_buttons(msc, clicks & 3);
+ input_report_rel(input, REL_X, x);
+ input_report_rel(input, REL_Y, y);
+ } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+ input_report_key(input, BTN_MOUSE, clicks & 1);
+ input_report_key(input, BTN_TOUCH, msc->ntouches > 0);
+ input_report_key(input, BTN_TOOL_FINGER, msc->ntouches == 1);
+ input_report_key(input, BTN_TOOL_DOUBLETAP, msc->ntouches == 2);
+ input_report_key(input, BTN_TOOL_TRIPLETAP, msc->ntouches == 3);
+ input_report_key(input, BTN_TOOL_QUADTAP, msc->ntouches == 4);
+ if (msc->single_touch_id >= 0) {
+ input_report_abs(input, ABS_X,
+ msc->touches[msc->single_touch_id].x);
+ input_report_abs(input, ABS_Y,
+ msc->touches[msc->single_touch_id].y);
+ }
+ }
+
input_sync(input);
return 1;
}
-static int magicmouse_input_open(struct input_dev *dev)
-{
- struct hid_device *hid = input_get_drvdata(dev);
-
- return hid->ll_driver->open(hid);
-}
-
-static void magicmouse_input_close(struct input_dev *dev)
-{
- struct hid_device *hid = input_get_drvdata(dev);
-
- hid->ll_driver->close(hid);
-}
-
static void magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev)
{
- input_set_drvdata(input, hdev);
- input->event = hdev->ll_driver->hidinput_input_event;
- input->open = magicmouse_input_open;
- input->close = magicmouse_input_close;
-
- input->name = hdev->name;
- input->phys = hdev->phys;
- input->uniq = hdev->uniq;
- input->id.bustype = hdev->bus;
- input->id.vendor = hdev->vendor;
- input->id.product = hdev->product;
- input->id.version = hdev->version;
- input->dev.parent = hdev->dev.parent;
-
__set_bit(EV_KEY, input->evbit);
- __set_bit(BTN_LEFT, input->keybit);
- __set_bit(BTN_RIGHT, input->keybit);
- if (emulate_3button)
- __set_bit(BTN_MIDDLE, input->keybit);
- __set_bit(BTN_TOOL_FINGER, input->keybit);
-
- __set_bit(EV_REL, input->evbit);
- __set_bit(REL_X, input->relbit);
- __set_bit(REL_Y, input->relbit);
- if (emulate_scroll_wheel) {
- __set_bit(REL_WHEEL, input->relbit);
- __set_bit(REL_HWHEEL, input->relbit);
+
+ if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
+ __set_bit(BTN_LEFT, input->keybit);
+ __set_bit(BTN_RIGHT, input->keybit);
+ if (emulate_3button)
+ __set_bit(BTN_MIDDLE, input->keybit);
+
+ __set_bit(EV_REL, input->evbit);
+ __set_bit(REL_X, input->relbit);
+ __set_bit(REL_Y, input->relbit);
+ if (emulate_scroll_wheel) {
+ __set_bit(REL_WHEEL, input->relbit);
+ __set_bit(REL_HWHEEL, input->relbit);
+ }
+ } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+ __set_bit(BTN_MOUSE, input->keybit);
+ __set_bit(BTN_TOOL_FINGER, input->keybit);
+ __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
+ __set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
+ __set_bit(BTN_TOOL_QUADTAP, input->keybit);
+ __set_bit(BTN_TOUCH, input->keybit);
}
if (report_touches) {
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 4, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 4, 0);
input_set_abs_params(input, ABS_MT_ORIENTATION, -32, 31, 1, 0);
- input_set_abs_params(input, ABS_MT_POSITION_X, -1100, 1358,
- 4, 0);
+
/* Note: Touch Y position from the device is inverted relative
* to how pointer motion is reported (and relative to how USB
* HID recommends the coordinates work). This driver keeps
* the origin at the same position, and just uses the additive
* inverse of the reported Y.
*/
- input_set_abs_params(input, ABS_MT_POSITION_Y, -1589, 2047,
- 4, 0);
+ if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
+ input_set_abs_params(input, ABS_MT_POSITION_X, -1100,
+ 1358, 4, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, -1589,
+ 2047, 4, 0);
+ } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+ input_set_abs_params(input, ABS_X, -2909, 3167, 4, 0);
+ input_set_abs_params(input, ABS_Y, -2456, 2565, 4, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_X, -2909,
+ 3167, 4, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, -2456,
+ 2565, 4, 0);
+ }
}
if (report_undeciphered) {
}
}
+static int magicmouse_input_mapping(struct hid_device *hdev,
+ struct hid_input *hi, struct hid_field *field,
+ struct hid_usage *usage, unsigned long **bit, int *max)
+{
+ struct magicmouse_sc *msc = hid_get_drvdata(hdev);
+
+ if (!msc->input)
+ msc->input = hi->input;
+
+ /* Magic Trackpad does not give relative data after switching to MT */
+ if (hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD &&
+ field->flags & HID_MAIN_ITEM_RELATIVE)
+ return -1;
+
+ return 0;
+}
+
static int magicmouse_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
- __u8 feature_1[] = { 0xd7, 0x01 };
- __u8 feature_2[] = { 0xf8, 0x01, 0x32 };
- struct input_dev *input;
+ __u8 feature[] = { 0xd7, 0x01 };
struct magicmouse_sc *msc;
struct hid_report *report;
int ret;
msc->quirks = id->driver_data;
hid_set_drvdata(hdev, msc);
+ msc->single_touch_id = NO_TOUCHES;
+
ret = hid_parse(hdev);
if (ret) {
dev_err(&hdev->dev, "magicmouse hid parse failed\n");
goto err_free;
}
- /* we are handling the input ourselves */
- hidinput_disconnect(hdev);
+ /* We do this after hid-input is done parsing reports so that
+ * hid-input uses the most natural button and axis IDs.
+ */
+ if (msc->input)
+ magicmouse_setup_input(msc->input, hdev);
+
+ if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
+ report = hid_register_report(hdev, HID_INPUT_REPORT,
+ MOUSE_REPORT_ID);
+ else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+ report = hid_register_report(hdev, HID_INPUT_REPORT,
+ TRACKPAD_REPORT_ID);
+ report = hid_register_report(hdev, HID_INPUT_REPORT,
+ DOUBLE_REPORT_ID);
+ }
- report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID);
if (!report) {
dev_err(&hdev->dev, "unable to register touch report\n");
ret = -ENOMEM;
}
report->size = 6;
- ret = hdev->hid_output_raw_report(hdev, feature_1, sizeof(feature_1),
+ ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
HID_FEATURE_REPORT);
- if (ret != sizeof(feature_1)) {
- dev_err(&hdev->dev, "unable to request touch data (1:%d)\n",
- ret);
- goto err_stop_hw;
- }
- ret = hdev->hid_output_raw_report(hdev, feature_2,
- sizeof(feature_2), HID_FEATURE_REPORT);
- if (ret != sizeof(feature_2)) {
- dev_err(&hdev->dev, "unable to request touch data (2:%d)\n",
+ if (ret != sizeof(feature)) {
+ dev_err(&hdev->dev, "unable to request touch data (%d)\n",
ret);
goto err_stop_hw;
}
- input = input_allocate_device();
- if (!input) {
- dev_err(&hdev->dev, "can't alloc input device\n");
- ret = -ENOMEM;
- goto err_stop_hw;
- }
- magicmouse_setup_input(input, hdev);
-
- ret = input_register_device(input);
- if (ret) {
- dev_err(&hdev->dev, "input device registration failed\n");
- goto err_input;
- }
- msc->input = input;
-
return 0;
-err_input:
- input_free_device(input);
err_stop_hw:
hid_hw_stop(hdev);
err_free:
struct magicmouse_sc *msc = hid_get_drvdata(hdev);
hid_hw_stop(hdev);
- input_unregister_device(msc->input);
kfree(msc);
}
static const struct hid_device_id magic_mice[] = {
- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE),
- .driver_data = 0 },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+ USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+ USB_DEVICE_ID_APPLE_MAGICTRACKPAD), .driver_data = 0 },
{ }
};
MODULE_DEVICE_TABLE(hid, magic_mice);
.probe = magicmouse_probe,
.remove = magicmouse_remove,
.raw_event = magicmouse_raw_event,
+ .input_mapping = magicmouse_input_mapping,
};
static int __init magicmouse_init(void)
if (plat->mmc_data.built_in)
sdhci->mmc->pm_flags = MMC_PM_KEEP_POWER | MMC_PM_IGNORE_PM_NOTIFY;
+ if (plat->rt_disable != 0)
+ sdhci->quirks |= SDHCI_QUIRK_RUNTIME_DISABLE;
+
rc = sdhci_add_host(sdhci);
if (rc)
goto err_clk_disable;
return present;
}
+static int sdhci_enable(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ if (!mmc->card || mmc->card->type == MMC_TYPE_SDIO)
+ return 0;
+
+ if (mmc->ios.clock)
+ sdhci_set_clock(host, mmc->ios.clock);
+
+ return 0;
+}
+
+static int sdhci_disable(struct mmc_host *mmc, int lazy)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ if (!mmc->card || mmc->card->type == MMC_TYPE_SDIO)
+ return 0;
+
+ sdhci_set_clock(host, 0);
+
+ return 0;
+}
+
static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
{
struct sdhci_host *host;
.request = sdhci_request,
.set_ios = sdhci_set_ios,
.get_ro = sdhci_get_ro,
+ .enable = sdhci_enable,
+ .disable = sdhci_disable,
.enable_sdio_irq = sdhci_enable_sdio_irq,
};
if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
mmc->caps |= MMC_CAP_NEEDS_POLL;
+ if (host->quirks & SDHCI_QUIRK_RUNTIME_DISABLE) {
+ mmc->caps |= MMC_CAP_DISABLE;
+ mmc_set_disable_delay(mmc, 50);
+ }
+
mmc->caps |= MMC_CAP_ERASE;
mmc->ocr_avail = 0;
u64 quirks; /* Deviations from spec. */
/* Controller doesn't honor resets unless we touch the clock register */
-#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0)
+#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1LL<<0)
/* Controller has bad caps bits, but really supports DMA */
-#define SDHCI_QUIRK_FORCE_DMA (1<<1)
+#define SDHCI_QUIRK_FORCE_DMA (1LL<<1)
/* Controller doesn't like to be reset when there is no card inserted. */
-#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2)
+#define SDHCI_QUIRK_NO_CARD_NO_RESET (1LL<<2)
/* Controller doesn't like clearing the power reg before a change */
-#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3)
+#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1LL<<3)
/* Controller has flaky internal state so reset it on each ios change */
-#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4)
+#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1LL<<4)
/* Controller has an unusable DMA engine */
-#define SDHCI_QUIRK_BROKEN_DMA (1<<5)
+#define SDHCI_QUIRK_BROKEN_DMA (1LL<<5)
/* Controller has an unusable ADMA engine */
-#define SDHCI_QUIRK_BROKEN_ADMA (1<<6)
+#define SDHCI_QUIRK_BROKEN_ADMA (1LL<<6)
/* Controller can only DMA from 32-bit aligned addresses */
-#define SDHCI_QUIRK_32BIT_DMA_ADDR (1<<7)
+#define SDHCI_QUIRK_32BIT_DMA_ADDR (1LL<<7)
/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
-#define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<8)
+#define SDHCI_QUIRK_32BIT_DMA_SIZE (1LL<<8)
/* Controller can only ADMA chunks that are a multiple of 32 bits */
-#define SDHCI_QUIRK_32BIT_ADMA_SIZE (1<<9)
+#define SDHCI_QUIRK_32BIT_ADMA_SIZE (1LL<<9)
/* Controller needs to be reset after each request to stay stable */
-#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<10)
+#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1LL<<10)
/* Controller needs voltage and power writes to happen separately */
-#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<11)
+#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1LL<<11)
/* Controller provides an incorrect timeout value for transfers */
-#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12)
+#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1LL<<12)
/* Controller has an issue with buffer bits for small transfers */
-#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13)
+#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1LL<<13)
/* Controller does not provide transfer-complete interrupt when not busy */
-#define SDHCI_QUIRK_NO_BUSY_IRQ (1<<14)
+#define SDHCI_QUIRK_NO_BUSY_IRQ (1LL<<14)
/* Controller has unreliable card detection */
-#define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15)
+#define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1LL<<15)
/* Controller reports inverted write-protect state */
-#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16)
+#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1LL<<16)
/* Controller has nonstandard clock management */
-#define SDHCI_QUIRK_NONSTANDARD_CLOCK (1<<17)
+#define SDHCI_QUIRK_NONSTANDARD_CLOCK (1LL<<17)
/* Controller does not like fast PIO transfers */
-#define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18)
+#define SDHCI_QUIRK_PIO_NEEDS_DELAY (1LL<<18)
/* Controller losing signal/interrupt enable states after reset */
-#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET (1<<19)
+#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET (1LL<<19)
/* Controller has to be forced to use block size of 2048 bytes */
-#define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20)
+#define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1LL<<20)
/* Controller cannot do multi-block transfers */
-#define SDHCI_QUIRK_NO_MULTIBLOCK (1<<21)
+#define SDHCI_QUIRK_NO_MULTIBLOCK (1LL<<21)
/* Controller can only handle 1-bit data transfers */
-#define SDHCI_QUIRK_FORCE_1_BIT_DATA (1<<22)
+#define SDHCI_QUIRK_FORCE_1_BIT_DATA (1LL<<22)
/* Controller needs 10ms delay between applying power and clock */
-#define SDHCI_QUIRK_DELAY_AFTER_POWER (1<<23)
+#define SDHCI_QUIRK_DELAY_AFTER_POWER (1LL<<23)
/* Controller uses SDCLK instead of TMCLK for data timeouts */
-#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1<<24)
+#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1LL<<24)
/* Controller reports wrong base clock capability */
-#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1<<25)
+#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1LL<<25)
/* Controller cannot support End Attribute in NOP ADMA descriptor */
-#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1<<26)
+#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1LL<<26)
/* Controller is missing device caps. Use caps provided by host */
-#define SDHCI_QUIRK_MISSING_CAPS (1<<27)
+#define SDHCI_QUIRK_MISSING_CAPS (1LL<<27)
/* Controller uses Auto CMD12 command to stop the transfer */
-#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 (1<<28)
+#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 (1LL<<28)
/* Controller doesn't have HISPD bit field in HI-SPEED SD card */
-#define SDHCI_QUIRK_NO_HISPD_BIT (1<<29)
+#define SDHCI_QUIRK_NO_HISPD_BIT (1LL<<29)
/* Controller write protect bit is broken. Assume no write protection */
-#define SDHCI_QUIRK_BROKEN_WRITE_PROTECT (1<<30)
+#define SDHCI_QUIRK_BROKEN_WRITE_PROTECT (1LL<<30)
/* Controller needs INTERRUPT_AT_BLOCK_GAP enabled to detect card interrupts */
-#define SDHCI_QUIRK_ENABLE_INTERRUPT_AT_BLOCK_GAP (1<<31)
+#define SDHCI_QUIRK_ENABLE_INTERRUPT_AT_BLOCK_GAP (1LL<<31)
/* Controller should not program HIGH_SPEED_EN after switching to high speed */
#define SDHCI_QUIRK_BROKEN_CTRL_HISPD (1LL<<32)
/* Controller supports 8-bit data width */
#define SDHCI_QUIRK_NO_SDIO_IRQ (1LL<<36)
/* Controller should only use high-speed mode */
#define SDHCI_QUIRK_FORCE_HIGH_SPEED_MODE (1LL<<37)
+/* Controller allows runtime enable / disable */
+#define SDHCI_QUIRK_RUNTIME_DISABLE (1LL<<38)
int irq; /* Device IRQ */
void __iomem * ioaddr; /* Mapped address */
*/
/* This driver handles L2TP data packets between a UDP socket and a PPP channel.
- * To keep things simple, only one session per socket is permitted. Packets are
- * sent via the socket, so it must keep connected to the same address. One must
- * not set sequencing in ICCN but let LNS controll it. Currently this driver
- * only works on IPv4 due to the lack of UDP encapsulation support in IPv6. */
+ * The socket must keep connected, and only one session per socket is permitted.
+ * Sequencing of outgoing packets is controlled by LNS. Incoming packets with
+ * sequences are reordered within a sliding window of one second. Currently
+ * reordering only happens when a packet is received. It is done for simplicity
+ * since no additional locks or threads are required. This driver only works on
+ * IPv4 due to the lack of UDP encapsulation support in IPv6. */
#include <linux/module.h>
+#include <linux/jiffies.h>
#include <linux/workqueue.h>
#include <linux/skbuff.h>
#include <linux/file.h>
return (union unaligned *)ptr;
}
+struct meta {
+ __u32 sequence;
+ __u32 timestamp;
+};
+
+static inline struct meta *skb_meta(struct sk_buff *skb)
+{
+ return (struct meta *)skb->cb;
+}
+
+/******************************************************************************/
+
static int pppolac_recv_core(struct sock *sk_udp, struct sk_buff *skb)
{
struct sock *sk = (struct sock *)sk_udp->sk_user_data;
struct pppolac_opt *opt = &pppox_sk(sk)->proto.lac;
+ struct meta *meta = skb_meta(skb);
+ __u32 now = jiffies;
__u8 bits;
__u8 *ptr;
- /* Drop the packet if it is too short. */
+ /* Drop the packet if L2TP header is missing. */
if (skb->len < sizeof(struct udphdr) + 6)
goto drop;
if (unaligned(ptr)->u32 != opt->local)
goto drop;
- /* Check the sequence if it is present. According to RFC 2661 section
- * 5.4, the only thing to do is to update opt->sequencing. */
- opt->sequencing = bits & L2TP_SEQUENCE_BIT;
+ /* Check the sequence if it is present. */
+ if (bits & L2TP_SEQUENCE_BIT) {
+ meta->sequence = ptr[4] << 8 | ptr[5];
+ if ((__s16)(meta->sequence - opt->recv_sequence) < 0)
+ goto drop;
+ }
/* Skip PPP address and control if they are present. */
if (skb->len >= 2 && skb->data[0] == PPP_ADDR &&
if (skb->len >= 1 && skb->data[0] & 1)
skb_push(skb, 1)[0] = 0;
- /* Finally, deliver the packet to PPP channel. */
+ /* Drop the packet if PPP protocol is missing. */
+ if (skb->len < 2)
+ goto drop;
+
+ /* Perform reordering if sequencing is enabled. */
+ atomic_set(&opt->sequencing, bits & L2TP_SEQUENCE_BIT);
+ if (bits & L2TP_SEQUENCE_BIT) {
+ struct sk_buff *skb1;
+
+ /* Insert the packet into receive queue in order. */
+ skb_set_owner_r(skb, sk);
+ skb_queue_walk(&sk->sk_receive_queue, skb1) {
+ struct meta *meta1 = skb_meta(skb1);
+ __s16 order = meta->sequence - meta1->sequence;
+ if (order == 0)
+ goto drop;
+ if (order < 0) {
+ meta->timestamp = meta1->timestamp;
+ skb_insert(skb1, skb, &sk->sk_receive_queue);
+ skb = NULL;
+ break;
+ }
+ }
+ if (skb) {
+ meta->timestamp = now;
+ skb_queue_tail(&sk->sk_receive_queue, skb);
+ }
+
+ /* Remove packets from receive queue as long as
+ * 1. the receive buffer is full,
+ * 2. they are queued longer than one second, or
+ * 3. there are no missing packets before them. */
+ skb_queue_walk_safe(&sk->sk_receive_queue, skb, skb1) {
+ meta = skb_meta(skb);
+ if (atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf &&
+ now - meta->timestamp < HZ &&
+ meta->sequence != opt->recv_sequence)
+ break;
+ skb_unlink(skb, &sk->sk_receive_queue);
+ opt->recv_sequence = (__u16)(meta->sequence + 1);
+ skb_orphan(skb);
+ ppp_input(&pppox_sk(sk)->chan, skb);
+ }
+ return NET_RX_SUCCESS;
+ }
+
+ /* Flush receive queue if sequencing is disabled. */
+ skb_queue_purge(&sk->sk_receive_queue);
skb_orphan(skb);
ppp_input(&pppox_sk(sk)->chan, skb);
return NET_RX_SUCCESS;
skb->data[1] = PPP_CTRL;
/* Install L2TP header. */
- if (opt->sequencing) {
+ if (atomic_read(&opt->sequencing)) {
skb_push(skb, 10);
skb->data[0] = L2TP_SEQUENCE_BIT;
- skb->data[6] = opt->sequence >> 8;
- skb->data[7] = opt->sequence;
+ skb->data[6] = opt->xmit_sequence >> 8;
+ skb->data[7] = opt->xmit_sequence;
skb->data[8] = 0;
skb->data[9] = 0;
- opt->sequence++;
+ opt->xmit_sequence++;
} else {
skb_push(skb, 6);
skb->data[0] = 0;
po->chan.mtu = PPP_MTU - 80;
po->proto.lac.local = unaligned(&addr->local)->u32;
po->proto.lac.remote = unaligned(&addr->remote)->u32;
+ atomic_set(&po->proto.lac.sequencing, 1);
po->proto.lac.backlog_rcv = sk_udp->sk_backlog_rcv;
error = ppp_register_channel(&po->chan);
if (sk->sk_state != PPPOX_NONE) {
struct sock *sk_udp = (struct sock *)pppox_sk(sk)->chan.private;
lock_sock(sk_udp);
+ skb_queue_purge(&sk->sk_receive_queue);
pppox_unbind_sock(sk);
udp_sk(sk_udp)->encap_type = 0;
udp_sk(sk_udp)->encap_rcv = NULL;
/* This driver handles PPTP data packets between a RAW socket and a PPP channel.
* The socket is created in the kernel space and connected to the same address
- * of the control socket. To keep things simple, packets are always sent with
- * sequence but without acknowledgement. This driver should work on both IPv4
- * and IPv6. */
+ * of the control socket. Outgoing packets are always sent with sequences but
+ * without acknowledgements. Incoming packets with sequences are reordered
+ * within a sliding window of one second. Currently reordering only happens when
+ * a packet is received. It is done for simplicity since no additional locks or
+ * threads are required. This driver should work on both IPv4 and IPv6. */
#include <linux/module.h>
+#include <linux/jiffies.h>
#include <linux/workqueue.h>
#include <linux/skbuff.h>
#include <linux/file.h>
__u32 sequence;
} __attribute__((packed));
+struct meta {
+ __u32 sequence;
+ __u32 timestamp;
+};
+
+static inline struct meta *skb_meta(struct sk_buff *skb)
+{
+ return (struct meta *)skb->cb;
+}
+
+/******************************************************************************/
+
static int pppopns_recv_core(struct sock *sk_raw, struct sk_buff *skb)
{
struct sock *sk = (struct sock *)sk_raw->sk_user_data;
struct pppopns_opt *opt = &pppox_sk(sk)->proto.pns;
+ struct meta *meta = skb_meta(skb);
+ __u32 now = jiffies;
struct header *hdr;
/* Skip transport header */
skb_pull(skb, skb_transport_header(skb) - skb->data);
- /* Drop the packet if it is too short. */
+ /* Drop the packet if GRE header is missing. */
if (skb->len < GRE_HEADER_SIZE)
goto drop;
+ hdr = (struct header *)skb->data;
/* Check the header. */
- hdr = (struct header *)skb->data;
if (hdr->type != PPTP_GRE_TYPE || hdr->call != opt->local ||
(hdr->bits & PPTP_GRE_BITS_MASK) != PPTP_GRE_BITS)
goto drop;
if (skb->len != ntohs(hdr->length))
goto drop;
+ /* Check the sequence if it is present. */
+ if (hdr->bits & PPTP_GRE_SEQ_BIT) {
+ meta->sequence = ntohl(hdr->sequence);
+ if ((__s32)(meta->sequence - opt->recv_sequence) < 0)
+ goto drop;
+ }
+
/* Skip PPP address and control if they are present. */
if (skb->len >= 2 && skb->data[0] == PPP_ADDR &&
skb->data[1] == PPP_CTRL)
if (skb->len >= 1 && skb->data[0] & 1)
skb_push(skb, 1)[0] = 0;
- /* Finally, deliver the packet to PPP channel. */
+ /* Drop the packet if PPP protocol is missing. */
+ if (skb->len < 2)
+ goto drop;
+
+ /* Perform reordering if sequencing is enabled. */
+ if (hdr->bits & PPTP_GRE_SEQ_BIT) {
+ struct sk_buff *skb1;
+
+ /* Insert the packet into receive queue in order. */
+ skb_set_owner_r(skb, sk);
+ skb_queue_walk(&sk->sk_receive_queue, skb1) {
+ struct meta *meta1 = skb_meta(skb1);
+ __s32 order = meta->sequence - meta1->sequence;
+ if (order == 0)
+ goto drop;
+ if (order < 0) {
+ meta->timestamp = meta1->timestamp;
+ skb_insert(skb1, skb, &sk->sk_receive_queue);
+ skb = NULL;
+ break;
+ }
+ }
+ if (skb) {
+ meta->timestamp = now;
+ skb_queue_tail(&sk->sk_receive_queue, skb);
+ }
+
+ /* Remove packets from receive queue as long as
+ * 1. the receive buffer is full,
+ * 2. they are queued longer than one second, or
+ * 3. there are no missing packets before them. */
+ skb_queue_walk_safe(&sk->sk_receive_queue, skb, skb1) {
+ meta = skb_meta(skb);
+ if (atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf &&
+ now - meta->timestamp < HZ &&
+ meta->sequence != opt->recv_sequence)
+ break;
+ skb_unlink(skb, &sk->sk_receive_queue);
+ opt->recv_sequence = meta->sequence + 1;
+ skb_orphan(skb);
+ ppp_input(&pppox_sk(sk)->chan, skb);
+ }
+ return NET_RX_SUCCESS;
+ }
+
+ /* Flush receive queue if sequencing is disabled. */
+ skb_queue_purge(&sk->sk_receive_queue);
skb_orphan(skb);
ppp_input(&pppox_sk(sk)->chan, skb);
return NET_RX_SUCCESS;
hdr->type = PPTP_GRE_TYPE;
hdr->length = htons(length);
hdr->call = opt->remote;
- hdr->sequence = htonl(opt->sequence);
- opt->sequence++;
+ hdr->sequence = htonl(opt->xmit_sequence);
+ opt->xmit_sequence++;
/* Now send the packet via the delivery queue. */
skb_set_owner_w(skb, sk_raw);
if (sk->sk_state != PPPOX_NONE) {
struct sock *sk_raw = (struct sock *)pppox_sk(sk)->chan.private;
lock_sock(sk_raw);
+ skb_queue_purge(&sk->sk_receive_queue);
pppox_unbind_sock(sk);
sk_raw->sk_data_ready = pppox_sk(sk)->proto.pns.data_ready;
sk_raw->sk_backlog_rcv = pppox_sk(sk)->proto.pns.backlog_rcv;
}
clk_enable(emc_clk);
- clk_set_rate(emc_clk, 400000000);
+ clk_set_rate(emc_clk, 300000000);
/* we have to remap the registers ourselves as fsl_udc does not
* export them for us.
else if (typeReq == GetPortStatus) {
temp = ehci_readl(ehci, status_reg);
- if (tegra->port_resuming && !(temp & PORT_SUSPEND)) {
+ if (tegra->port_resuming && !(temp & PORT_SUSPEND) &&
+ time_after_eq(jiffies, ehci->reset_done[wIndex-1])) {
/* Resume completed, re-enable disconnect detection */
tegra->port_resuming = 0;
+ clear_bit((wIndex & 0xff) - 1, &ehci->suspended_ports);
+ ehci->reset_done[wIndex-1] = 0;
tegra_usb_phy_postresume(tegra->phy);
}
}
if (!(temp & PORT_SUSPEND))
goto done;
+ tegra->port_resuming = 1;
+
/* Disable disconnect detection during port resume */
tegra_usb_phy_preresume(tegra->phy);
- ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25);
-
ehci_dbg(ehci, "%s:USBSTS = 0x%x", __func__,
ehci_readl(ehci, &ehci->regs->status));
usbsts_reg = ehci_readl(ehci, &ehci->regs->status);
udelay(20);
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
- /* start resume signalling */
+ /* start resume signaling */
ehci_writel(ehci, temp | PORT_RESUME, status_reg);
- spin_unlock_irqrestore(&ehci->lock, flags);
- msleep(20);
- spin_lock_irqsave(&ehci->lock, flags);
-
- /* Poll until the controller clears RESUME and SUSPEND */
- if (handshake(ehci, status_reg, PORT_RESUME, 0, 2000))
- pr_err("%s: timeout waiting for RESUME\n", __func__);
- if (handshake(ehci, status_reg, PORT_SUSPEND, 0, 2000))
- pr_err("%s: timeout waiting for SUSPEND\n", __func__);
-
- ehci->reset_done[wIndex-1] = 0;
-
- tegra->port_resuming = 1;
+ ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25);
+ /* whoever resumes must GetPortStatus to complete it!! */
goto done;
}
tegra->bus_suspended = 0;
}
- tegra_usb_phy_preresume(tegra->phy);
- tegra->port_resuming = 1;
return ehci_bus_resume(hcd);
}
#endif
}
clk_enable(tegra->emc_clk);
- clk_set_rate(tegra->emc_clk, 400000000);
+ clk_set_rate(tegra->emc_clk, 300000000);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
struct tegra_dc_win *win = windows[i];
unsigned h_dda;
unsigned v_dda;
+ unsigned h_offset;
+ unsigned v_offset;
+ bool invert_h = (win->flags & TEGRA_WIN_FLAG_INVERT_H) != 0;
+ bool invert_v = (win->flags & TEGRA_WIN_FLAG_INVERT_V) != 0;
bool yuvp = tegra_dc_is_yuv_planar(win->fmt);
if (win->z != dc->blend.z[win->idx]) {
DC_WIN_LINE_STRIDE);
}
- tegra_dc_writel(dc, win->x * tegra_dc_fmt_bpp(win->fmt) / 8,
- DC_WINBUF_ADDR_H_OFFSET);
- tegra_dc_writel(dc, win->y, DC_WINBUF_ADDR_V_OFFSET);
+ h_offset = win->x;
+ if (invert_h) {
+ h_offset += win->w - 1;
+ }
+ h_offset *= tegra_dc_fmt_bpp(win->fmt) / 8;
+
+ v_offset = win->y;
+ if (invert_v) {
+ v_offset += win->h - 1;
+ }
+
+ tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET);
+ tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET);
+
+ if (win->flags & TEGRA_WIN_FLAG_TILED)
+ tegra_dc_writel(dc,
+ DC_WIN_BUFFER_ADDR_MODE_TILE |
+ DC_WIN_BUFFER_ADDR_MODE_TILE_UV,
+ DC_WIN_BUFFER_ADDR_MODE);
+ else
+ tegra_dc_writel(dc,
+ DC_WIN_BUFFER_ADDR_MODE_LINEAR |
+ DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV,
+ DC_WIN_BUFFER_ADDR_MODE);
val = WIN_ENABLE;
if (yuvp)
if (win->h != win->out_h)
val |= V_FILTER_ENABLE;
+ if (invert_h)
+ val |= H_DIRECTION_DECREMENT;
+ if (invert_v)
+ val |= V_DIRECTION_DECREMENT;
+
tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS);
win->dirty = no_vsync ? 0 : 1;
#define DC_WIN_V_FILTER_P(x) (0x619 + (x))
#define DC_WIN_WIN_OPTIONS 0x700
#define H_DIRECTION_INCREMENT (0 << 0)
-#define H_DIRECTION_DECREMENTT (1 << 0)
+#define H_DIRECTION_DECREMENT (1 << 0)
#define V_DIRECTION_INCREMENT (0 << 2)
-#define V_DIRECTION_DECREMENTT (1 << 2)
+#define V_DIRECTION_DECREMENT (1 << 2)
#define COLOR_EXPAND (1 << 6)
#define H_FILTER_ENABLE (1 << 8)
#define V_FILTER_ENABLE (1 << 10)
#define DC_WIN_BUF_STRIDE 0x70b
#define DC_WIN_UV_BUF_STRIDE 0x70c
#define DC_WIN_BUFFER_ADDR_MODE 0x70d
+#define DC_WIN_BUFFER_ADDR_MODE_LINEAR (0 << 0)
+#define DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV (0 << 16)
+#define DC_WIN_BUFFER_ADDR_MODE_TILE (1 << 0)
+#define DC_WIN_BUFFER_ADDR_MODE_TILE_UV (1 << 16)
#define DC_WIN_DV_CONTROL 0x70e
#define DC_WIN_BLEND_NOKEY 0x70f
#define DC_WIN_BLEND_1WIN 0x710
win->flags |= TEGRA_WIN_FLAG_BLEND_PREMULT;
else if (flip_win->attr.blend == TEGRA_FB_WIN_BLEND_COVERAGE)
win->flags |= TEGRA_WIN_FLAG_BLEND_COVERAGE;
+ if (flip_win->attr.flags & TEGRA_FB_WIN_FLAG_INVERT_H)
+ win->flags |= TEGRA_WIN_FLAG_INVERT_H;
+ if (flip_win->attr.flags & TEGRA_FB_WIN_FLAG_INVERT_V)
+ win->flags |= TEGRA_WIN_FLAG_INVERT_V;
+ if (flip_win->attr.flags & TEGRA_FB_WIN_FLAG_TILED)
+ win->flags |= TEGRA_WIN_FLAG_TILED;
+
win->fmt = flip_win->attr.pixformat;
win->x = flip_win->attr.x;
win->y = flip_win->attr.y;
};
struct pppolac_opt {
- __u32 local;
- __u32 remote;
- __u16 sequence;
- __u8 sequencing;
- int (*backlog_rcv)(struct sock *sk_udp, struct sk_buff *skb);
+ __u32 local;
+ __u32 remote;
+ __u32 recv_sequence;
+ __u32 xmit_sequence;
+ atomic_t sequencing;
+ int (*backlog_rcv)(struct sock *sk_udp, struct sk_buff *skb);
};
struct pppopns_opt {
- __u16 local;
- __u16 remote;
- __u32 sequence;
- void (*data_ready)(struct sock *sk_raw, int length);
- int (*backlog_rcv)(struct sock *sk_raw, struct sk_buff *skb);
+ __u16 local;
+ __u16 remote;
+ __u32 recv_sequence;
+ __u32 xmit_sequence;
+ void (*data_ready)(struct sock *sk_raw, int length);
+ int (*backlog_rcv)(struct sock *sk_raw, struct sk_buff *skb);
};
#include <net/sock.h>
extern int tcp_gro_complete(struct sk_buff *skb);
extern int tcp4_gro_complete(struct sk_buff *skb);
-extern void tcp_v4_nuke_addr(__u32 saddr);
+extern int tcp_nuke_addr(struct net *net, struct sockaddr *addr);
#ifdef CONFIG_PROC_FS
extern int tcp4_proc_init(void);
#define TEGRA_FB_WIN_FMT_YCbCr422RA 24
#define TEGRA_FB_WIN_FMT_YUV422RA 25
-#define TEGRA_FB_WIN_BLEND_NONE 0
-#define TEGRA_FB_WIN_BLEND_PREMULT 1
-#define TEGRA_FB_WIN_BLEND_COVERAGE 2
+#define TEGRA_FB_WIN_BLEND_NONE 0
+#define TEGRA_FB_WIN_BLEND_PREMULT 1
+#define TEGRA_FB_WIN_BLEND_COVERAGE 2
+
+#define TEGRA_FB_WIN_FLAG_INVERT_H (1 << 0)
+#define TEGRA_FB_WIN_FLAG_INVERT_V (1 << 1)
+#define TEGRA_FB_WIN_FLAG_TILED (1 << 2)
/* set index to -1 to ignore window data */
struct tegra_fb_windowattr {
__s32 index;
__u32 buff_id;
+ __u32 flags;
__u32 blend;
__u32 offset;
__u32 offset_u;
}
break;
case SIOCKILLADDR: /* Nuke all connections on this address */
- ret = 0;
- tcp_v4_nuke_addr(sin->sin_addr.s_addr);
+ ret = tcp_nuke_addr(net, (struct sockaddr *) sin);
break;
}
done:
#include <net/tcp.h>
#include <net/xfrm.h>
#include <net/ip.h>
+#include <net/ip6_route.h>
#include <net/netdma.h>
#include <net/sock.h>
tcp_secret_retiring = &tcp_secret_two;
tcp_secret_secondary = &tcp_secret_two;
}
+
+static int tcp_is_local(struct net *net, __be32 addr) {
+ struct rtable *rt;
+ struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
+ if (ip_route_output_key(net, &rt, &fl) || !rt)
+ return 0;
+ return rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static int tcp_is_local6(struct net *net, struct in6_addr *addr) {
+ struct rt6_info *rt6 = rt6_lookup(net, addr, addr, 0, 0);
+ return rt6 && rt6->rt6i_dev && (rt6->rt6i_dev->flags & IFF_LOOPBACK);
+}
+#endif
+
+/*
+ * tcp_nuke_addr - destroy all sockets on the given local address
+ * if local address is the unspecified address (0.0.0.0 or ::), destroy all
+ * sockets with local addresses that are not configured.
+ */
+int tcp_nuke_addr(struct net *net, struct sockaddr *addr)
+{
+ int family = addr->sa_family;
+ unsigned int bucket;
+
+ struct in_addr *in;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ struct in6_addr *in6;
+#endif
+ if (family == AF_INET) {
+ in = &((struct sockaddr_in *)addr)->sin_addr;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ } else if (family == AF_INET6) {
+ in6 = &((struct sockaddr_in6 *)addr)->sin6_addr;
+#endif
+ } else {
+ return -EAFNOSUPPORT;
+ }
+
+ for (bucket = 0; bucket < tcp_hashinfo.ehash_mask; bucket++) {
+ struct hlist_nulls_node *node;
+ struct sock *sk;
+ spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, bucket);
+
+restart:
+ spin_lock_bh(lock);
+ sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[bucket].chain) {
+ struct inet_sock *inet = inet_sk(sk);
+
+ if (family == AF_INET) {
+ __be32 s4 = inet->inet_rcv_saddr;
+ if (in->s_addr != s4 &&
+ !(in->s_addr == INADDR_ANY &&
+ !tcp_is_local(net, s4)))
+ continue;
+ }
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ if (family == AF_INET6) {
+ struct in6_addr *s6;
+ if (!inet->pinet6)
+ continue;
+ s6 = &inet->pinet6->rcv_saddr;
+ if (!ipv6_addr_equal(in6, s6) &&
+ !(ipv6_addr_equal(in6, &in6addr_any) &&
+ !tcp_is_local6(net, s6)))
+ continue;
+ }
+#endif
+
+ if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT)
+ continue;
+ if (sock_flag(sk, SOCK_DEAD))
+ continue;
+
+ sock_hold(sk);
+ spin_unlock_bh(lock);
+
+ local_bh_disable();
+ bh_lock_sock(sk);
+ sk->sk_err = ETIMEDOUT;
+ sk->sk_error_report(sk);
+
+ tcp_done(sk);
+ bh_unlock_sock(sk);
+ local_bh_enable();
+ sock_put(sk);
+
+ goto restart;
+ }
+ spin_unlock_bh(lock);
+ }
+
+ return 0;
+}
}
EXPORT_SYMBOL(tcp_v4_destroy_sock);
-/*
- * tcp_v4_nuke_addr - destroy all sockets on the given local address
- */
-void tcp_v4_nuke_addr(__u32 saddr)
-{
- unsigned int bucket;
-
- for (bucket = 0; bucket < tcp_hashinfo.ehash_mask; bucket++) {
- struct hlist_nulls_node *node;
- struct sock *sk;
- spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, bucket);
-
-restart:
- spin_lock_bh(lock);
- sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[bucket].chain) {
- struct inet_sock *inet = inet_sk(sk);
-
- if (inet->inet_rcv_saddr != saddr)
- continue;
- if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT)
- continue;
- if (sock_flag(sk, SOCK_DEAD))
- continue;
-
- sock_hold(sk);
- spin_unlock_bh(lock);
-
- local_bh_disable();
- bh_lock_sock(sk);
- sk->sk_err = ETIMEDOUT;
- sk->sk_error_report(sk);
-
- tcp_done(sk);
- bh_unlock_sock(sk);
- local_bh_enable();
- sock_put(sk);
-
- goto restart;
- }
- spin_unlock_bh(lock);
- }
-}
-
#ifdef CONFIG_PROC_FS
/* Proc filesystem TCP sock list dumping. */
EXPORT_SYMBOL(inet6_getname);
+int inet6_killaddr_ioctl(struct net *net, void __user *arg) {
+ struct in6_ifreq ireq;
+ struct sockaddr_in6 sin6;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EACCES;
+
+ if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
+ return -EFAULT;
+
+ sin6.sin6_family = AF_INET6;
+ ipv6_addr_copy(&sin6.sin6_addr, &ireq.ifr6_addr);
+ return tcp_nuke_addr(net, (struct sockaddr *) &sin6);
+}
+
int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
return addrconf_del_ifaddr(net, (void __user *) arg);
case SIOCSIFDSTADDR:
return addrconf_set_dstaddr(net, (void __user *) arg);
+ case SIOCKILLADDR:
+ return inet6_killaddr_ioctl(net, (void __user *) arg);
default:
if (!sk->sk_prot->ioctl)
return -ENOIOCTLCMD;