Commit 10e07b83 authored by Mauro Ribeiro's avatar Mauro Ribeiro

Merge tag 'v3.10.77' of...

Merge tag 'v3.10.77' of git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable into odroidxu3-3.10.y

This is the 3.10.77 stable release
parents 908ab16c 9182148a
VERSION = 3
PATCHLEVEL = 10
SUBLEVEL = 76
SUBLEVEL = 77
EXTRAVERSION =
NAME = TOSSUG Baby Fish
......
......@@ -116,7 +116,7 @@ int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs);
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. */
#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
/* When the program starts, a1 contains a pointer to a function to be
registered with atexit, as per the SVR4 ABI. A value of 0 means we
......
......@@ -14,6 +14,7 @@
#include <linux/gpio.h>
#define GLENFARCLAS_PMIC_IRQ_BASE IRQ_BOARD_START
#define BANFF_PMIC_IRQ_BASE (IRQ_BOARD_START + 64)
#define PCA935X_GPIO_BASE GPIO_BOARD_START
#define CODEC_GPIO_BASE (GPIO_BOARD_START + 8)
......
......@@ -558,6 +558,7 @@ static struct wm831x_touch_pdata touch_pdata = {
static struct wm831x_pdata crag_pmic_pdata = {
.wm831x_num = 1,
.irq_base = BANFF_PMIC_IRQ_BASE,
.gpio_base = BANFF_PMIC_GPIO_BASE,
.soft_shutdown = true,
......
......@@ -16,14 +16,14 @@
#ifndef __ASM_TIMEX_H
#define __ASM_TIMEX_H
#include <asm/arch_timer.h>
/*
* Use the current timer as a cycle counter since this is what we use for
* the delay loop.
*/
#define get_cycles() ({ cycles_t c; read_current_timer(&c); c; })
#define get_cycles() arch_counter_get_cntvct()
#include <asm-generic/timex.h>
#define ARCH_HAS_READ_CURRENT_TIMER
#endif
......@@ -68,12 +68,6 @@ unsigned long long notrace sched_clock(void)
return arch_timer_read_counter() * sched_clock_mult;
}
int read_current_timer(unsigned long *timer_value)
{
*timer_value = arch_timer_read_counter();
return 0;
}
void __init time_init(void)
{
u32 arch_timer_rate;
......
......@@ -49,7 +49,7 @@ u64 sched_clock(void)
return (tsc * sched_clock_multiplier) >> SCHED_CLOCK_SHIFT;
}
void time_init(void)
void __init time_init(void)
{
u64 tmp = (u64)NSEC_PER_SEC << SCHED_CLOCK_SHIFT;
......
#ifndef __ASM_SUSPEND_H
#define __ASM_SUSPEND_H
/* References to section boundaries */
extern const void __nosave_begin, __nosave_end;
#endif /* __ASM_SUSPEND_H */
......@@ -7,7 +7,7 @@
* Author: Hu Hongbing <huhb@lemote.com>
* Wu Zhangjin <wuzhangjin@gmail.com>
*/
#include <asm/suspend.h>
#include <asm/sections.h>
#include <asm/fpu.h>
#include <asm/dsp.h>
......
......@@ -30,6 +30,8 @@ LEAF(swsusp_arch_suspend)
END(swsusp_arch_suspend)
LEAF(swsusp_arch_resume)
/* Avoid TLB mismatch during and after kernel resume */
jal local_flush_tlb_all
PTR_L t0, restore_pblist
0:
PTR_L t1, PBE_ADDRESS(t0) /* source */
......@@ -43,7 +45,6 @@ LEAF(swsusp_arch_resume)
bne t1, t3, 1b
PTR_L t0, PBE_NEXT(t0)
bnez t0, 0b
jal local_flush_tlb_all /* Avoid TLB mismatch after kernel resume */
PTR_LA t0, saved_regs
PTR_L ra, PT_R31(t0)
PTR_L sp, PT_R29(t0)
......
......@@ -9,9 +9,7 @@
#include <linux/mm.h>
#include <asm/page.h>
/* References to section boundaries */
extern const void __nosave_begin, __nosave_end;
#include <asm/sections.h>
/*
* pfn_is_nosave - check if given pfn is in the 'nosave' section
......
......@@ -243,7 +243,7 @@ static void perf_callchain_user_64(struct perf_callchain_entry *entry,
sp = regs->gpr[1];
perf_callchain_store(entry, next_ip);
for (;;) {
while (entry->nr < PERF_MAX_STACK_DEPTH) {
fp = (unsigned long __user *) sp;
if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp))
return;
......
......@@ -9,12 +9,9 @@
#include <linux/pfn.h>
#include <linux/suspend.h>
#include <linux/mm.h>
#include <asm/sections.h>
#include <asm/ctl_reg.h>
/*
* References to section boundaries
*/
extern const void __nosave_begin, __nosave_end;
#include <asm/ipl.h>
/*
* The restore of the saved pages in an hibernation image will set
......@@ -138,6 +135,8 @@ int pfn_is_nosave(unsigned long pfn)
{
unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin));
unsigned long nosave_end_pfn = PFN_DOWN(__pa(&__nosave_end));
unsigned long eshared_pfn = PFN_DOWN(__pa(&_eshared)) - 1;
unsigned long stext_pfn = PFN_DOWN(__pa(&_stext));
/* Always save lowcore pages (LC protection might be enabled). */
if (pfn <= LC_PAGES)
......@@ -145,6 +144,8 @@ int pfn_is_nosave(unsigned long pfn)
if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn)
return 1;
/* Skip memory holes and read-only pages (NSS, DCSS, ...). */
if (pfn >= stext_pfn && pfn <= eshared_pfn)
return ipl_info.type == IPL_TYPE_NSS ? 1 : 0;
if (tprot(PFN_PHYS(pfn)))
return 1;
return 0;
......
......@@ -328,6 +328,7 @@ static void handle_stsi_3_2_2(struct kvm_vcpu *vcpu, struct sysinfo_3_2_2 *mem)
for (n = mem->count - 1; n > 0 ; n--)
memcpy(&mem->vm[n], &mem->vm[n - 1], sizeof(mem->vm[0]));
memset(&mem->vm[0], 0, sizeof(mem->vm[0]));
mem->vm[0].cpus_total = cpus;
mem->vm[0].cpus_configured = cpus;
mem->vm[0].cpus_standby = 0;
......
......@@ -3,7 +3,6 @@
#include <asm-generic/sections.h>
extern long __nosave_begin, __nosave_end;
extern long __machvec_start, __machvec_end;
extern char __uncached_start, __uncached_end;
extern char __start_eh_frame[], __stop_eh_frame[];
......
......@@ -9,11 +9,9 @@
#include <asm/hibernate.h>
#include <asm/visasm.h>
#include <asm/page.h>
#include <asm/sections.h>
#include <asm/tlb.h>
/* References to section boundaries */
extern const void __nosave_begin, __nosave_end;
struct saved_context saved_context;
/*
......
......@@ -36,8 +36,5 @@ extern int puv3_pm_enter(suspend_state_t state);
/* Defined in hibernate_asm.S */
extern int restore_image(pgd_t *resume_pg_dir, struct pbe *restore_pblist);
/* References to section boundaries */
extern const void __nosave_begin, __nosave_end;
extern struct pbe *restore_pblist;
#endif
......@@ -18,6 +18,7 @@
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/sections.h>
#include <asm/suspend.h>
#include "mach/pm.h"
......
......@@ -13,13 +13,11 @@
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/mmzone.h>
#include <asm/sections.h>
/* Defined in hibernate_asm_32.S */
extern int restore_image(void);
/* References to section boundaries */
extern const void __nosave_begin, __nosave_end;
/* Pointer to the temporary resume page tables */
pgd_t *resume_pg_dir;
......
......@@ -17,11 +17,9 @@
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/mtrr.h>
#include <asm/sections.h>
#include <asm/suspend.h>
/* References to section boundaries */
extern const void __nosave_begin, __nosave_end;
/* Defined in hibernate_asm_64.S */
extern int restore_image(void);
......
......@@ -287,6 +287,36 @@ menu "Executable file formats"
source "fs/Kconfig.binfmt"
config XTFPGA_LCD
bool "Enable XTFPGA LCD driver"
depends on XTENSA_PLATFORM_XTFPGA
default n
help
There's a 2x16 LCD on most of XTFPGA boards, kernel may output
progress messages there during bootup/shutdown. It may be useful
during board bringup.
If unsure, say N.
config XTFPGA_LCD_BASE_ADDR
hex "XTFPGA LCD base address"
depends on XTFPGA_LCD
default "0x0d0c0000"
help
Base address of the LCD controller inside KIO region.
Different boards from XTFPGA family have LCD controller at different
addresses. Please consult prototyping user guide for your board for
the correct address. Wrong address here may lead to hardware lockup.
config XTFPGA_LCD_8BIT_ACCESS
bool "Use 8-bit access to XTFPGA LCD"
depends on XTFPGA_LCD
default n
help
LCD may be connected with 4- or 8-bit interface, 8-bit access may
only be used with 8-bit interface. Please consult prototyping user
guide for your board for the correct interface width.
endmenu
source "net/Kconfig"
......
......@@ -715,7 +715,7 @@ __SYSCALL(323, sys_process_vm_writev, 6)
__SYSCALL(324, sys_name_to_handle_at, 5)
#define __NR_open_by_handle_at 325
__SYSCALL(325, sys_open_by_handle_at, 3)
#define __NR_sync_file_range 326
#define __NR_sync_file_range2 326
__SYSCALL(326, sys_sync_file_range2, 6)
#define __NR_perf_event_open 327
__SYSCALL(327, sys_perf_event_open, 5)
......
......@@ -6,4 +6,5 @@
#
# Note 2! The CFLAGS definitions are in the main makefile...
obj-y = setup.o lcd.o
obj-y += setup.o
obj-$(CONFIG_XTFPGA_LCD) += lcd.o
......@@ -44,9 +44,6 @@
/* UART */
#define DUART16552_PADDR (XCHAL_KIO_PADDR + 0x0D050020)
/* LCD instruction and data addresses. */
#define LCD_INSTR_ADDR ((char *)IOADDR(0x0D040000))
#define LCD_DATA_ADDR ((char *)IOADDR(0x0D040004))
/* Misc. */
#define XTFPGA_FPGAREGS_VADDR IOADDR(0x0D020000)
......
......@@ -11,10 +11,25 @@
#ifndef __XTENSA_XTAVNET_LCD_H
#define __XTENSA_XTAVNET_LCD_H
#ifdef CONFIG_XTFPGA_LCD
/* Display string STR at position POS on the LCD. */
void lcd_disp_at_pos(char *str, unsigned char pos);
/* Shift the contents of the LCD display left or right. */
void lcd_shiftleft(void);
void lcd_shiftright(void);
#else
static inline void lcd_disp_at_pos(char *str, unsigned char pos)
{
}
static inline void lcd_shiftleft(void)
{
}
static inline void lcd_shiftright(void)
{
}
#endif
#endif
/*
* Driver for the LCD display on the Tensilica LX60 Board.
* Driver for the LCD display on the Tensilica XTFPGA board family.
* http://www.mytechcorp.com/cfdata/productFile/File1/MOC-16216B-B-A0A04.pdf
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2001, 2006 Tensilica Inc.
* Copyright (C) 2015 Cadence Design Systems Inc.
*/
/*
*
* FIXME: this code is from the examples from the LX60 user guide.
*
* The lcd_pause function does busy waiting, which is probably not
* great. Maybe the code could be changed to use kernel timers, or
* change the hardware to not need to wait.
*/
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <platform/hardware.h>
#include <platform/lcd.h>
#include <linux/delay.h>
#define LCD_PAUSE_ITERATIONS 4000
/* LCD instruction and data addresses. */
#define LCD_INSTR_ADDR ((char *)IOADDR(CONFIG_XTFPGA_LCD_BASE_ADDR))
#define LCD_DATA_ADDR (LCD_INSTR_ADDR + 4)
#define LCD_CLEAR 0x1
#define LCD_DISPLAY_ON 0xc
/* 8bit and 2 lines display */
#define LCD_DISPLAY_MODE8BIT 0x38
#define LCD_DISPLAY_MODE4BIT 0x28
#define LCD_DISPLAY_POS 0x80
#define LCD_SHIFT_LEFT 0x18
#define LCD_SHIFT_RIGHT 0x1c
static void lcd_put_byte(u8 *addr, u8 data)
{
#ifdef CONFIG_XTFPGA_LCD_8BIT_ACCESS
ACCESS_ONCE(*addr) = data;
#else
ACCESS_ONCE(*addr) = data & 0xf0;
ACCESS_ONCE(*addr) = (data << 4) & 0xf0;
#endif
}
static int __init lcd_init(void)
{
*LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT;
ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT;
mdelay(5);
*LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT;
ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT;
udelay(200);
*LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT;
ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT;
udelay(50);
#ifndef CONFIG_XTFPGA_LCD_8BIT_ACCESS
ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE4BIT;
udelay(50);
lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_MODE4BIT);
udelay(50);
*LCD_INSTR_ADDR = LCD_DISPLAY_ON;
#endif
lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_ON);
udelay(50);
*LCD_INSTR_ADDR = LCD_CLEAR;
lcd_put_byte(LCD_INSTR_ADDR, LCD_CLEAR);
mdelay(10);
lcd_disp_at_pos("XTENSA LINUX", 0);
return 0;
......@@ -52,10 +65,10 @@ static int __init lcd_init(void)
void lcd_disp_at_pos(char *str, unsigned char pos)
{
*LCD_INSTR_ADDR = LCD_DISPLAY_POS | pos;
lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_POS | pos);
udelay(100);
while (*str != 0) {
*LCD_DATA_ADDR = *str;
lcd_put_byte(LCD_DATA_ADDR, *str);
udelay(200);
str++;
}
......@@ -63,13 +76,13 @@ void lcd_disp_at_pos(char *str, unsigned char pos)
void lcd_shiftleft(void)
{
*LCD_INSTR_ADDR = LCD_SHIFT_LEFT;
lcd_put_byte(LCD_INSTR_ADDR, LCD_SHIFT_LEFT);
udelay(50);
}
void lcd_shiftright(void)
{
*LCD_INSTR_ADDR = LCD_SHIFT_RIGHT;
lcd_put_byte(LCD_INSTR_ADDR, LCD_SHIFT_RIGHT);
udelay(50);
}
......
......@@ -1543,6 +1543,7 @@ enum punit_power_well {
#define GMBUS_CYCLE_INDEX (2<<25)
#define GMBUS_CYCLE_STOP (4<<25)
#define GMBUS_BYTE_COUNT_SHIFT 16
#define GMBUS_BYTE_COUNT_MAX 256U
#define GMBUS_SLAVE_INDEX_SHIFT 8
#define GMBUS_SLAVE_ADDR_SHIFT 1
#define GMBUS_SLAVE_READ (1<<0)
......
......@@ -324,18 +324,17 @@ gmbus_wait_idle(struct drm_i915_private *dev_priv)
}
static int
gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
u32 gmbus1_index)
gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv,
unsigned short addr, u8 *buf, unsigned int len,
u32 gmbus1_index)
{
int reg_offset = dev_priv->gpio_mmio_base;
u16 len = msg->len;
u8 *buf = msg->buf;
I915_WRITE(GMBUS1 + reg_offset,
gmbus1_index |
GMBUS_CYCLE_WAIT |
(len << GMBUS_BYTE_COUNT_SHIFT) |
(msg->addr << GMBUS_SLAVE_ADDR_SHIFT) |
(addr << GMBUS_SLAVE_ADDR_SHIFT) |
GMBUS_SLAVE_READ | GMBUS_SW_RDY);
while (len) {
int ret;
......@@ -357,11 +356,35 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
}
static int
gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
u32 gmbus1_index)
{
int reg_offset = dev_priv->gpio_mmio_base;
u16 len = msg->len;
u8 *buf = msg->buf;
unsigned int rx_size = msg->len;
unsigned int len;
int ret;
do {
len = min(rx_size, GMBUS_BYTE_COUNT_MAX);
ret = gmbus_xfer_read_chunk(dev_priv, msg->addr,
buf, len, gmbus1_index);
if (ret)
return ret;
rx_size -= len;
buf += len;
} while (rx_size != 0);
return 0;
}
static int
gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
unsigned short addr, u8 *buf, unsigned int len)
{
int reg_offset = dev_priv->gpio_mmio_base;
unsigned int chunk_size = len;
u32 val, loop;
val = loop = 0;
......@@ -373,8 +396,8 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
I915_WRITE(GMBUS3 + reg_offset, val);
I915_WRITE(GMBUS1 + reg_offset,
GMBUS_CYCLE_WAIT |
(msg->len << GMBUS_BYTE_COUNT_SHIFT) |
(msg->addr << GMBUS_SLAVE_ADDR_SHIFT) |
(chunk_size << GMBUS_BYTE_COUNT_SHIFT) |
(addr << GMBUS_SLAVE_ADDR_SHIFT) |
GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
while (len) {
int ret;
......@@ -391,6 +414,29 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
if (ret)
return ret;
}
return 0;
}
static int
gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
{
u8 *buf = msg->buf;
unsigned int tx_size = msg->len;
unsigned int len;
int ret;
do {
len = min(tx_size, GMBUS_BYTE_COUNT_MAX);
ret = gmbus_xfer_write_chunk(dev_priv, msg->addr, buf, len);
if (ret)
return ret;
buf += len;
tx_size -= len;
} while (tx_size != 0);
return 0;
}
......
......@@ -330,8 +330,10 @@ atombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
misc |= ATOM_COMPOSITESYNC;
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
misc |= ATOM_INTERLACE;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
misc |= ATOM_DOUBLE_CLOCK_MODE;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2;
args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
args.ucCRTC = radeon_crtc->crtc_id;
......@@ -374,8 +376,10 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc,
misc |= ATOM_COMPOSITESYNC;
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
misc |= ATOM_INTERLACE;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
misc |= ATOM_DOUBLE_CLOCK_MODE;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2;
args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
args.ucCRTC = radeon_crtc->crtc_id;
......
......@@ -169,7 +169,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
GFP_KERNEL);
if (!open_info) {
err = -ENOMEM;
goto error0;
goto error_gpadl;
}
init_completion(&open_info->waitevent);
......@@ -185,7 +185,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
if (userdatalen > MAX_USER_DEFINED_BYTES) {
err = -EINVAL;
goto error0;
goto error_gpadl;
}
if (userdatalen)
......@@ -226,6 +226,9 @@ error1:
list_del(&open_info->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
error_gpadl:
vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle);
error0:
free_pages((unsigned long)out,
get_order(send_ringbuffer_size + recv_ringbuffer_size));
......
......@@ -206,6 +206,7 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap)
adap->bus_recovery_info->set_scl(adap, 1);
return i2c_generic_recovery(adap);
}
EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery);
int i2c_generic_gpio_recovery(struct i2c_adapter *adap)
{
......@@ -220,6 +221,7 @@ int i2c_generic_gpio_recovery(struct i2c_adapter *adap)
return ret;
}
EXPORT_SYMBOL_GPL(i2c_generic_gpio_recovery);
int i2c_recover_bus(struct i2c_adapter *adap)
{
......@@ -229,6 +231,7 @@ int i2c_recover_bus(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "Trying i2c bus recovery\n");
return adap->bus_recovery_info->recover_bus(adap);
}
EXPORT_SYMBOL_GPL(i2c_recover_bus);
static int i2c_device_probe(struct device *dev)
{
......
......@@ -94,12 +94,15 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
if (dmasync)
dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs);
if (!size)
return ERR_PTR(-EINVAL);
/*
* If the combination of the addr and size requested for this memory
* region causes an integer overflow, return error.
*/
if ((PAGE_ALIGN(addr + size) <= size) ||
(PAGE_ALIGN(addr + size) <= addr))
if (((addr + size) < addr) ||
PAGE_ALIGN(addr + size) < (addr + size))
return ERR_PTR(-EINVAL);
if (!can_do_mlock())
......
......@@ -2174,8 +2174,7 @@ static int build_lso_seg(struct mlx4_wqe_lso_seg *wqe, struct ib_send_wr *wr,
memcpy(wqe->header, wr->wr.ud.header, wr->wr.ud.hlen);
*lso_hdr_sz = cpu_to_be32((wr->wr.ud.mss - wr->wr.ud.hlen) << 16 |
wr->wr.ud.hlen);
*lso_hdr_sz = cpu_to_be32(wr->wr.ud.mss << 16 | wr->wr.ud.hlen);
*lso_seg_len = halign;
return 0;
}
......
......@@ -783,6 +783,21 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
return PSMOUSE_FULL_PACKET;
}
/*
* This writes the reg_07 value again to the hardware at the end of every
* set_rate call because the register loses its value. reg_07 allows setting
* absolute mode on v4 hardware
*/
static void elantech_set_rate_restore_reg_07(struct psmouse *psmouse,
unsigned int rate)
{
struct elantech_data *etd = psmouse->private;
etd->original_set_rate(psmouse, rate);
if (elantech_write_reg(psmouse, 0x07, etd->reg_07))
psmouse_err(psmouse, "restoring reg_07 failed\n");
}
/*
* Put the touchpad into absolute mode
*/
......@@ -985,6 +1000,8 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
* Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons
* Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons
* Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons
* Asus TP500LN 0x381f17 10, 14, 0e clickpad
* Asus X750JN 0x381f17 10, 14, 0e clickpad
* Asus UX31 0x361f00 20, 15, 0e clickpad
* Asus UX32VD 0x361f02 00, 15, 0e clickpad
* Avatar AVIU-145A2 0x361f00 ? clickpad
......@@ -1452,6 +1469,11 @@ int elantech_init(struct psmouse *psmouse)
goto init_fail;
}
if (etd->fw_version == 0x381f17) {
etd->original_set_rate = psmouse->set_rate;
psmouse->set_rate = elantech_set_rate_restore_reg_07;
}
if (elantech_set_input_params(psmouse)) {
psmouse_err(psmouse, "failed to query touchpad range.\n");
goto init_fail;
......
......@@ -138,6 +138,7 @@ struct elantech_data {
struct finger_pos mt[ETP_MAX_FINGERS];
unsigned char parity[256];
int (*send_cmd)(struct psmouse *psmouse, unsigned char c, unsigned char *param);
void (*original_set_rate)(struct psmouse *psmouse, unsigned int rate);
};