Merge branch 'next' into for-linus
Prepare input updates for 4.19 merge window.
这个提交包含在:
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
@@ -481,7 +481,7 @@ static int evdev_release(struct inode *inode, struct file *file)
|
||||
evdev_detach_client(evdev, client);
|
||||
|
||||
for (i = 0; i < EV_CNT; ++i)
|
||||
kfree(client->evmasks[i]);
|
||||
bitmap_free(client->evmasks[i]);
|
||||
|
||||
kvfree(client);
|
||||
|
||||
@@ -925,17 +925,15 @@ static int evdev_handle_get_val(struct evdev_client *client,
|
||||
{
|
||||
int ret;
|
||||
unsigned long *mem;
|
||||
size_t len;
|
||||
|
||||
len = BITS_TO_LONGS(maxbit) * sizeof(unsigned long);
|
||||
mem = kmalloc(len, GFP_KERNEL);
|
||||
mem = bitmap_alloc(maxbit, GFP_KERNEL);
|
||||
if (!mem)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_irq(&dev->event_lock);
|
||||
spin_lock(&client->buffer_lock);
|
||||
|
||||
memcpy(mem, bits, len);
|
||||
bitmap_copy(mem, bits, maxbit);
|
||||
|
||||
spin_unlock(&dev->event_lock);
|
||||
|
||||
@@ -947,7 +945,7 @@ static int evdev_handle_get_val(struct evdev_client *client,
|
||||
if (ret < 0)
|
||||
evdev_queue_syn_dropped(client);
|
||||
|
||||
kfree(mem);
|
||||
bitmap_free(mem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1003,13 +1001,13 @@ static int evdev_set_mask(struct evdev_client *client,
|
||||
if (!cnt)
|
||||
return 0;
|
||||
|
||||
mask = kcalloc(sizeof(unsigned long), BITS_TO_LONGS(cnt), GFP_KERNEL);
|
||||
mask = bitmap_zalloc(cnt, GFP_KERNEL);
|
||||
if (!mask)
|
||||
return -ENOMEM;
|
||||
|
||||
error = bits_from_user(mask, cnt - 1, codes_size, codes, compat);
|
||||
if (error < 0) {
|
||||
kfree(mask);
|
||||
bitmap_free(mask);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -1018,7 +1016,7 @@ static int evdev_set_mask(struct evdev_client *client,
|
||||
client->evmasks[type] = mask;
|
||||
spin_unlock_irqrestore(&client->buffer_lock, flags);
|
||||
|
||||
kfree(oldmask);
|
||||
bitmap_free(oldmask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
|
@@ -21,10 +21,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
|
@@ -480,11 +480,19 @@ EXPORT_SYMBOL(input_inject_event);
|
||||
*/
|
||||
void input_alloc_absinfo(struct input_dev *dev)
|
||||
{
|
||||
if (!dev->absinfo)
|
||||
dev->absinfo = kcalloc(ABS_CNT, sizeof(*dev->absinfo),
|
||||
GFP_KERNEL);
|
||||
if (dev->absinfo)
|
||||
return;
|
||||
|
||||
WARN(!dev->absinfo, "%s(): kcalloc() failed?\n", __func__);
|
||||
dev->absinfo = kcalloc(ABS_CNT, sizeof(*dev->absinfo), GFP_KERNEL);
|
||||
if (!dev->absinfo) {
|
||||
dev_err(dev->dev.parent ?: &dev->dev,
|
||||
"%s: unable to allocate memory\n", __func__);
|
||||
/*
|
||||
* We will handle this allocation failure in
|
||||
* input_register_device() when we refuse to register input
|
||||
* device with ABS bits but without absinfo.
|
||||
*/
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(input_alloc_absinfo);
|
||||
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@@ -23,10 +23,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@@ -263,6 +259,7 @@ static unsigned char db9_saturn_read_packet(struct parport *port, unsigned char
|
||||
db9_saturn_write_sub(port, type, 3, powered, 0);
|
||||
return data[0] = 0xe3;
|
||||
}
|
||||
/* else: fall through */
|
||||
default:
|
||||
return data[0];
|
||||
}
|
||||
@@ -282,11 +279,14 @@ static int db9_saturn_report(unsigned char id, unsigned char data[60], struct in
|
||||
switch (data[j]) {
|
||||
case 0x16: /* multi controller (analog 4 axis) */
|
||||
input_report_abs(dev, db9_abs[5], data[j + 6]);
|
||||
/* fall through */
|
||||
case 0x15: /* mission stick (analog 3 axis) */
|
||||
input_report_abs(dev, db9_abs[3], data[j + 4]);
|
||||
input_report_abs(dev, db9_abs[4], data[j + 5]);
|
||||
/* fall through */
|
||||
case 0x13: /* racing controller (analog 1 axis) */
|
||||
input_report_abs(dev, db9_abs[2], data[j + 3]);
|
||||
/* fall through */
|
||||
case 0x34: /* saturn keyboard (udlr ZXC ASD QE Esc) */
|
||||
case 0x02: /* digital pad (digital 2 axis + buttons) */
|
||||
input_report_abs(dev, db9_abs[0], !(data[j + 1] & 128) - !(data[j + 1] & 64));
|
||||
@@ -380,6 +380,7 @@ static void db9_timer(struct timer_list *t)
|
||||
input_report_abs(dev2, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
|
||||
input_report_abs(dev2, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
|
||||
input_report_key(dev2, BTN_TRIGGER, ~data & DB9_FIRE1);
|
||||
/* fall through */
|
||||
|
||||
case DB9_MULTI_0802:
|
||||
|
||||
|
@@ -24,10 +24,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@@ -19,10 +19,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include "iforce.h"
|
||||
@@ -56,7 +52,7 @@ static int make_magnitude_modifier(struct iforce* iforce,
|
||||
|
||||
iforce_send_packet(iforce, FF_CMD_MAGNITUDE, data);
|
||||
|
||||
iforce_dump_packet("magnitude: ", FF_CMD_MAGNITUDE, data);
|
||||
iforce_dump_packet(iforce, "magnitude", FF_CMD_MAGNITUDE, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -178,7 +174,7 @@ static int make_condition_modifier(struct iforce* iforce,
|
||||
data[9] = (100 * lsat) >> 16;
|
||||
|
||||
iforce_send_packet(iforce, FF_CMD_CONDITION, data);
|
||||
iforce_dump_packet("condition", FF_CMD_CONDITION, data);
|
||||
iforce_dump_packet(iforce, "condition", FF_CMD_CONDITION, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -19,10 +19,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include "iforce.h"
|
||||
@@ -33,21 +29,14 @@ MODULE_LICENSE("GPL");
|
||||
|
||||
static signed short btn_joystick[] =
|
||||
{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
|
||||
BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 };
|
||||
BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A,
|
||||
BTN_B, BTN_C, BTN_DEAD, -1 };
|
||||
|
||||
static signed short btn_avb_pegasus[] =
|
||||
{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
|
||||
BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 };
|
||||
static signed short btn_joystick_avb[] =
|
||||
{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE,
|
||||
BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_DEAD, -1 };
|
||||
|
||||
static signed short btn_wheel[] =
|
||||
{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
|
||||
BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 };
|
||||
|
||||
static signed short btn_avb_tw[] =
|
||||
{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE,
|
||||
BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 };
|
||||
|
||||
static signed short btn_avb_wheel[] =
|
||||
{ BTN_GEAR_DOWN, BTN_GEAR_UP, BTN_BASE, BTN_BASE2, BTN_BASE3,
|
||||
BTN_BASE4, BTN_BASE5, BTN_BASE6, -1 };
|
||||
|
||||
@@ -73,9 +62,9 @@ static struct iforce_device iforce_device[] = {
|
||||
{ 0x044f, 0xa01c, "Thrustmaster Motor Sport GT", btn_wheel, abs_wheel, ff_iforce },
|
||||
{ 0x046d, 0xc281, "Logitech WingMan Force", btn_joystick, abs_joystick, ff_iforce },
|
||||
{ 0x046d, 0xc291, "Logitech WingMan Formula Force", btn_wheel, abs_wheel, ff_iforce },
|
||||
{ 0x05ef, 0x020a, "AVB Top Shot Pegasus", btn_avb_pegasus, abs_avb_pegasus, ff_iforce },
|
||||
{ 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_avb_wheel, abs_wheel, ff_iforce },
|
||||
{ 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel", btn_avb_tw, abs_wheel, ff_iforce }, //?
|
||||
{ 0x05ef, 0x020a, "AVB Top Shot Pegasus", btn_joystick_avb, abs_avb_pegasus, ff_iforce },
|
||||
{ 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_wheel, abs_wheel, ff_iforce },
|
||||
{ 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //?
|
||||
{ 0x061c, 0xc0a4, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //?
|
||||
{ 0x061c, 0xc084, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce },
|
||||
{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //?
|
||||
@@ -360,7 +349,7 @@ int iforce_init_device(struct iforce *iforce)
|
||||
|
||||
for (i = 0; c[i]; i++)
|
||||
if (!iforce_get_id_packet(iforce, c + i))
|
||||
iforce_dump_packet("info", iforce->ecmd, iforce->edata);
|
||||
iforce_dump_packet(iforce, "info", iforce->ecmd, iforce->edata);
|
||||
|
||||
/*
|
||||
* Disable spring, enable force feedback.
|
||||
@@ -388,7 +377,6 @@ int iforce_init_device(struct iforce *iforce)
|
||||
|
||||
for (i = 0; iforce->type->btn[i] >= 0; i++)
|
||||
set_bit(iforce->type->btn[i], input_dev->keybit);
|
||||
set_bit(BTN_DEAD, input_dev->keybit);
|
||||
|
||||
for (i = 0; iforce->type->abs[i] >= 0; i++) {
|
||||
|
||||
|
@@ -19,10 +19,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include "iforce.h"
|
||||
@@ -33,14 +29,10 @@ static struct {
|
||||
} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
|
||||
|
||||
|
||||
void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data)
|
||||
void iforce_dump_packet(struct iforce *iforce, char *msg, u16 cmd, unsigned char *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
printk(KERN_DEBUG __FILE__ ": %s cmd = %04x, data = ", msg, cmd);
|
||||
for (i = 0; i < LO(cmd); i++)
|
||||
printk("%02x ", data[i]);
|
||||
printk("\n");
|
||||
dev_dbg(iforce->dev->dev.parent, "%s %s cmd = %04x, data = %*ph\n",
|
||||
__func__, msg, cmd, LO(cmd), data);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -255,7 +247,7 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
|
||||
iforce->cr.bRequest = packet[0];
|
||||
iforce->ctrl->dev = iforce->usbdev;
|
||||
|
||||
status = usb_submit_urb(iforce->ctrl, GFP_ATOMIC);
|
||||
status = usb_submit_urb(iforce->ctrl, GFP_KERNEL);
|
||||
if (status) {
|
||||
dev_err(&iforce->intf->dev,
|
||||
"usb_submit_urb failed %d\n", status);
|
||||
|
@@ -19,10 +19,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include "iforce.h"
|
||||
|
@@ -19,10 +19,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include "iforce.h"
|
||||
|
@@ -19,10 +19,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@@ -158,7 +154,7 @@ int iforce_init_device(struct iforce *iforce);
|
||||
int iforce_control_playback(struct iforce*, u16 id, unsigned int);
|
||||
void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data);
|
||||
int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data);
|
||||
void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ;
|
||||
void iforce_dump_packet(struct iforce *iforce, char *msg, u16 cmd, unsigned char *data);
|
||||
int iforce_get_id_packet(struct iforce *iforce, char *packet);
|
||||
|
||||
/* iforce-ff.c */
|
||||
|
@@ -23,10 +23,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@@ -21,10 +21,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@@ -3,7 +3,6 @@
|
||||
* Driver for Phoenix RC Flight Controller Adapter
|
||||
*
|
||||
* Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@@ -16,31 +15,22 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#define PXRC_VENDOR_ID (0x1781)
|
||||
#define PXRC_PRODUCT_ID (0x0898)
|
||||
|
||||
static const struct usb_device_id pxrc_table[] = {
|
||||
{ USB_DEVICE(PXRC_VENDOR_ID, PXRC_PRODUCT_ID) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, pxrc_table);
|
||||
#define PXRC_VENDOR_ID 0x1781
|
||||
#define PXRC_PRODUCT_ID 0x0898
|
||||
|
||||
struct pxrc {
|
||||
struct input_dev *input;
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *intf;
|
||||
struct urb *urb;
|
||||
struct mutex pm_mutex;
|
||||
bool is_open;
|
||||
__u8 epaddr;
|
||||
char phys[64];
|
||||
unsigned char *data;
|
||||
size_t bsize;
|
||||
};
|
||||
|
||||
static void pxrc_usb_irq(struct urb *urb)
|
||||
{
|
||||
struct pxrc *pxrc = urb->context;
|
||||
u8 *data = urb->transfer_buffer;
|
||||
int error;
|
||||
|
||||
switch (urb->status) {
|
||||
@@ -68,15 +58,15 @@ static void pxrc_usb_irq(struct urb *urb)
|
||||
}
|
||||
|
||||
if (urb->actual_length == 8) {
|
||||
input_report_abs(pxrc->input, ABS_X, pxrc->data[0]);
|
||||
input_report_abs(pxrc->input, ABS_Y, pxrc->data[2]);
|
||||
input_report_abs(pxrc->input, ABS_RX, pxrc->data[3]);
|
||||
input_report_abs(pxrc->input, ABS_RY, pxrc->data[4]);
|
||||
input_report_abs(pxrc->input, ABS_RUDDER, pxrc->data[5]);
|
||||
input_report_abs(pxrc->input, ABS_THROTTLE, pxrc->data[6]);
|
||||
input_report_abs(pxrc->input, ABS_MISC, pxrc->data[7]);
|
||||
input_report_abs(pxrc->input, ABS_X, data[0]);
|
||||
input_report_abs(pxrc->input, ABS_Y, data[2]);
|
||||
input_report_abs(pxrc->input, ABS_RX, data[3]);
|
||||
input_report_abs(pxrc->input, ABS_RY, data[4]);
|
||||
input_report_abs(pxrc->input, ABS_RUDDER, data[5]);
|
||||
input_report_abs(pxrc->input, ABS_THROTTLE, data[6]);
|
||||
input_report_abs(pxrc->input, ABS_MISC, data[7]);
|
||||
|
||||
input_report_key(pxrc->input, BTN_A, pxrc->data[1]);
|
||||
input_report_key(pxrc->input, BTN_A, data[1]);
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -120,61 +110,73 @@ static void pxrc_close(struct input_dev *input)
|
||||
mutex_unlock(&pxrc->pm_mutex);
|
||||
}
|
||||
|
||||
static int pxrc_usb_init(struct pxrc *pxrc)
|
||||
static void pxrc_free_urb(void *_pxrc)
|
||||
{
|
||||
struct usb_endpoint_descriptor *epirq;
|
||||
unsigned int pipe;
|
||||
int retval;
|
||||
|
||||
/* Set up the endpoint information */
|
||||
/* This device only has an interrupt endpoint */
|
||||
retval = usb_find_common_endpoints(pxrc->intf->cur_altsetting,
|
||||
NULL, NULL, &epirq, NULL);
|
||||
if (retval) {
|
||||
dev_err(&pxrc->intf->dev,
|
||||
"Could not find endpoint\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
pxrc->bsize = usb_endpoint_maxp(epirq);
|
||||
pxrc->epaddr = epirq->bEndpointAddress;
|
||||
pxrc->data = devm_kmalloc(&pxrc->intf->dev, pxrc->bsize, GFP_KERNEL);
|
||||
if (!pxrc->data) {
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
usb_set_intfdata(pxrc->intf, pxrc);
|
||||
usb_make_path(pxrc->udev, pxrc->phys, sizeof(pxrc->phys));
|
||||
strlcat(pxrc->phys, "/input0", sizeof(pxrc->phys));
|
||||
|
||||
pxrc->urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!pxrc->urb) {
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
pipe = usb_rcvintpipe(pxrc->udev, pxrc->epaddr),
|
||||
usb_fill_int_urb(pxrc->urb, pxrc->udev, pipe, pxrc->data, pxrc->bsize,
|
||||
pxrc_usb_irq, pxrc, 1);
|
||||
|
||||
error:
|
||||
return retval;
|
||||
|
||||
struct pxrc *pxrc = _pxrc;
|
||||
|
||||
usb_free_urb(pxrc->urb);
|
||||
}
|
||||
|
||||
static int pxrc_input_init(struct pxrc *pxrc)
|
||||
static int pxrc_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
pxrc->input = devm_input_allocate_device(&pxrc->intf->dev);
|
||||
if (pxrc->input == NULL) {
|
||||
dev_err(&pxrc->intf->dev, "couldn't allocate input device\n");
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
struct pxrc *pxrc;
|
||||
struct usb_endpoint_descriptor *epirq;
|
||||
size_t xfer_size;
|
||||
void *xfer_buf;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Locate the endpoint information. This device only has an
|
||||
* interrupt endpoint.
|
||||
*/
|
||||
error = usb_find_common_endpoints(intf->cur_altsetting,
|
||||
NULL, NULL, &epirq, NULL);
|
||||
if (error) {
|
||||
dev_err(&intf->dev, "Could not find endpoint\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
pxrc = devm_kzalloc(&intf->dev, sizeof(*pxrc), GFP_KERNEL);
|
||||
if (!pxrc)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&pxrc->pm_mutex);
|
||||
pxrc->intf = intf;
|
||||
|
||||
usb_set_intfdata(pxrc->intf, pxrc);
|
||||
|
||||
xfer_size = usb_endpoint_maxp(epirq);
|
||||
xfer_buf = devm_kmalloc(&intf->dev, xfer_size, GFP_KERNEL);
|
||||
if (!xfer_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
pxrc->urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!pxrc->urb)
|
||||
return -ENOMEM;
|
||||
|
||||
error = devm_add_action_or_reset(&intf->dev, pxrc_free_urb, pxrc);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
usb_fill_int_urb(pxrc->urb, udev,
|
||||
usb_rcvintpipe(udev, epirq->bEndpointAddress),
|
||||
xfer_buf, xfer_size, pxrc_usb_irq, pxrc, 1);
|
||||
|
||||
pxrc->input = devm_input_allocate_device(&intf->dev);
|
||||
if (!pxrc->input) {
|
||||
dev_err(&intf->dev, "couldn't allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pxrc->input->name = "PXRC Flight Controller Adapter";
|
||||
|
||||
usb_make_path(udev, pxrc->phys, sizeof(pxrc->phys));
|
||||
strlcat(pxrc->phys, "/input0", sizeof(pxrc->phys));
|
||||
pxrc->input->phys = pxrc->phys;
|
||||
usb_to_input_id(pxrc->udev, &pxrc->input->id);
|
||||
|
||||
usb_to_input_id(udev, &pxrc->input->id);
|
||||
|
||||
pxrc->input->open = pxrc_open;
|
||||
pxrc->input->close = pxrc_close;
|
||||
@@ -190,46 +192,16 @@ static int pxrc_input_init(struct pxrc *pxrc)
|
||||
|
||||
input_set_drvdata(pxrc->input, pxrc);
|
||||
|
||||
return input_register_device(pxrc->input);
|
||||
}
|
||||
|
||||
static int pxrc_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct pxrc *pxrc;
|
||||
int retval;
|
||||
|
||||
pxrc = devm_kzalloc(&intf->dev, sizeof(*pxrc), GFP_KERNEL);
|
||||
if (!pxrc)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&pxrc->pm_mutex);
|
||||
pxrc->udev = usb_get_dev(interface_to_usbdev(intf));
|
||||
pxrc->intf = intf;
|
||||
|
||||
retval = pxrc_usb_init(pxrc);
|
||||
if (retval)
|
||||
goto error;
|
||||
|
||||
retval = pxrc_input_init(pxrc);
|
||||
if (retval)
|
||||
goto err_free_urb;
|
||||
error = input_register_device(pxrc->input);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_urb:
|
||||
usb_free_urb(pxrc->urb);
|
||||
|
||||
error:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void pxrc_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct pxrc *pxrc = usb_get_intfdata(intf);
|
||||
|
||||
usb_free_urb(pxrc->urb);
|
||||
usb_set_intfdata(intf, NULL);
|
||||
/* All driver resources are devm-managed. */
|
||||
}
|
||||
|
||||
static int pxrc_suspend(struct usb_interface *intf, pm_message_t message)
|
||||
@@ -284,6 +256,12 @@ static int pxrc_reset_resume(struct usb_interface *intf)
|
||||
return pxrc_resume(intf);
|
||||
}
|
||||
|
||||
static const struct usb_device_id pxrc_table[] = {
|
||||
{ USB_DEVICE(PXRC_VENDOR_ID, PXRC_PRODUCT_ID) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, pxrc_table);
|
||||
|
||||
static struct usb_driver pxrc_driver = {
|
||||
.name = "pxrc",
|
||||
.probe = pxrc_probe,
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
@@ -24,10 +24,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@@ -23,10 +23,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@@ -21,10 +21,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@@ -23,10 +23,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
@@ -23,10 +23,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@@ -885,6 +885,7 @@ static int adp5589_probe(struct i2c_client *client,
|
||||
switch (id->driver_data) {
|
||||
case ADP5585_02:
|
||||
kpad->support_row5 = true;
|
||||
/* fall through */
|
||||
case ADP5585_01:
|
||||
kpad->is_adp5585 = true;
|
||||
kpad->var = &const_adp5585;
|
||||
|
@@ -23,10 +23,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@@ -34,10 +34,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@@ -1,25 +1,15 @@
|
||||
/*
|
||||
* ChromeOS EC keyboard driver
|
||||
*
|
||||
* Copyright (C) 2012 Google, Inc
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This driver uses the Chrome OS EC byte-level message-based protocol for
|
||||
* communicating the keyboard state (which keys are pressed) from a keyboard EC
|
||||
* to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing,
|
||||
* but everything else (including deghosting) is done here. The main
|
||||
* motivation for this is to keep the EC firmware as simple as possible, since
|
||||
* it cannot be easily upgraded and EC flash/IRAM space is relatively
|
||||
* expensive.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// ChromeOS EC keyboard driver
|
||||
//
|
||||
// Copyright (C) 2012 Google, Inc.
|
||||
//
|
||||
// This driver uses the ChromeOS EC byte-level message-based protocol for
|
||||
// communicating the keyboard state (which keys are pressed) from a keyboard EC
|
||||
// to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing,
|
||||
// but everything else (including deghosting) is done here. The main
|
||||
// motivation for this is to keep the EC firmware as simple as possible, since
|
||||
// it cannot be easily upgraded and EC flash/IRAM space is relatively
|
||||
// expensive.
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/bitops.h>
|
||||
@@ -170,9 +160,6 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev,
|
||||
int col, row;
|
||||
int new_state;
|
||||
int old_state;
|
||||
int num_cols;
|
||||
|
||||
num_cols = len;
|
||||
|
||||
if (ckdev->ghost_filter && cros_ec_keyb_has_ghosting(ckdev, kb_state)) {
|
||||
/*
|
||||
@@ -242,19 +229,17 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
|
||||
u32 val;
|
||||
unsigned int ev_type;
|
||||
|
||||
/*
|
||||
* If not wake enabled, discard key state changes during
|
||||
* suspend. Switches will be re-checked in
|
||||
* cros_ec_keyb_resume() to be sure nothing is lost.
|
||||
*/
|
||||
if (queued_during_suspend && !device_may_wakeup(ckdev->dev))
|
||||
return NOTIFY_OK;
|
||||
|
||||
switch (ckdev->ec->event_data.event_type) {
|
||||
case EC_MKBP_EVENT_KEY_MATRIX:
|
||||
if (device_may_wakeup(ckdev->dev)) {
|
||||
pm_wakeup_event(ckdev->dev, 0);
|
||||
} else {
|
||||
/*
|
||||
* If keyboard is not wake enabled, discard key state
|
||||
* changes during suspend. Switches will be re-checked
|
||||
* in cros_ec_keyb_resume() to be sure nothing is lost.
|
||||
*/
|
||||
if (queued_during_suspend)
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
pm_wakeup_event(ckdev->dev, 0);
|
||||
|
||||
if (ckdev->ec->event_size != ckdev->cols) {
|
||||
dev_err(ckdev->dev,
|
||||
@@ -268,10 +253,7 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
|
||||
break;
|
||||
|
||||
case EC_MKBP_EVENT_SYSRQ:
|
||||
if (device_may_wakeup(ckdev->dev))
|
||||
pm_wakeup_event(ckdev->dev, 0);
|
||||
else if (queued_during_suspend)
|
||||
return NOTIFY_OK;
|
||||
pm_wakeup_event(ckdev->dev, 0);
|
||||
|
||||
val = get_unaligned_le32(&ckdev->ec->event_data.data.sysrq);
|
||||
dev_dbg(ckdev->dev, "sysrq code from EC: %#x\n", val);
|
||||
@@ -280,10 +262,7 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
|
||||
|
||||
case EC_MKBP_EVENT_BUTTON:
|
||||
case EC_MKBP_EVENT_SWITCH:
|
||||
if (device_may_wakeup(ckdev->dev))
|
||||
pm_wakeup_event(ckdev->dev, 0);
|
||||
else if (queued_during_suspend)
|
||||
return NOTIFY_OK;
|
||||
pm_wakeup_event(ckdev->dev, 0);
|
||||
|
||||
if (ckdev->ec->event_data.event_type == EC_MKBP_EVENT_BUTTON) {
|
||||
val = get_unaligned_le32(
|
||||
@@ -683,6 +662,6 @@ static struct platform_driver cros_ec_keyb_driver = {
|
||||
|
||||
module_platform_driver(cros_ec_keyb_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("ChromeOS EC keyboard driver");
|
||||
MODULE_ALIAS("platform:cros-ec-keyb");
|
||||
|
@@ -196,7 +196,7 @@ static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
|
||||
ssize_t ret;
|
||||
int i;
|
||||
|
||||
bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
|
||||
bits = bitmap_zalloc(n_events, GFP_KERNEL);
|
||||
if (!bits)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -216,7 +216,7 @@ static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
|
||||
buf[ret++] = '\n';
|
||||
buf[ret] = '\0';
|
||||
|
||||
kfree(bits);
|
||||
bitmap_free(bits);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -240,7 +240,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
|
||||
ssize_t error;
|
||||
int i;
|
||||
|
||||
bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
|
||||
bits = bitmap_zalloc(n_events, GFP_KERNEL);
|
||||
if (!bits)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -284,7 +284,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
|
||||
mutex_unlock(&ddata->disable_lock);
|
||||
|
||||
out:
|
||||
kfree(bits);
|
||||
bitmap_free(bits);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@@ -1,11 +1,7 @@
|
||||
/*
|
||||
* Driver for the IMX keypad port.
|
||||
* Copyright (C) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Driver for the IMX keypad port.
|
||||
// Copyright (C) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <j.cormack@doc.ic.ac.uk>, or by paper mail:
|
||||
* Justin Cormack, 68 Dartmouth Park Road, London NW5 1SN, UK.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
@@ -1,14 +1,7 @@
|
||||
/*
|
||||
* Driver for the IMX SNVS ON/OFF Power Key
|
||||
* Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// Driver for the IMX SNVS ON/OFF Power Key
|
||||
// Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
|
@@ -23,10 +23,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <marek.vasut@gmail.com>, or by paper mail:
|
||||
* Marek Vasut, Liskovecka 559, Frydek-Mistek, 738 01 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
@@ -466,7 +466,7 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
|
||||
remote->in_endpoint = endpoint;
|
||||
remote->toggle = -1; /* Set to -1 so we will always not match the toggle from the first remote message. */
|
||||
|
||||
remote->in_buffer = usb_alloc_coherent(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma);
|
||||
remote->in_buffer = usb_alloc_coherent(udev, RECV_SIZE, GFP_KERNEL, &remote->in_dma);
|
||||
if (!remote->in_buffer) {
|
||||
error = -ENOMEM;
|
||||
goto fail1;
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include <linux/log2.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/regmap.h>
|
||||
@@ -28,6 +29,7 @@
|
||||
|
||||
#define PON_RT_STS 0x10
|
||||
#define PON_KPDPWR_N_SET BIT(0)
|
||||
#define PON_RESIN_N_SET BIT(1)
|
||||
|
||||
#define PON_PS_HOLD_RST_CTL 0x5a
|
||||
#define PON_PS_HOLD_RST_CTL2 0x5b
|
||||
@@ -38,10 +40,15 @@
|
||||
|
||||
#define PON_PULL_CTL 0x70
|
||||
#define PON_KPDPWR_PULL_UP BIT(1)
|
||||
#define PON_RESIN_PULL_UP BIT(0)
|
||||
|
||||
#define PON_DBC_CTL 0x71
|
||||
#define PON_DBC_DELAY_MASK 0x7
|
||||
|
||||
struct pm8941_data {
|
||||
unsigned int pull_up_bit;
|
||||
unsigned int status_bit;
|
||||
};
|
||||
|
||||
struct pm8941_pwrkey {
|
||||
struct device *dev;
|
||||
@@ -52,6 +59,9 @@ struct pm8941_pwrkey {
|
||||
|
||||
unsigned int revision;
|
||||
struct notifier_block reboot_notifier;
|
||||
|
||||
u32 code;
|
||||
const struct pm8941_data *data;
|
||||
};
|
||||
|
||||
static int pm8941_reboot_notify(struct notifier_block *nb,
|
||||
@@ -124,7 +134,8 @@ static irqreturn_t pm8941_pwrkey_irq(int irq, void *_data)
|
||||
if (error)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
input_report_key(pwrkey->input, KEY_POWER, !!(sts & PON_KPDPWR_N_SET));
|
||||
input_report_key(pwrkey->input, pwrkey->code,
|
||||
sts & pwrkey->data->status_bit);
|
||||
input_sync(pwrkey->input);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@@ -157,6 +168,7 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pm8941_pwrkey *pwrkey;
|
||||
bool pull_up;
|
||||
struct device *parent;
|
||||
u32 req_delay;
|
||||
int error;
|
||||
|
||||
@@ -175,12 +187,30 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
pwrkey->dev = &pdev->dev;
|
||||
pwrkey->data = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
pwrkey->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
parent = pdev->dev.parent;
|
||||
pwrkey->regmap = dev_get_regmap(parent, NULL);
|
||||
if (!pwrkey->regmap) {
|
||||
dev_err(&pdev->dev, "failed to locate regmap\n");
|
||||
return -ENODEV;
|
||||
/*
|
||||
* We failed to get regmap for parent. Let's see if we are
|
||||
* a child of pon node and read regmap and reg from its
|
||||
* parent.
|
||||
*/
|
||||
pwrkey->regmap = dev_get_regmap(parent->parent, NULL);
|
||||
if (!pwrkey->regmap) {
|
||||
dev_err(&pdev->dev, "failed to locate regmap\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
error = of_property_read_u32(parent->of_node,
|
||||
"reg", &pwrkey->baseaddr);
|
||||
} else {
|
||||
error = of_property_read_u32(pdev->dev.of_node, "reg",
|
||||
&pwrkey->baseaddr);
|
||||
}
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
pwrkey->irq = platform_get_irq(pdev, 0);
|
||||
if (pwrkey->irq < 0) {
|
||||
@@ -188,11 +218,6 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
|
||||
return pwrkey->irq;
|
||||
}
|
||||
|
||||
error = of_property_read_u32(pdev->dev.of_node, "reg",
|
||||
&pwrkey->baseaddr);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_REV2,
|
||||
&pwrkey->revision);
|
||||
if (error) {
|
||||
@@ -200,13 +225,21 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
|
||||
return error;
|
||||
}
|
||||
|
||||
error = of_property_read_u32(pdev->dev.of_node, "linux,code",
|
||||
&pwrkey->code);
|
||||
if (error) {
|
||||
dev_dbg(&pdev->dev,
|
||||
"no linux,code assuming power (%d)\n", error);
|
||||
pwrkey->code = KEY_POWER;
|
||||
}
|
||||
|
||||
pwrkey->input = devm_input_allocate_device(&pdev->dev);
|
||||
if (!pwrkey->input) {
|
||||
dev_dbg(&pdev->dev, "unable to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
input_set_capability(pwrkey->input, EV_KEY, KEY_POWER);
|
||||
input_set_capability(pwrkey->input, EV_KEY, pwrkey->code);
|
||||
|
||||
pwrkey->input->name = "pm8941_pwrkey";
|
||||
pwrkey->input->phys = "pm8941_pwrkey/input0";
|
||||
@@ -225,8 +258,8 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
|
||||
|
||||
error = regmap_update_bits(pwrkey->regmap,
|
||||
pwrkey->baseaddr + PON_PULL_CTL,
|
||||
PON_KPDPWR_PULL_UP,
|
||||
pull_up ? PON_KPDPWR_PULL_UP : 0);
|
||||
pwrkey->data->pull_up_bit,
|
||||
pull_up ? pwrkey->data->pull_up_bit : 0);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to set pull: %d\n", error);
|
||||
return error;
|
||||
@@ -271,8 +304,19 @@ static int pm8941_pwrkey_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pm8941_data pwrkey_data = {
|
||||
.pull_up_bit = PON_KPDPWR_PULL_UP,
|
||||
.status_bit = PON_KPDPWR_N_SET,
|
||||
};
|
||||
|
||||
static const struct pm8941_data resin_data = {
|
||||
.pull_up_bit = PON_RESIN_PULL_UP,
|
||||
.status_bit = PON_RESIN_N_SET,
|
||||
};
|
||||
|
||||
static const struct of_device_id pm8941_pwr_key_id_table[] = {
|
||||
{ .compatible = "qcom,pm8941-pwrkey" },
|
||||
{ .compatible = "qcom,pm8941-pwrkey", .data = &pwrkey_data },
|
||||
{ .compatible = "qcom,pm8941-resin", .data = &resin_data },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pm8941_pwr_key_id_table);
|
||||
|
@@ -277,7 +277,7 @@ static int powermate_input_event(struct input_dev *dev, unsigned int type, unsig
|
||||
static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_device *pm)
|
||||
{
|
||||
pm->data = usb_alloc_coherent(udev, POWERMATE_PAYLOAD_SIZE_MAX,
|
||||
GFP_ATOMIC, &pm->data_dma);
|
||||
GFP_KERNEL, &pm->data_dma);
|
||||
if (!pm->data)
|
||||
return -1;
|
||||
|
||||
|
@@ -63,6 +63,9 @@ static void xenkbd_disconnect_backend(struct xenkbd_info *);
|
||||
static void xenkbd_handle_motion_event(struct xenkbd_info *info,
|
||||
struct xenkbd_motion *motion)
|
||||
{
|
||||
if (unlikely(!info->ptr))
|
||||
return;
|
||||
|
||||
input_report_rel(info->ptr, REL_X, motion->rel_x);
|
||||
input_report_rel(info->ptr, REL_Y, motion->rel_y);
|
||||
if (motion->rel_z)
|
||||
@@ -73,6 +76,9 @@ static void xenkbd_handle_motion_event(struct xenkbd_info *info,
|
||||
static void xenkbd_handle_position_event(struct xenkbd_info *info,
|
||||
struct xenkbd_position *pos)
|
||||
{
|
||||
if (unlikely(!info->ptr))
|
||||
return;
|
||||
|
||||
input_report_abs(info->ptr, ABS_X, pos->abs_x);
|
||||
input_report_abs(info->ptr, ABS_Y, pos->abs_y);
|
||||
if (pos->rel_z)
|
||||
@@ -97,6 +103,9 @@ static void xenkbd_handle_key_event(struct xenkbd_info *info,
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(!dev))
|
||||
return;
|
||||
|
||||
input_event(dev, EV_KEY, key->keycode, value);
|
||||
input_sync(dev);
|
||||
}
|
||||
@@ -192,7 +201,7 @@ static int xenkbd_probe(struct xenbus_device *dev,
|
||||
const struct xenbus_device_id *id)
|
||||
{
|
||||
int ret, i;
|
||||
unsigned int abs, touch;
|
||||
bool with_mtouch, with_kbd, with_ptr;
|
||||
struct xenkbd_info *info;
|
||||
struct input_dev *kbd, *ptr, *mtouch;
|
||||
|
||||
@@ -211,106 +220,127 @@ static int xenkbd_probe(struct xenbus_device *dev,
|
||||
if (!info->page)
|
||||
goto error_nomem;
|
||||
|
||||
/* Set input abs params to match backend screen res */
|
||||
abs = xenbus_read_unsigned(dev->otherend,
|
||||
XENKBD_FIELD_FEAT_ABS_POINTER, 0);
|
||||
ptr_size[KPARAM_X] = xenbus_read_unsigned(dev->otherend,
|
||||
XENKBD_FIELD_WIDTH,
|
||||
ptr_size[KPARAM_X]);
|
||||
ptr_size[KPARAM_Y] = xenbus_read_unsigned(dev->otherend,
|
||||
XENKBD_FIELD_HEIGHT,
|
||||
ptr_size[KPARAM_Y]);
|
||||
if (abs) {
|
||||
ret = xenbus_write(XBT_NIL, dev->nodename,
|
||||
XENKBD_FIELD_REQ_ABS_POINTER, "1");
|
||||
if (ret) {
|
||||
pr_warn("xenkbd: can't request abs-pointer\n");
|
||||
abs = 0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The below are reverse logic, e.g. if the feature is set, then
|
||||
* do not expose the corresponding virtual device.
|
||||
*/
|
||||
with_kbd = !xenbus_read_unsigned(dev->otherend,
|
||||
XENKBD_FIELD_FEAT_DSBL_KEYBRD, 0);
|
||||
|
||||
touch = xenbus_read_unsigned(dev->nodename,
|
||||
XENKBD_FIELD_FEAT_MTOUCH, 0);
|
||||
if (touch) {
|
||||
with_ptr = !xenbus_read_unsigned(dev->otherend,
|
||||
XENKBD_FIELD_FEAT_DSBL_POINTER, 0);
|
||||
|
||||
/* Direct logic: if set, then create multi-touch device. */
|
||||
with_mtouch = xenbus_read_unsigned(dev->otherend,
|
||||
XENKBD_FIELD_FEAT_MTOUCH, 0);
|
||||
if (with_mtouch) {
|
||||
ret = xenbus_write(XBT_NIL, dev->nodename,
|
||||
XENKBD_FIELD_REQ_MTOUCH, "1");
|
||||
if (ret) {
|
||||
pr_warn("xenkbd: can't request multi-touch");
|
||||
touch = 0;
|
||||
with_mtouch = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* keyboard */
|
||||
kbd = input_allocate_device();
|
||||
if (!kbd)
|
||||
goto error_nomem;
|
||||
kbd->name = "Xen Virtual Keyboard";
|
||||
kbd->phys = info->phys;
|
||||
kbd->id.bustype = BUS_PCI;
|
||||
kbd->id.vendor = 0x5853;
|
||||
kbd->id.product = 0xffff;
|
||||
if (with_kbd) {
|
||||
kbd = input_allocate_device();
|
||||
if (!kbd)
|
||||
goto error_nomem;
|
||||
kbd->name = "Xen Virtual Keyboard";
|
||||
kbd->phys = info->phys;
|
||||
kbd->id.bustype = BUS_PCI;
|
||||
kbd->id.vendor = 0x5853;
|
||||
kbd->id.product = 0xffff;
|
||||
|
||||
__set_bit(EV_KEY, kbd->evbit);
|
||||
for (i = KEY_ESC; i < KEY_UNKNOWN; i++)
|
||||
__set_bit(i, kbd->keybit);
|
||||
for (i = KEY_OK; i < KEY_MAX; i++)
|
||||
__set_bit(i, kbd->keybit);
|
||||
__set_bit(EV_KEY, kbd->evbit);
|
||||
for (i = KEY_ESC; i < KEY_UNKNOWN; i++)
|
||||
__set_bit(i, kbd->keybit);
|
||||
for (i = KEY_OK; i < KEY_MAX; i++)
|
||||
__set_bit(i, kbd->keybit);
|
||||
|
||||
ret = input_register_device(kbd);
|
||||
if (ret) {
|
||||
input_free_device(kbd);
|
||||
xenbus_dev_fatal(dev, ret, "input_register_device(kbd)");
|
||||
goto error;
|
||||
ret = input_register_device(kbd);
|
||||
if (ret) {
|
||||
input_free_device(kbd);
|
||||
xenbus_dev_fatal(dev, ret,
|
||||
"input_register_device(kbd)");
|
||||
goto error;
|
||||
}
|
||||
info->kbd = kbd;
|
||||
}
|
||||
info->kbd = kbd;
|
||||
|
||||
/* pointing device */
|
||||
ptr = input_allocate_device();
|
||||
if (!ptr)
|
||||
goto error_nomem;
|
||||
ptr->name = "Xen Virtual Pointer";
|
||||
ptr->phys = info->phys;
|
||||
ptr->id.bustype = BUS_PCI;
|
||||
ptr->id.vendor = 0x5853;
|
||||
ptr->id.product = 0xfffe;
|
||||
if (with_ptr) {
|
||||
unsigned int abs;
|
||||
|
||||
if (abs) {
|
||||
__set_bit(EV_ABS, ptr->evbit);
|
||||
input_set_abs_params(ptr, ABS_X, 0, ptr_size[KPARAM_X], 0, 0);
|
||||
input_set_abs_params(ptr, ABS_Y, 0, ptr_size[KPARAM_Y], 0, 0);
|
||||
} else {
|
||||
input_set_capability(ptr, EV_REL, REL_X);
|
||||
input_set_capability(ptr, EV_REL, REL_Y);
|
||||
/* Set input abs params to match backend screen res */
|
||||
abs = xenbus_read_unsigned(dev->otherend,
|
||||
XENKBD_FIELD_FEAT_ABS_POINTER, 0);
|
||||
ptr_size[KPARAM_X] = xenbus_read_unsigned(dev->otherend,
|
||||
XENKBD_FIELD_WIDTH,
|
||||
ptr_size[KPARAM_X]);
|
||||
ptr_size[KPARAM_Y] = xenbus_read_unsigned(dev->otherend,
|
||||
XENKBD_FIELD_HEIGHT,
|
||||
ptr_size[KPARAM_Y]);
|
||||
if (abs) {
|
||||
ret = xenbus_write(XBT_NIL, dev->nodename,
|
||||
XENKBD_FIELD_REQ_ABS_POINTER, "1");
|
||||
if (ret) {
|
||||
pr_warn("xenkbd: can't request abs-pointer\n");
|
||||
abs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ptr = input_allocate_device();
|
||||
if (!ptr)
|
||||
goto error_nomem;
|
||||
ptr->name = "Xen Virtual Pointer";
|
||||
ptr->phys = info->phys;
|
||||
ptr->id.bustype = BUS_PCI;
|
||||
ptr->id.vendor = 0x5853;
|
||||
ptr->id.product = 0xfffe;
|
||||
|
||||
if (abs) {
|
||||
__set_bit(EV_ABS, ptr->evbit);
|
||||
input_set_abs_params(ptr, ABS_X, 0,
|
||||
ptr_size[KPARAM_X], 0, 0);
|
||||
input_set_abs_params(ptr, ABS_Y, 0,
|
||||
ptr_size[KPARAM_Y], 0, 0);
|
||||
} else {
|
||||
input_set_capability(ptr, EV_REL, REL_X);
|
||||
input_set_capability(ptr, EV_REL, REL_Y);
|
||||
}
|
||||
input_set_capability(ptr, EV_REL, REL_WHEEL);
|
||||
|
||||
__set_bit(EV_KEY, ptr->evbit);
|
||||
for (i = BTN_LEFT; i <= BTN_TASK; i++)
|
||||
__set_bit(i, ptr->keybit);
|
||||
|
||||
ret = input_register_device(ptr);
|
||||
if (ret) {
|
||||
input_free_device(ptr);
|
||||
xenbus_dev_fatal(dev, ret,
|
||||
"input_register_device(ptr)");
|
||||
goto error;
|
||||
}
|
||||
info->ptr = ptr;
|
||||
}
|
||||
input_set_capability(ptr, EV_REL, REL_WHEEL);
|
||||
|
||||
__set_bit(EV_KEY, ptr->evbit);
|
||||
for (i = BTN_LEFT; i <= BTN_TASK; i++)
|
||||
__set_bit(i, ptr->keybit);
|
||||
|
||||
ret = input_register_device(ptr);
|
||||
if (ret) {
|
||||
input_free_device(ptr);
|
||||
xenbus_dev_fatal(dev, ret, "input_register_device(ptr)");
|
||||
goto error;
|
||||
}
|
||||
info->ptr = ptr;
|
||||
|
||||
/* multi-touch device */
|
||||
if (touch) {
|
||||
if (with_mtouch) {
|
||||
int num_cont, width, height;
|
||||
|
||||
mtouch = input_allocate_device();
|
||||
if (!mtouch)
|
||||
goto error_nomem;
|
||||
|
||||
num_cont = xenbus_read_unsigned(info->xbdev->nodename,
|
||||
num_cont = xenbus_read_unsigned(info->xbdev->otherend,
|
||||
XENKBD_FIELD_MT_NUM_CONTACTS,
|
||||
1);
|
||||
width = xenbus_read_unsigned(info->xbdev->nodename,
|
||||
width = xenbus_read_unsigned(info->xbdev->otherend,
|
||||
XENKBD_FIELD_MT_WIDTH,
|
||||
XENFB_WIDTH);
|
||||
height = xenbus_read_unsigned(info->xbdev->nodename,
|
||||
height = xenbus_read_unsigned(info->xbdev->otherend,
|
||||
XENKBD_FIELD_MT_HEIGHT,
|
||||
XENFB_HEIGHT);
|
||||
|
||||
@@ -346,6 +376,11 @@ static int xenkbd_probe(struct xenbus_device *dev,
|
||||
info->mtouch = mtouch;
|
||||
}
|
||||
|
||||
if (!(with_kbd || with_ptr || with_mtouch)) {
|
||||
ret = -ENXIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = xenkbd_connect_backend(dev, info);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
@@ -894,12 +894,12 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
|
||||
/* allocate usb buffers */
|
||||
yld->irq_data = usb_alloc_coherent(udev, USB_PKT_LEN,
|
||||
GFP_ATOMIC, &yld->irq_dma);
|
||||
GFP_KERNEL, &yld->irq_dma);
|
||||
if (yld->irq_data == NULL)
|
||||
return usb_cleanup(yld, -ENOMEM);
|
||||
|
||||
yld->ctl_data = usb_alloc_coherent(udev, USB_PKT_LEN,
|
||||
GFP_ATOMIC, &yld->ctl_dma);
|
||||
GFP_KERNEL, &yld->ctl_dma);
|
||||
if (!yld->ctl_data)
|
||||
return usb_cleanup(yld, -ENOMEM);
|
||||
|
||||
|
@@ -472,6 +472,7 @@ static int atp_status_check(struct urb *urb)
|
||||
dev->info->datalen, dev->urb->actual_length);
|
||||
dev->overflow_warned = true;
|
||||
}
|
||||
/* fall through */
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
@@ -810,7 +811,7 @@ static int atp_open(struct input_dev *input)
|
||||
{
|
||||
struct atp *dev = input_get_drvdata(input);
|
||||
|
||||
if (usb_submit_urb(dev->urb, GFP_ATOMIC))
|
||||
if (usb_submit_urb(dev->urb, GFP_KERNEL))
|
||||
return -EIO;
|
||||
|
||||
dev->open = true;
|
||||
@@ -976,7 +977,7 @@ static int atp_recover(struct atp *dev)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
|
||||
if (dev->open && usb_submit_urb(dev->urb, GFP_KERNEL))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
@@ -994,7 +995,7 @@ static int atp_resume(struct usb_interface *iface)
|
||||
{
|
||||
struct atp *dev = usb_get_intfdata(iface);
|
||||
|
||||
if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
|
||||
if (dev->open && usb_submit_urb(dev->urb, GFP_KERNEL))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
|
@@ -2554,6 +2554,7 @@ static int cyapa_gen5_do_operational_check(struct cyapa *cyapa)
|
||||
}
|
||||
|
||||
cyapa->state = CYAPA_STATE_GEN5_APP;
|
||||
/* fall through */
|
||||
|
||||
case CYAPA_STATE_GEN5_APP:
|
||||
/*
|
||||
|
@@ -680,6 +680,7 @@ static int cyapa_gen6_operational_check(struct cyapa *cyapa)
|
||||
}
|
||||
|
||||
cyapa->state = CYAPA_STATE_GEN6_APP;
|
||||
/* fall through */
|
||||
|
||||
case CYAPA_STATE_GEN6_APP:
|
||||
/*
|
||||
|
@@ -340,7 +340,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
|
||||
*/
|
||||
if (packet[3] & 0x80)
|
||||
fingers = 4;
|
||||
/* pass through... */
|
||||
/* fall through */
|
||||
case 1:
|
||||
/*
|
||||
* byte 1: . . . . x11 x10 x9 x8
|
||||
|
@@ -26,10 +26,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@@ -27,10 +27,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@@ -23,10 +23,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
@@ -143,7 +139,8 @@ static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
|
||||
switch (sermouse->type) {
|
||||
|
||||
case SERIO_MS:
|
||||
sermouse->type = SERIO_MP;
|
||||
sermouse->type = SERIO_MP;
|
||||
/* fall through */
|
||||
|
||||
case SERIO_MP:
|
||||
if ((data >> 2) & 3) break; /* M++ Wireless Extension packet. */
|
||||
@@ -154,6 +151,7 @@ static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
|
||||
case SERIO_MZP:
|
||||
case SERIO_MZPP:
|
||||
input_report_key(dev, BTN_SIDE, (data >> 5) & 1);
|
||||
/* fall through */
|
||||
|
||||
case SERIO_MZ:
|
||||
input_report_key(dev, BTN_MIDDLE, (data >> 4) & 1);
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
@@ -573,6 +573,9 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
|
||||
port = &i8042_ports[port_no];
|
||||
serio = port->exists ? port->serio : NULL;
|
||||
|
||||
if (irq && serio)
|
||||
pm_wakeup_event(&serio->dev, 0);
|
||||
|
||||
filter_dbg(port->driver_bound, data, "<- i8042 (interrupt, %d, %d%s%s)\n",
|
||||
port_no, irq,
|
||||
dfl & SERIO_PARITY ? ", bad parity" : "",
|
||||
|
@@ -23,10 +23,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@@ -21,10 +21,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
@@ -1712,7 +1712,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
}
|
||||
|
||||
aiptek->data = usb_alloc_coherent(usbdev, AIPTEK_PACKET_LENGTH,
|
||||
GFP_ATOMIC, &aiptek->data_dma);
|
||||
GFP_KERNEL, &aiptek->data_dma);
|
||||
if (!aiptek->data) {
|
||||
dev_warn(&intf->dev, "cannot allocate usb buffer\n");
|
||||
goto fail1;
|
||||
|
@@ -151,6 +151,18 @@ config TOUCHSCREEN_BU21013
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called bu21013_ts.
|
||||
|
||||
config TOUCHSCREEN_BU21029
|
||||
tristate "Rohm BU21029 based touch panel controllers"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you have a Rohm BU21029 touchscreen controller
|
||||
connected to your system.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called bu21029_ts.
|
||||
|
||||
config TOUCHSCREEN_CHIPONE_ICN8318
|
||||
tristate "chipone icn8318 touchscreen controller"
|
||||
depends on GPIOLIB || COMPILE_TEST
|
||||
|
@@ -18,6 +18,7 @@ obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) += ar1021_i2c.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_BU21029) += bu21029_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8318) += chipone_icn8318.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8505) += chipone_icn8505.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
|
||||
|
@@ -75,6 +75,7 @@
|
||||
#define MXT_SPT_DIGITIZER_T43 43
|
||||
#define MXT_SPT_MESSAGECOUNT_T44 44
|
||||
#define MXT_SPT_CTECONFIG_T46 46
|
||||
#define MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71 71
|
||||
#define MXT_TOUCH_MULTITOUCHSCREEN_T100 100
|
||||
|
||||
/* MXT_GEN_MESSAGE_T5 object */
|
||||
@@ -88,12 +89,12 @@
|
||||
#define MXT_COMMAND_DIAGNOSTIC 5
|
||||
|
||||
/* Define for T6 status byte */
|
||||
#define MXT_T6_STATUS_RESET (1 << 7)
|
||||
#define MXT_T6_STATUS_OFL (1 << 6)
|
||||
#define MXT_T6_STATUS_SIGERR (1 << 5)
|
||||
#define MXT_T6_STATUS_CAL (1 << 4)
|
||||
#define MXT_T6_STATUS_CFGERR (1 << 3)
|
||||
#define MXT_T6_STATUS_COMSERR (1 << 2)
|
||||
#define MXT_T6_STATUS_RESET BIT(7)
|
||||
#define MXT_T6_STATUS_OFL BIT(6)
|
||||
#define MXT_T6_STATUS_SIGERR BIT(5)
|
||||
#define MXT_T6_STATUS_CAL BIT(4)
|
||||
#define MXT_T6_STATUS_CFGERR BIT(3)
|
||||
#define MXT_T6_STATUS_COMSERR BIT(2)
|
||||
|
||||
/* MXT_GEN_POWER_T7 field */
|
||||
struct t7_config {
|
||||
@@ -112,14 +113,14 @@ struct t7_config {
|
||||
#define MXT_T9_RANGE 18
|
||||
|
||||
/* MXT_TOUCH_MULTI_T9 status */
|
||||
#define MXT_T9_UNGRIP (1 << 0)
|
||||
#define MXT_T9_SUPPRESS (1 << 1)
|
||||
#define MXT_T9_AMP (1 << 2)
|
||||
#define MXT_T9_VECTOR (1 << 3)
|
||||
#define MXT_T9_MOVE (1 << 4)
|
||||
#define MXT_T9_RELEASE (1 << 5)
|
||||
#define MXT_T9_PRESS (1 << 6)
|
||||
#define MXT_T9_DETECT (1 << 7)
|
||||
#define MXT_T9_UNGRIP BIT(0)
|
||||
#define MXT_T9_SUPPRESS BIT(1)
|
||||
#define MXT_T9_AMP BIT(2)
|
||||
#define MXT_T9_VECTOR BIT(3)
|
||||
#define MXT_T9_MOVE BIT(4)
|
||||
#define MXT_T9_RELEASE BIT(5)
|
||||
#define MXT_T9_PRESS BIT(6)
|
||||
#define MXT_T9_DETECT BIT(7)
|
||||
|
||||
struct t9_range {
|
||||
__le16 x;
|
||||
@@ -127,9 +128,9 @@ struct t9_range {
|
||||
} __packed;
|
||||
|
||||
/* MXT_TOUCH_MULTI_T9 orient */
|
||||
#define MXT_T9_ORIENT_SWITCH (1 << 0)
|
||||
#define MXT_T9_ORIENT_INVERTX (1 << 1)
|
||||
#define MXT_T9_ORIENT_INVERTY (1 << 2)
|
||||
#define MXT_T9_ORIENT_SWITCH BIT(0)
|
||||
#define MXT_T9_ORIENT_INVERTX BIT(1)
|
||||
#define MXT_T9_ORIENT_INVERTY BIT(2)
|
||||
|
||||
/* MXT_SPT_COMMSCONFIG_T18 */
|
||||
#define MXT_COMMS_CTRL 0
|
||||
@@ -214,7 +215,7 @@ enum t100_type {
|
||||
#define MXT_FRAME_CRC_PASS 0x04
|
||||
#define MXT_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */
|
||||
#define MXT_BOOT_STATUS_MASK 0x3f
|
||||
#define MXT_BOOT_EXTENDED_ID (1 << 5)
|
||||
#define MXT_BOOT_EXTENDED_ID BIT(5)
|
||||
#define MXT_BOOT_ID_MASK 0x1f
|
||||
|
||||
/* Touchscreen absolute values */
|
||||
@@ -276,6 +277,19 @@ enum mxt_suspend_mode {
|
||||
MXT_SUSPEND_T9_CTRL = 1,
|
||||
};
|
||||
|
||||
/* Config update context */
|
||||
struct mxt_cfg {
|
||||
u8 *raw;
|
||||
size_t raw_size;
|
||||
off_t raw_pos;
|
||||
|
||||
u8 *mem;
|
||||
size_t mem_size;
|
||||
int start_ofs;
|
||||
|
||||
struct mxt_info info;
|
||||
};
|
||||
|
||||
/* Each client has this additional data */
|
||||
struct mxt_data {
|
||||
struct i2c_client *client;
|
||||
@@ -317,6 +331,7 @@ struct mxt_data {
|
||||
u8 T6_reportid;
|
||||
u16 T6_address;
|
||||
u16 T7_address;
|
||||
u16 T71_address;
|
||||
u8 T9_reportid_min;
|
||||
u8 T9_reportid_max;
|
||||
u8 T19_reportid;
|
||||
@@ -382,6 +397,7 @@ static bool mxt_object_readable(unsigned int type)
|
||||
case MXT_SPT_USERDATA_T38:
|
||||
case MXT_SPT_DIGITIZER_T43:
|
||||
case MXT_SPT_CTECONFIG_T46:
|
||||
case MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -712,13 +728,13 @@ static void mxt_proc_t6_messages(struct mxt_data *data, u8 *msg)
|
||||
u8 status = msg[1];
|
||||
u32 crc = msg[2] | (msg[3] << 8) | (msg[4] << 16);
|
||||
|
||||
complete(&data->crc_completion);
|
||||
|
||||
if (crc != data->config_crc) {
|
||||
data->config_crc = crc;
|
||||
dev_dbg(dev, "T6 Config Checksum: 0x%06X\n", crc);
|
||||
}
|
||||
|
||||
complete(&data->crc_completion);
|
||||
|
||||
/* Detect reset */
|
||||
if (status & MXT_T6_STATUS_RESET)
|
||||
complete(&data->reset_completion);
|
||||
@@ -827,6 +843,10 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
|
||||
mxt_input_sync(data);
|
||||
}
|
||||
|
||||
/* if active, pressure must be non-zero */
|
||||
if (!amplitude)
|
||||
amplitude = MXT_PRESSURE_DEFAULT;
|
||||
|
||||
/* Touch active */
|
||||
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);
|
||||
input_report_abs(input_dev, ABS_MT_POSITION_X, x);
|
||||
@@ -1279,12 +1299,7 @@ static u32 mxt_calculate_crc(u8 *base, off_t start_off, off_t end_off)
|
||||
return crc;
|
||||
}
|
||||
|
||||
static int mxt_prepare_cfg_mem(struct mxt_data *data,
|
||||
const struct firmware *cfg,
|
||||
unsigned int data_pos,
|
||||
unsigned int cfg_start_ofs,
|
||||
u8 *config_mem,
|
||||
size_t config_mem_size)
|
||||
static int mxt_prepare_cfg_mem(struct mxt_data *data, struct mxt_cfg *cfg)
|
||||
{
|
||||
struct device *dev = &data->client->dev;
|
||||
struct mxt_object *object;
|
||||
@@ -1295,9 +1310,9 @@ static int mxt_prepare_cfg_mem(struct mxt_data *data,
|
||||
u16 reg;
|
||||
u8 val;
|
||||
|
||||
while (data_pos < cfg->size) {
|
||||
while (cfg->raw_pos < cfg->raw_size) {
|
||||
/* Read type, instance, length */
|
||||
ret = sscanf(cfg->data + data_pos, "%x %x %x%n",
|
||||
ret = sscanf(cfg->raw + cfg->raw_pos, "%x %x %x%n",
|
||||
&type, &instance, &size, &offset);
|
||||
if (ret == 0) {
|
||||
/* EOF */
|
||||
@@ -1306,20 +1321,20 @@ static int mxt_prepare_cfg_mem(struct mxt_data *data,
|
||||
dev_err(dev, "Bad format: failed to parse object\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
data_pos += offset;
|
||||
cfg->raw_pos += offset;
|
||||
|
||||
object = mxt_get_object(data, type);
|
||||
if (!object) {
|
||||
/* Skip object */
|
||||
for (i = 0; i < size; i++) {
|
||||
ret = sscanf(cfg->data + data_pos, "%hhx%n",
|
||||
ret = sscanf(cfg->raw + cfg->raw_pos, "%hhx%n",
|
||||
&val, &offset);
|
||||
if (ret != 1) {
|
||||
dev_err(dev, "Bad format in T%d at %d\n",
|
||||
type, i);
|
||||
return -EINVAL;
|
||||
}
|
||||
data_pos += offset;
|
||||
cfg->raw_pos += offset;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -1354,7 +1369,7 @@ static int mxt_prepare_cfg_mem(struct mxt_data *data,
|
||||
reg = object->start_address + mxt_obj_size(object) * instance;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
ret = sscanf(cfg->data + data_pos, "%hhx%n",
|
||||
ret = sscanf(cfg->raw + cfg->raw_pos, "%hhx%n",
|
||||
&val,
|
||||
&offset);
|
||||
if (ret != 1) {
|
||||
@@ -1362,15 +1377,15 @@ static int mxt_prepare_cfg_mem(struct mxt_data *data,
|
||||
type, i);
|
||||
return -EINVAL;
|
||||
}
|
||||
data_pos += offset;
|
||||
cfg->raw_pos += offset;
|
||||
|
||||
if (i > mxt_obj_size(object))
|
||||
continue;
|
||||
|
||||
byte_offset = reg + i - cfg_start_ofs;
|
||||
byte_offset = reg + i - cfg->start_ofs;
|
||||
|
||||
if (byte_offset >= 0 && byte_offset < config_mem_size) {
|
||||
*(config_mem + byte_offset) = val;
|
||||
if (byte_offset >= 0 && byte_offset < cfg->mem_size) {
|
||||
*(cfg->mem + byte_offset) = val;
|
||||
} else {
|
||||
dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n",
|
||||
reg, object->type, byte_offset);
|
||||
@@ -1382,22 +1397,21 @@ static int mxt_prepare_cfg_mem(struct mxt_data *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxt_upload_cfg_mem(struct mxt_data *data, unsigned int cfg_start,
|
||||
u8 *config_mem, size_t config_mem_size)
|
||||
static int mxt_upload_cfg_mem(struct mxt_data *data, struct mxt_cfg *cfg)
|
||||
{
|
||||
unsigned int byte_offset = 0;
|
||||
int error;
|
||||
|
||||
/* Write configuration as blocks */
|
||||
while (byte_offset < config_mem_size) {
|
||||
unsigned int size = config_mem_size - byte_offset;
|
||||
while (byte_offset < cfg->mem_size) {
|
||||
unsigned int size = cfg->mem_size - byte_offset;
|
||||
|
||||
if (size > MXT_MAX_BLOCK_WRITE)
|
||||
size = MXT_MAX_BLOCK_WRITE;
|
||||
|
||||
error = __mxt_write_reg(data->client,
|
||||
cfg_start + byte_offset,
|
||||
size, config_mem + byte_offset);
|
||||
cfg->start_ofs + byte_offset,
|
||||
size, cfg->mem + byte_offset);
|
||||
if (error) {
|
||||
dev_err(&data->client->dev,
|
||||
"Config write error, ret=%d\n", error);
|
||||
@@ -1431,65 +1445,75 @@ static int mxt_init_t7_power_cfg(struct mxt_data *data);
|
||||
* <SIZE> - 2-byte object size as hex
|
||||
* <CONTENTS> - array of <SIZE> 1-byte hex values
|
||||
*/
|
||||
static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
|
||||
static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
|
||||
{
|
||||
struct device *dev = &data->client->dev;
|
||||
struct mxt_info cfg_info;
|
||||
struct mxt_cfg cfg;
|
||||
int ret;
|
||||
int offset;
|
||||
int data_pos;
|
||||
int i;
|
||||
int cfg_start_ofs;
|
||||
u32 info_crc, config_crc, calculated_crc;
|
||||
u8 *config_mem;
|
||||
size_t config_mem_size;
|
||||
u16 crc_start = 0;
|
||||
|
||||
/* Make zero terminated copy of the OBP_RAW file */
|
||||
cfg.raw = kmemdup_nul(fw->data, fw->size, GFP_KERNEL);
|
||||
if (!cfg.raw)
|
||||
return -ENOMEM;
|
||||
|
||||
cfg.raw_size = fw->size;
|
||||
|
||||
mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1);
|
||||
|
||||
if (strncmp(cfg->data, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) {
|
||||
if (strncmp(cfg.raw, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) {
|
||||
dev_err(dev, "Unrecognised config file\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto release_raw;
|
||||
}
|
||||
|
||||
data_pos = strlen(MXT_CFG_MAGIC);
|
||||
cfg.raw_pos = strlen(MXT_CFG_MAGIC);
|
||||
|
||||
/* Load information block and check */
|
||||
for (i = 0; i < sizeof(struct mxt_info); i++) {
|
||||
ret = sscanf(cfg->data + data_pos, "%hhx%n",
|
||||
(unsigned char *)&cfg_info + i,
|
||||
ret = sscanf(cfg.raw + cfg.raw_pos, "%hhx%n",
|
||||
(unsigned char *)&cfg.info + i,
|
||||
&offset);
|
||||
if (ret != 1) {
|
||||
dev_err(dev, "Bad format\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto release_raw;
|
||||
}
|
||||
|
||||
data_pos += offset;
|
||||
cfg.raw_pos += offset;
|
||||
}
|
||||
|
||||
if (cfg_info.family_id != data->info->family_id) {
|
||||
if (cfg.info.family_id != data->info->family_id) {
|
||||
dev_err(dev, "Family ID mismatch!\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto release_raw;
|
||||
}
|
||||
|
||||
if (cfg_info.variant_id != data->info->variant_id) {
|
||||
if (cfg.info.variant_id != data->info->variant_id) {
|
||||
dev_err(dev, "Variant ID mismatch!\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto release_raw;
|
||||
}
|
||||
|
||||
/* Read CRCs */
|
||||
ret = sscanf(cfg->data + data_pos, "%x%n", &info_crc, &offset);
|
||||
ret = sscanf(cfg.raw + cfg.raw_pos, "%x%n", &info_crc, &offset);
|
||||
if (ret != 1) {
|
||||
dev_err(dev, "Bad format: failed to parse Info CRC\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto release_raw;
|
||||
}
|
||||
data_pos += offset;
|
||||
cfg.raw_pos += offset;
|
||||
|
||||
ret = sscanf(cfg->data + data_pos, "%x%n", &config_crc, &offset);
|
||||
ret = sscanf(cfg.raw + cfg.raw_pos, "%x%n", &config_crc, &offset);
|
||||
if (ret != 1) {
|
||||
dev_err(dev, "Bad format: failed to parse Config CRC\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto release_raw;
|
||||
}
|
||||
data_pos += offset;
|
||||
cfg.raw_pos += offset;
|
||||
|
||||
/*
|
||||
* The Info Block CRC is calculated over mxt_info and the object
|
||||
@@ -1515,39 +1539,39 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
|
||||
}
|
||||
|
||||
/* Malloc memory to store configuration */
|
||||
cfg_start_ofs = MXT_OBJECT_START +
|
||||
cfg.start_ofs = MXT_OBJECT_START +
|
||||
data->info->object_num * sizeof(struct mxt_object) +
|
||||
MXT_INFO_CHECKSUM_SIZE;
|
||||
config_mem_size = data->mem_size - cfg_start_ofs;
|
||||
config_mem = kzalloc(config_mem_size, GFP_KERNEL);
|
||||
if (!config_mem) {
|
||||
dev_err(dev, "Failed to allocate memory\n");
|
||||
return -ENOMEM;
|
||||
cfg.mem_size = data->mem_size - cfg.start_ofs;
|
||||
cfg.mem = kzalloc(cfg.mem_size, GFP_KERNEL);
|
||||
if (!cfg.mem) {
|
||||
ret = -ENOMEM;
|
||||
goto release_raw;
|
||||
}
|
||||
|
||||
ret = mxt_prepare_cfg_mem(data, cfg, data_pos, cfg_start_ofs,
|
||||
config_mem, config_mem_size);
|
||||
ret = mxt_prepare_cfg_mem(data, &cfg);
|
||||
if (ret)
|
||||
goto release_mem;
|
||||
|
||||
/* Calculate crc of the received configs (not the raw config file) */
|
||||
if (data->T7_address < cfg_start_ofs) {
|
||||
dev_err(dev, "Bad T7 address, T7addr = %x, config offset %x\n",
|
||||
data->T7_address, cfg_start_ofs);
|
||||
ret = 0;
|
||||
goto release_mem;
|
||||
if (data->T71_address)
|
||||
crc_start = data->T71_address;
|
||||
else if (data->T7_address)
|
||||
crc_start = data->T7_address;
|
||||
else
|
||||
dev_warn(dev, "Could not find CRC start\n");
|
||||
|
||||
if (crc_start > cfg.start_ofs) {
|
||||
calculated_crc = mxt_calculate_crc(cfg.mem,
|
||||
crc_start - cfg.start_ofs,
|
||||
cfg.mem_size);
|
||||
|
||||
if (config_crc > 0 && config_crc != calculated_crc)
|
||||
dev_warn(dev, "Config CRC in file inconsistent, calculated=%06X, file=%06X\n",
|
||||
calculated_crc, config_crc);
|
||||
}
|
||||
|
||||
calculated_crc = mxt_calculate_crc(config_mem,
|
||||
data->T7_address - cfg_start_ofs,
|
||||
config_mem_size);
|
||||
|
||||
if (config_crc > 0 && config_crc != calculated_crc)
|
||||
dev_warn(dev, "Config CRC error, calculated=%06X, file=%06X\n",
|
||||
calculated_crc, config_crc);
|
||||
|
||||
ret = mxt_upload_cfg_mem(data, cfg_start_ofs,
|
||||
config_mem, config_mem_size);
|
||||
ret = mxt_upload_cfg_mem(data, &cfg);
|
||||
if (ret)
|
||||
goto release_mem;
|
||||
|
||||
@@ -1562,8 +1586,10 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
|
||||
/* T7 config may have changed */
|
||||
mxt_init_t7_power_cfg(data);
|
||||
|
||||
release_raw:
|
||||
kfree(cfg.raw);
|
||||
release_mem:
|
||||
kfree(config_mem);
|
||||
kfree(cfg.mem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1591,6 +1617,7 @@ static void mxt_free_object_table(struct mxt_data *data)
|
||||
data->T5_msg_size = 0;
|
||||
data->T6_reportid = 0;
|
||||
data->T7_address = 0;
|
||||
data->T71_address = 0;
|
||||
data->T9_reportid_min = 0;
|
||||
data->T9_reportid_max = 0;
|
||||
data->T19_reportid = 0;
|
||||
@@ -1656,12 +1683,16 @@ static int mxt_parse_object_table(struct mxt_data *data,
|
||||
case MXT_GEN_POWER_T7:
|
||||
data->T7_address = object->start_address;
|
||||
break;
|
||||
case MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71:
|
||||
data->T71_address = object->start_address;
|
||||
break;
|
||||
case MXT_TOUCH_MULTI_T9:
|
||||
data->multitouch = MXT_TOUCH_MULTI_T9;
|
||||
/* Only handle messages from first T9 instance */
|
||||
data->T9_reportid_min = min_id;
|
||||
data->T9_reportid_max = max_id;
|
||||
data->num_touchids = object->num_report_ids
|
||||
* mxt_obj_instances(object);
|
||||
data->T9_reportid_max = min_id +
|
||||
object->num_report_ids - 1;
|
||||
data->num_touchids = object->num_report_ids;
|
||||
break;
|
||||
case MXT_SPT_MESSAGECOUNT_T44:
|
||||
data->T44_address = object->start_address;
|
||||
@@ -1981,10 +2012,8 @@ static int mxt_initialize_input_device(struct mxt_data *data)
|
||||
|
||||
/* Register input device */
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev) {
|
||||
dev_err(dev, "Failed to allocate memory\n");
|
||||
if (!input_dev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
input_dev->name = "Atmel maXTouch Touchscreen";
|
||||
input_dev->phys = data->phys;
|
||||
@@ -2054,12 +2083,6 @@ static int mxt_initialize_input_device(struct mxt_data *data)
|
||||
0, 255, 0, 0);
|
||||
}
|
||||
|
||||
if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
|
||||
data->t100_aux_ampl) {
|
||||
input_set_abs_params(input_dev, ABS_MT_PRESSURE,
|
||||
0, 255, 0, 0);
|
||||
}
|
||||
|
||||
if (data->multitouch == MXT_TOUCH_MULTITOUCHSCREEN_T100 &&
|
||||
data->t100_aux_vect) {
|
||||
input_set_abs_params(input_dev, ABS_MT_ORIENTATION,
|
||||
|
@@ -0,0 +1,484 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Rohm BU21029 touchscreen controller driver
|
||||
*
|
||||
* Copyright (C) 2015-2018 Bosch Sicherheitssysteme GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/touchscreen.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
/*
|
||||
* HW_ID1 Register (PAGE=0, ADDR=0x0E, Reset value=0x02, Read only)
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | HW_IDH |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* HW_ID2 Register (PAGE=0, ADDR=0x0F, Reset value=0x29, Read only)
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | HW_IDL |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* HW_IDH: high 8bits of IC's ID
|
||||
* HW_IDL: low 8bits of IC's ID
|
||||
*/
|
||||
#define BU21029_HWID_REG (0x0E << 3)
|
||||
#define SUPPORTED_HWID 0x0229
|
||||
|
||||
/*
|
||||
* CFR0 Register (PAGE=0, ADDR=0x00, Reset value=0x20)
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | 0 | 0 | CALIB | INTRM | 0 | 0 | 0 | 0 |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* CALIB: 0 = not to use calibration result (*)
|
||||
* 1 = use calibration result
|
||||
* INTRM: 0 = INT output depend on "pen down" (*)
|
||||
* 1 = INT output always "0"
|
||||
*/
|
||||
#define BU21029_CFR0_REG (0x00 << 3)
|
||||
#define CFR0_VALUE 0x00
|
||||
|
||||
/*
|
||||
* CFR1 Register (PAGE=0, ADDR=0x01, Reset value=0xA6)
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | MAV | AVE[2:0] | 0 | SMPL[2:0] |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* MAV: 0 = median average filter off
|
||||
* 1 = median average filter on (*)
|
||||
* AVE: AVE+1 = number of average samples for MAV,
|
||||
* if AVE>SMPL, then AVE=SMPL (=3)
|
||||
* SMPL: SMPL+1 = number of conversion samples for MAV (=7)
|
||||
*/
|
||||
#define BU21029_CFR1_REG (0x01 << 3)
|
||||
#define CFR1_VALUE 0xA6
|
||||
|
||||
/*
|
||||
* CFR2 Register (PAGE=0, ADDR=0x02, Reset value=0x04)
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | INTVL_TIME[3:0] | TIME_ST_ADC[3:0] |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* INTVL_TIME: waiting time between completion of conversion
|
||||
* and start of next conversion, only usable in
|
||||
* autoscan mode (=20.480ms)
|
||||
* TIME_ST_ADC: waiting time between application of voltage
|
||||
* to panel and start of A/D conversion (=100us)
|
||||
*/
|
||||
#define BU21029_CFR2_REG (0x02 << 3)
|
||||
#define CFR2_VALUE 0xC9
|
||||
|
||||
/*
|
||||
* CFR3 Register (PAGE=0, ADDR=0x0B, Reset value=0x72)
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | RM8 | STRETCH| PU90K | DUAL | PIDAC_OFS[3:0] |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* RM8: 0 = coordinate resolution is 12bit (*)
|
||||
* 1 = coordinate resolution is 8bit
|
||||
* STRETCH: 0 = SCL_STRETCH function off
|
||||
* 1 = SCL_STRETCH function on (*)
|
||||
* PU90K: 0 = internal pull-up resistance for touch detection is ~50kohms (*)
|
||||
* 1 = internal pull-up resistance for touch detection is ~90kohms
|
||||
* DUAL: 0 = dual touch detection off (*)
|
||||
* 1 = dual touch detection on
|
||||
* PIDAC_OFS: dual touch detection circuit adjustment, it is not necessary
|
||||
* to change this from initial value
|
||||
*/
|
||||
#define BU21029_CFR3_REG (0x0B << 3)
|
||||
#define CFR3_VALUE 0x42
|
||||
|
||||
/*
|
||||
* LDO Register (PAGE=0, ADDR=0x0C, Reset value=0x00)
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | 0 | PVDD[2:0] | 0 | AVDD[2:0] |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* PVDD: output voltage of panel output regulator (=2.000V)
|
||||
* AVDD: output voltage of analog circuit regulator (=2.000V)
|
||||
*/
|
||||
#define BU21029_LDO_REG (0x0C << 3)
|
||||
#define LDO_VALUE 0x77
|
||||
|
||||
/*
|
||||
* Serial Interface Command Byte 1 (CID=1)
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* | 1 | CF | CMSK | PDM | STP |
|
||||
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
* CF: conversion function, see table 3 in datasheet p6 (=0000, automatic scan)
|
||||
* CMSK: 0 = executes convert function (*)
|
||||
* 1 = reads the convert result
|
||||
* PDM: 0 = power down after convert function stops (*)
|
||||
* 1 = keep power on after convert function stops
|
||||
* STP: 1 = abort current conversion and power down, set to "0" automatically
|
||||
*/
|
||||
#define BU21029_AUTOSCAN 0x80
|
||||
|
||||
/*
|
||||
* The timeout value needs to be larger than INTVL_TIME + tConv4 (sample and
|
||||
* conversion time), where tConv4 is calculated by formula:
|
||||
* tPON + tDLY1 + (tTIME_ST_ADC + (tADC * tSMPL) * 2 + tDLY2) * 3
|
||||
* see figure 8 in datasheet p15 for details of each field.
|
||||
*/
|
||||
#define PEN_UP_TIMEOUT_MS 50
|
||||
|
||||
#define STOP_DELAY_MIN_US 50
|
||||
#define STOP_DELAY_MAX_US 1000
|
||||
#define START_DELAY_MS 2
|
||||
#define BUF_LEN 8
|
||||
#define SCALE_12BIT (1 << 12)
|
||||
#define MAX_12BIT ((1 << 12) - 1)
|
||||
#define DRIVER_NAME "bu21029"
|
||||
|
||||
struct bu21029_ts_data {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *in_dev;
|
||||
struct timer_list timer;
|
||||
struct regulator *vdd;
|
||||
struct gpio_desc *reset_gpios;
|
||||
u32 x_plate_ohms;
|
||||
struct touchscreen_properties prop;
|
||||
};
|
||||
|
||||
static void bu21029_touch_report(struct bu21029_ts_data *bu21029, const u8 *buf)
|
||||
{
|
||||
u16 x, y, z1, z2;
|
||||
u32 rz;
|
||||
s32 max_pressure = input_abs_get_max(bu21029->in_dev, ABS_PRESSURE);
|
||||
|
||||
/*
|
||||
* compose upper 8 and lower 4 bits into a 12bit value:
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | ByteH | ByteL |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* |b07|b06|b05|b04|b03|b02|b01|b00|b07|b06|b05|b04|b03|b02|b01|b00|
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* |v11|v10|v09|v08|v07|v06|v05|v04|v03|v02|v01|v00| 0 | 0 | 0 | 0 |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
*/
|
||||
x = (buf[0] << 4) | (buf[1] >> 4);
|
||||
y = (buf[2] << 4) | (buf[3] >> 4);
|
||||
z1 = (buf[4] << 4) | (buf[5] >> 4);
|
||||
z2 = (buf[6] << 4) | (buf[7] >> 4);
|
||||
|
||||
if (z1 && z2) {
|
||||
/*
|
||||
* calculate Rz (pressure resistance value) by equation:
|
||||
* Rz = Rx * (x/Q) * ((z2/z1) - 1), where
|
||||
* Rx is x-plate resistance,
|
||||
* Q is the touch screen resolution (8bit = 256, 12bit = 4096)
|
||||
* x, z1, z2 are the measured positions.
|
||||
*/
|
||||
rz = z2 - z1;
|
||||
rz *= x;
|
||||
rz *= bu21029->x_plate_ohms;
|
||||
rz /= z1;
|
||||
rz = DIV_ROUND_CLOSEST(rz, SCALE_12BIT);
|
||||
if (rz <= max_pressure) {
|
||||
touchscreen_report_pos(bu21029->in_dev, &bu21029->prop,
|
||||
x, y, false);
|
||||
input_report_abs(bu21029->in_dev, ABS_PRESSURE,
|
||||
max_pressure - rz);
|
||||
input_report_key(bu21029->in_dev, BTN_TOUCH, 1);
|
||||
input_sync(bu21029->in_dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void bu21029_touch_release(struct timer_list *t)
|
||||
{
|
||||
struct bu21029_ts_data *bu21029 = from_timer(bu21029, t, timer);
|
||||
|
||||
input_report_abs(bu21029->in_dev, ABS_PRESSURE, 0);
|
||||
input_report_key(bu21029->in_dev, BTN_TOUCH, 0);
|
||||
input_sync(bu21029->in_dev);
|
||||
}
|
||||
|
||||
static irqreturn_t bu21029_touch_soft_irq(int irq, void *data)
|
||||
{
|
||||
struct bu21029_ts_data *bu21029 = data;
|
||||
u8 buf[BUF_LEN];
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Read touch data and deassert interrupt (will assert again after
|
||||
* INTVL_TIME + tConv4 for continuous touch)
|
||||
*/
|
||||
error = i2c_smbus_read_i2c_block_data(bu21029->client, BU21029_AUTOSCAN,
|
||||
sizeof(buf), buf);
|
||||
if (error < 0)
|
||||
goto out;
|
||||
|
||||
bu21029_touch_report(bu21029, buf);
|
||||
|
||||
/* reset timer for pen up detection */
|
||||
mod_timer(&bu21029->timer,
|
||||
jiffies + msecs_to_jiffies(PEN_UP_TIMEOUT_MS));
|
||||
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void bu21029_put_chip_in_reset(struct bu21029_ts_data *bu21029)
|
||||
{
|
||||
if (bu21029->reset_gpios) {
|
||||
gpiod_set_value_cansleep(bu21029->reset_gpios, 1);
|
||||
usleep_range(STOP_DELAY_MIN_US, STOP_DELAY_MAX_US);
|
||||
}
|
||||
}
|
||||
|
||||
static int bu21029_start_chip(struct input_dev *dev)
|
||||
{
|
||||
struct bu21029_ts_data *bu21029 = input_get_drvdata(dev);
|
||||
struct i2c_client *i2c = bu21029->client;
|
||||
struct {
|
||||
u8 reg;
|
||||
u8 value;
|
||||
} init_table[] = {
|
||||
{BU21029_CFR0_REG, CFR0_VALUE},
|
||||
{BU21029_CFR1_REG, CFR1_VALUE},
|
||||
{BU21029_CFR2_REG, CFR2_VALUE},
|
||||
{BU21029_CFR3_REG, CFR3_VALUE},
|
||||
{BU21029_LDO_REG, LDO_VALUE}
|
||||
};
|
||||
int error, i;
|
||||
__be16 hwid;
|
||||
|
||||
error = regulator_enable(bu21029->vdd);
|
||||
if (error) {
|
||||
dev_err(&i2c->dev, "failed to power up chip: %d", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* take chip out of reset */
|
||||
if (bu21029->reset_gpios) {
|
||||
gpiod_set_value_cansleep(bu21029->reset_gpios, 0);
|
||||
msleep(START_DELAY_MS);
|
||||
}
|
||||
|
||||
error = i2c_smbus_read_i2c_block_data(i2c, BU21029_HWID_REG,
|
||||
sizeof(hwid), (u8 *)&hwid);
|
||||
if (error < 0) {
|
||||
dev_err(&i2c->dev, "failed to read HW ID\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (be16_to_cpu(hwid) != SUPPORTED_HWID) {
|
||||
dev_err(&i2c->dev,
|
||||
"unsupported HW ID 0x%x\n", be16_to_cpu(hwid));
|
||||
error = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(init_table); ++i) {
|
||||
error = i2c_smbus_write_byte_data(i2c,
|
||||
init_table[i].reg,
|
||||
init_table[i].value);
|
||||
if (error < 0) {
|
||||
dev_err(&i2c->dev,
|
||||
"failed to write %#02x to register %#02x: %d\n",
|
||||
init_table[i].value, init_table[i].reg,
|
||||
error);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
error = i2c_smbus_write_byte(i2c, BU21029_AUTOSCAN);
|
||||
if (error < 0) {
|
||||
dev_err(&i2c->dev, "failed to start autoscan\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
enable_irq(bu21029->client->irq);
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
bu21029_put_chip_in_reset(bu21029);
|
||||
regulator_disable(bu21029->vdd);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void bu21029_stop_chip(struct input_dev *dev)
|
||||
{
|
||||
struct bu21029_ts_data *bu21029 = input_get_drvdata(dev);
|
||||
|
||||
disable_irq(bu21029->client->irq);
|
||||
del_timer_sync(&bu21029->timer);
|
||||
|
||||
bu21029_put_chip_in_reset(bu21029);
|
||||
regulator_disable(bu21029->vdd);
|
||||
}
|
||||
|
||||
static int bu21029_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct bu21029_ts_data *bu21029;
|
||||
struct input_dev *in_dev;
|
||||
int error;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_WRITE_BYTE |
|
||||
I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
|
||||
dev_err(&client->dev,
|
||||
"i2c functionality support is not sufficient\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
bu21029 = devm_kzalloc(&client->dev, sizeof(*bu21029), GFP_KERNEL);
|
||||
if (!bu21029)
|
||||
return -ENOMEM;
|
||||
|
||||
error = device_property_read_u32(&client->dev, "rohm,x-plate-ohms",
|
||||
&bu21029->x_plate_ohms);
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"invalid 'x-plate-ohms' supplied: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
bu21029->vdd = devm_regulator_get(&client->dev, "vdd");
|
||||
if (IS_ERR(bu21029->vdd)) {
|
||||
error = PTR_ERR(bu21029->vdd);
|
||||
if (error != -EPROBE_DEFER)
|
||||
dev_err(&client->dev,
|
||||
"failed to acquire 'vdd' supply: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
bu21029->reset_gpios = devm_gpiod_get_optional(&client->dev,
|
||||
"reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(bu21029->reset_gpios)) {
|
||||
error = PTR_ERR(bu21029->reset_gpios);
|
||||
if (error != -EPROBE_DEFER)
|
||||
dev_err(&client->dev,
|
||||
"failed to acquire 'reset' gpio: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
in_dev = devm_input_allocate_device(&client->dev);
|
||||
if (!in_dev) {
|
||||
dev_err(&client->dev, "unable to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bu21029->client = client;
|
||||
bu21029->in_dev = in_dev;
|
||||
timer_setup(&bu21029->timer, bu21029_touch_release, 0);
|
||||
|
||||
in_dev->name = DRIVER_NAME;
|
||||
in_dev->id.bustype = BUS_I2C;
|
||||
in_dev->open = bu21029_start_chip;
|
||||
in_dev->close = bu21029_stop_chip;
|
||||
|
||||
input_set_capability(in_dev, EV_KEY, BTN_TOUCH);
|
||||
input_set_abs_params(in_dev, ABS_X, 0, MAX_12BIT, 0, 0);
|
||||
input_set_abs_params(in_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
|
||||
input_set_abs_params(in_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
|
||||
touchscreen_parse_properties(in_dev, false, &bu21029->prop);
|
||||
|
||||
input_set_drvdata(in_dev, bu21029);
|
||||
|
||||
irq_set_status_flags(client->irq, IRQ_NOAUTOEN);
|
||||
error = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL, bu21029_touch_soft_irq,
|
||||
IRQF_ONESHOT, DRIVER_NAME, bu21029);
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"unable to request touch irq: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = input_register_device(in_dev);
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"unable to register input device: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, bu21029);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused bu21029_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *i2c = to_i2c_client(dev);
|
||||
struct bu21029_ts_data *bu21029 = i2c_get_clientdata(i2c);
|
||||
|
||||
if (!device_may_wakeup(dev)) {
|
||||
mutex_lock(&bu21029->in_dev->mutex);
|
||||
if (bu21029->in_dev->users)
|
||||
bu21029_stop_chip(bu21029->in_dev);
|
||||
mutex_unlock(&bu21029->in_dev->mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused bu21029_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *i2c = to_i2c_client(dev);
|
||||
struct bu21029_ts_data *bu21029 = i2c_get_clientdata(i2c);
|
||||
|
||||
if (!device_may_wakeup(dev)) {
|
||||
mutex_lock(&bu21029->in_dev->mutex);
|
||||
if (bu21029->in_dev->users)
|
||||
bu21029_start_chip(bu21029->in_dev);
|
||||
mutex_unlock(&bu21029->in_dev->mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static SIMPLE_DEV_PM_OPS(bu21029_pm_ops, bu21029_suspend, bu21029_resume);
|
||||
|
||||
static const struct i2c_device_id bu21029_ids[] = {
|
||||
{ DRIVER_NAME, 0 },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bu21029_ids);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id bu21029_of_ids[] = {
|
||||
{ .compatible = "rohm,bu21029" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bu21029_of_ids);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver bu21029_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = of_match_ptr(bu21029_of_ids),
|
||||
.pm = &bu21029_pm_ops,
|
||||
},
|
||||
.id_table = bu21029_ids,
|
||||
.probe = bu21029_probe,
|
||||
};
|
||||
module_i2c_driver(bu21029_driver);
|
||||
|
||||
MODULE_AUTHOR("Zhu Yi <yi.zhu5@cn.bosch.com>");
|
||||
MODULE_DESCRIPTION("Rohm BU21029 touchscreen controller driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
* Touch Screen driver for EETI's I2C connected touch screen panels
|
||||
* Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
|
||||
* Copyright (c) 2009,2018 Daniel Mack <daniel@zonque.org>
|
||||
*
|
||||
* See EETI's software guide for the protocol specification:
|
||||
* http://home.eeti.com.tw/web20/eg/guide.htm
|
||||
* http://home.eeti.com.tw/documentation.html
|
||||
*
|
||||
* Based on migor_ts.c
|
||||
* Copyright (c) 2008 Magnus Damm
|
||||
@@ -25,28 +25,22 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/touchscreen.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
static bool flip_x;
|
||||
module_param(flip_x, bool, 0644);
|
||||
MODULE_PARM_DESC(flip_x, "flip x coordinate");
|
||||
|
||||
static bool flip_y;
|
||||
module_param(flip_y, bool, 0644);
|
||||
MODULE_PARM_DESC(flip_y, "flip y coordinate");
|
||||
|
||||
struct eeti_ts {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input;
|
||||
struct gpio_desc *attn_gpio;
|
||||
struct touchscreen_properties props;
|
||||
bool running;
|
||||
};
|
||||
|
||||
@@ -73,17 +67,10 @@ static void eeti_ts_report_event(struct eeti_ts *eeti, u8 *buf)
|
||||
x >>= res - EETI_TS_BITDEPTH;
|
||||
y >>= res - EETI_TS_BITDEPTH;
|
||||
|
||||
if (flip_x)
|
||||
x = EETI_MAXVAL - x;
|
||||
|
||||
if (flip_y)
|
||||
y = EETI_MAXVAL - y;
|
||||
|
||||
if (buf[0] & REPORT_BIT_HAS_PRESSURE)
|
||||
input_report_abs(eeti->input, ABS_PRESSURE, buf[5]);
|
||||
|
||||
input_report_abs(eeti->input, ABS_X, x);
|
||||
input_report_abs(eeti->input, ABS_Y, y);
|
||||
touchscreen_report_pos(eeti->input, &eeti->props, x, y, false);
|
||||
input_report_key(eeti->input, BTN_TOUCH, buf[0] & REPORT_BIT_PRESSED);
|
||||
input_sync(eeti->input);
|
||||
}
|
||||
@@ -178,6 +165,8 @@ static int eeti_ts_probe(struct i2c_client *client,
|
||||
input_set_abs_params(input, ABS_Y, 0, EETI_MAXVAL, 0, 0);
|
||||
input_set_abs_params(input, ABS_PRESSURE, 0, 0xff, 0, 0);
|
||||
|
||||
touchscreen_parse_properties(input, false, &eeti->props);
|
||||
|
||||
input->name = client->name;
|
||||
input->id.bustype = BUS_I2C;
|
||||
input->open = eeti_ts_open;
|
||||
@@ -262,10 +251,18 @@ static const struct i2c_device_id eeti_ts_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, eeti_ts_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id of_eeti_ts_match[] = {
|
||||
{ .compatible = "eeti,exc3000-i2c", },
|
||||
{ }
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct i2c_driver eeti_ts_driver = {
|
||||
.driver = {
|
||||
.name = "eeti_ts",
|
||||
.pm = &eeti_ts_pm,
|
||||
.of_match_table = of_match_ptr(of_eeti_ts_match),
|
||||
},
|
||||
.probe = eeti_ts_probe,
|
||||
.id_table = eeti_ts_id,
|
||||
@@ -274,5 +271,5 @@ static struct i2c_driver eeti_ts_driver = {
|
||||
module_i2c_driver(eeti_ts_driver);
|
||||
|
||||
MODULE_DESCRIPTION("EETI Touchscreen driver");
|
||||
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
|
||||
MODULE_AUTHOR("Daniel Mack <daniel@zonque.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@@ -1,13 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Driver for EETI eGalax Multiple Touch Controller
|
||||
*
|
||||
* Copyright (C) 2011 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* based on max11801_ts.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/* EETI eGalax serial touch screen controller is a I2C based multiple
|
||||
|
@@ -352,6 +352,7 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
|
||||
|
||||
case 1: /* 6-byte protocol */
|
||||
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 15, 0, 0);
|
||||
/* fall through */
|
||||
|
||||
case 2: /* 4-byte protocol */
|
||||
input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0);
|
||||
|
@@ -1,16 +1,11 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* Based on driver from 2011:
|
||||
* Juergen Beisert, Pengutronix <kernel@pengutronix.de>
|
||||
*
|
||||
* This is the driver for the imx25 TCQ (Touchscreen Conversion Queue)
|
||||
* connected to the imx25 ADC.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Copyright (C) 2014-2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de>
|
||||
// Based on driver from 2011:
|
||||
// Juergen Beisert, Pengutronix <kernel@pengutronix.de>
|
||||
//
|
||||
// This is the driver for the imx25 TCQ (Touchscreen Conversion Queue)
|
||||
// connected to the imx25 ADC.
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
|
@@ -20,10 +20,6 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
|
@@ -1,12 +1,8 @@
|
||||
/*
|
||||
* Freescale i.MX6UL touchscreen controller driver
|
||||
*
|
||||
* Copyright (C) 2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Freescale i.MX6UL touchscreen controller driver
|
||||
//
|
||||
// Copyright (C) 2015 Freescale Semiconductor, Inc.
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@@ -466,7 +466,7 @@ static bool raydium_i2c_boot_trigger(struct i2c_client *client)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool raydium_i2c_fw_trigger(struct i2c_client *client)
|
||||
@@ -492,7 +492,7 @@ static bool raydium_i2c_fw_trigger(struct i2c_client *client)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int raydium_i2c_check_path(struct i2c_client *client)
|
||||
|
@@ -1142,7 +1142,7 @@ static int __maybe_unused wdt87xx_resume(struct device *dev)
|
||||
* The chip may have been reset while system is resuming,
|
||||
* give it some time to settle.
|
||||
*/
|
||||
mdelay(100);
|
||||
msleep(100);
|
||||
|
||||
error = wdt87xx_send_command(client, VND_CMD_START, 0);
|
||||
if (error)
|
||||
|
在新工单中引用
屏蔽一个用户