Merge remote-tracking branch 'remotes/tegra/android-tegra-2.6.36' into develop-2...
author黄涛 <huangtao@rock-chips.com>
Sun, 31 Jul 2011 16:17:16 +0000 (00:17 +0800)
committer黄涛 <huangtao@rock-chips.com>
Sun, 31 Jul 2011 16:17:16 +0000 (00:17 +0800)
Conflicts:
drivers/mmc/host/sdhci-tegra.c
drivers/net/wireless/bcm4329/dhd_common.c
drivers/net/wireless/bcm4329/dhd_custom_gpio.c

24 files changed:
arch/arm/mach-tegra/include/mach/dc.h
arch/arm/mach-tegra/include/mach/sdhci.h
arch/arm/mach-tegra/include/mach/usb_phy.h
arch/arm/mach-tegra/usb_phy.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-magicmouse.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/net/pppolac.c
drivers/net/pppopns.c
drivers/usb/gadget/fsl_tegra_udc.c
drivers/usb/host/ehci-tegra.c
drivers/video/tegra/dc/dc.c
drivers/video/tegra/dc/dc_reg.h
drivers/video/tegra/fb.c
include/linux/if_pppox.h
include/net/tcp.h
include/video/tegrafb.h
net/ipv4/devinet.c
net/ipv4/tcp.c
net/ipv4/tcp_ipv4.c
net/ipv6/af_inet6.c

index 9bd26194f0c96263eca8e65ebed228925abf0b0b..daaeb3b8a72eae4fbd9df0c1e0e69b9cc260c9c7 100644 (file)
@@ -122,6 +122,9 @@ struct tegra_dc_win {
 #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)
index b0e07d26f1612a3dff9d8074089c28d1e7c80ce8..a6e7fc5fc98485750704af7127a3950c01ca8d4c 100644 (file)
@@ -23,6 +23,7 @@
 struct tegra_sdhci_platform_data {
        const char *clk_id;
        int force_hs;
+       int rt_disable;
        int cd_gpio;
        int wp_gpio;
        int power_gpio;
index d4b8f9e298a8a8502e0de7e5f67227bf91737ba9..bca649d80e38f79ce0ba5ec33248a81972e5e651 100644 (file)
@@ -59,6 +59,7 @@ struct tegra_usb_phy {
        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,
index 88081bb3ec52dd807092ea397685126f2a1602f2..ef07efd11b19eeae8606d4d2bae139bc1968ed02 100644 (file)
 #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)
@@ -50,6 +54,7 @@
 #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)
@@ -288,7 +293,7 @@ static int utmip_pad_power_off(struct tegra_usb_phy *phy)
 
 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;
@@ -349,7 +354,7 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
        }
 
        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__);
 }
 
@@ -566,6 +571,36 @@ static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
        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;
@@ -573,13 +608,16 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
        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);
@@ -592,6 +630,21 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
        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);
 
@@ -623,15 +676,6 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
        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;
 }
 
@@ -639,7 +683,25 @@ static void ulpi_phy_power_off(struct tegra_usb_phy *phy)
 {
        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
@@ -648,7 +710,14 @@ static void ulpi_phy_power_off(struct tegra_usb_phy *phy)
        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);
 }
 
@@ -669,6 +738,7 @@ struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs,
        phy->regs = regs;
        phy->config = config;
        phy->mode = phy_mode;
+       phy->initialized = 0;
 
        if (!phy->config) {
                if (phy_is_ulpi(phy)) {
@@ -763,12 +833,16 @@ void tegra_ehci_phy_restore_start(struct tegra_usb_phy *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)
index 107e81728ff891b5c0f2c9c5bf27caf1cc2a38b1..45e9a295e02d14fab2c1c2f56bb6027bd69ddf3e 100644 (file)
@@ -1248,6 +1248,7 @@ static const struct hid_device_id hid_blacklist[] = {
        { 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) },
index 5d2553d5fe327e03d49cbda05331a8460bad89bf..2e23804b65d63f0e88382d6cbbeab3fa4c1970ff 100644 (file)
@@ -63,6 +63,7 @@
 #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
index 319b0e57ee41f1cdbebafb833989b7a3507c7440..51f945a9e9e004995d9628af073f4c02d676c145 100644 (file)
@@ -2,6 +2,7 @@
  *   Apple "Magic" Wireless Mouse driver
  *
  *   Copyright (c) 2010 Michael Poole <mdpoole@troilus.org>
+ *   Copyright (c) 2010 Chase Douglas <chase.douglas@canonical.com>
  */
 
 /*
@@ -53,7 +54,9 @@ static bool report_undeciphered;
 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,
@@ -67,15 +70,19 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
 
 #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.
@@ -86,8 +93,6 @@ struct magicmouse_sc {
        struct input_dev *input;
        unsigned long quirks;
 
-       int last_timestamp;
-       int delta_time;
        int ntouches;
        int scroll_accel;
        unsigned long scroll_jiffies;
@@ -98,9 +103,9 @@ struct magicmouse_sc {
                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)
@@ -166,18 +171,35 @@ static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state)
 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.
@@ -188,7 +210,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
                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;
@@ -222,21 +244,28 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
                }
        }
 
+       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);
        }
@@ -247,39 +276,43 @@ static int magicmouse_raw_event(struct hid_device *hdev,
 {
        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
@@ -288,68 +321,72 @@ static int magicmouse_raw_event(struct hid_device *hdev,
                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) {
@@ -359,16 +396,26 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h
                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) {
@@ -377,12 +424,27 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h
        }
 }
 
+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;
@@ -398,6 +460,8 @@ static int magicmouse_probe(struct hid_device *hdev,
        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");
@@ -410,10 +474,22 @@ static int magicmouse_probe(struct hid_device *hdev,
                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;
@@ -421,39 +497,15 @@ static int magicmouse_probe(struct hid_device *hdev,
        }
        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:
@@ -466,13 +518,14 @@ static void magicmouse_remove(struct hid_device *hdev)
        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);
@@ -483,6 +536,7 @@ static struct hid_driver magicmouse_driver = {
        .probe = magicmouse_probe,
        .remove = magicmouse_remove,
        .raw_event = magicmouse_raw_event,
+       .input_mapping = magicmouse_input_mapping,
 };
 
 static int __init magicmouse_init(void)
index a0b9750eb8dd02862eb6d76b0ccfdc6f0ea95832..793915f8b239cd08777bd71a5714b03592f3b032 100644 (file)
@@ -186,6 +186,9 @@ static int __devinit tegra_sdhci_probe(struct platform_device *pdev)
        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;
index 7577da76fbb2f192f4b1118ba49296e328ee1656..ba32a2ef93a1a8804fbb5c0595c08449f0949b3b 100644 (file)
@@ -1229,6 +1229,31 @@ static int sdhci_get_ro(struct mmc_host *mmc)
        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;
@@ -1265,6 +1290,8 @@ static const struct mmc_host_ops sdhci_ops = {
        .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,
 };
 
@@ -1871,6 +1898,11 @@ int sdhci_add_host(struct sdhci_host *host)
        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;
index 1727609c13f81712a9e57a97d0ba9342f280fa13..9cac859561ff5aef336b9903c885c584f0a17265 100644 (file)
@@ -189,69 +189,69 @@ struct sdhci_host {
        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 */
@@ -264,6 +264,8 @@ struct sdhci_host {
 #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 */
index af3202a920a005b1f2d379def77a73f8cf3f40af..c94b8507d92bb4462798bc9ffed5e23ccadeb526 100644 (file)
  */
 
 /* 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>
@@ -53,14 +56,28 @@ static inline union unaligned *unaligned(void *ptr)
        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;
 
@@ -99,9 +116,12 @@ static int pppolac_recv_core(struct sock *sk_udp, struct sk_buff *skb)
        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 &&
@@ -112,7 +132,54 @@ static int pppolac_recv_core(struct sock *sk_udp, struct sk_buff *skb)
        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;
@@ -163,14 +230,14 @@ static int pppolac_xmit(struct ppp_channel *chan, struct sk_buff *skb)
        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;
@@ -246,6 +313,7 @@ static int pppolac_connect(struct socket *sock, struct sockaddr *useraddr,
        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);
@@ -283,6 +351,7 @@ static int pppolac_release(struct socket *sock)
        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;
index 298097127c90feb003dd3c54cfa5b93a640e19d0..fb8198447938be6babddb34f7a1c7e8ce03f20b5 100644 (file)
 
 /* 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>
@@ -52,21 +55,35 @@ struct header {
        __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;
@@ -81,6 +98,13 @@ static int pppopns_recv_core(struct sock *sk_raw, struct sk_buff *skb)
        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)
@@ -90,7 +114,53 @@ static int pppopns_recv_core(struct sock *sk_raw, struct sk_buff *skb)
        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;
@@ -151,8 +221,8 @@ static int pppopns_xmit(struct ppp_channel *chan, struct sk_buff *skb)
        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);
@@ -261,6 +331,7 @@ static int pppopns_release(struct socket *sock)
        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;
index 14e62f40a50a50d0923c2e46220af98bdb0642cc..24867cd6090908dc0d1e8132e5aff2bbbb438984 100644 (file)
@@ -42,7 +42,7 @@ int fsl_udc_clk_init(struct platform_device *pdev)
        }
 
        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.
index 8acf0c4366f73a567912bdb0a61e612c80cc4b26..9738b994f391a4fa3dfd1c37932ac2710724d143 100644 (file)
@@ -94,9 +94,12 @@ static int tegra_ehci_hub_control(
 
        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);
                }
        }
@@ -142,11 +145,11 @@ static int tegra_ehci_hub_control(
                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);
@@ -168,22 +171,11 @@ static int tegra_ehci_hub_control(
 
                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;
        }
 
@@ -402,8 +394,6 @@ static int tegra_ehci_bus_resume(struct usb_hcd *hcd)
                tegra->bus_suspended = 0;
        }
 
-       tegra_usb_phy_preresume(tegra->phy);
-       tegra->port_resuming = 1;
        return ehci_bus_resume(hcd);
 }
 #endif
@@ -574,7 +564,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
        }
 
        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) {
index 4549670fdff52f65967e86335d938afe84752c1d..53f52df2e0f881aa6aeda5baf532eaba09544c9f 100644 (file)
@@ -500,6 +500,10 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
                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]) {
@@ -567,9 +571,30 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
                                        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)
@@ -582,6 +607,11 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
                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;
index ab21c6eba0e169fa98661c11402859fc650b4204..df1333e31d141d66cde2d04f9703be2ad62769ea 100644 (file)
 #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
index 9b70114c9cd107d10da923a13f697285aa7c3b9d..c42452caef43204a7c8cefbf3e0bbd9ca4caa4f1 100644 (file)
@@ -387,6 +387,13 @@ static int tegra_fb_set_windowattr(struct tegra_fb_info *tegra_fb,
                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;
index 03749f41131f1d832a9aee3229bcae773185ac0c..a807266c05b976f0e14c1a46c7218f4c68ec2302 100644 (file)
@@ -155,19 +155,21 @@ struct pppoe_opt {
 };
 
 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>
index 22c912c5dde69545d5bb266206129f0f7bea69ec..0b612e7dba28c39e17fb26cd3fda76186ad640ff 100644 (file)
@@ -1403,7 +1403,7 @@ extern struct sk_buff **tcp4_gro_receive(struct sk_buff **head,
 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);
index b9861bc7953aecc906992431b942cbe633705d2e..6e765c5b175a19ebbaa25ff26171d6be05c85679 100644 (file)
 #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;
index 8b7dfaf3b6ea607f32db6bc1e10e24d479ffeaee..ac582d17bf409e739644488d655b76fb5d176177 100644 (file)
@@ -815,8 +815,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
                }
                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:
index 1b171b5dcf3c7c5cd4f294f3ff9c26b85252469a..886721da4888fbacfbe77edc2c52b594cacf8be7 100644 (file)
 #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>
 
@@ -3320,3 +3321,99 @@ void __init tcp_init(void)
        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;
+}
index 459eb1d24629b66eb037306118394df1ea170b1d..cb8d305cb5b4dadaae65035c5a9c37e76eed4234 100644 (file)
@@ -1967,49 +1967,6 @@ void tcp_v4_destroy_sock(struct sock *sk)
 }
 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. */
 
index 2f421a4beca750781c5be967de6a41dd3013ca27..fa743e0d32074b8cb6c029946e36e620c335c339 100644 (file)
@@ -489,6 +489,21 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
 
 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;
@@ -513,6 +528,8 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                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;