FILE
nvec_ps2.c
File preview with syntax highlighting.
linux-6.19.14/drivers/staging/nvec/nvec_ps2.c
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * nvec_ps2: mouse driver for a NVIDIA compliant embedded controller 4 * 5 * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.launchpad.net> 6 * 7 * Authors: Pierre-Hugues Husson <phhusson@free.fr> 8 * Ilya Petrov <ilya.muromec@gmail.com> 9 * Marc Dietrich <marvin24@gmx.de> 10 */ 11 12#include <linux/module.h> 13#include <linux/slab.h> 14#include <linux/serio.h> 15#include <linux/delay.h> 16#include <linux/platform_device.h> 17 18#include "nvec.h" 19 20#define PACKET_SIZE 6 21 22#define ENABLE_MOUSE 0xf4 23#define DISABLE_MOUSE 0xf5 24#define PSMOUSE_RST 0xff 25 26enum ps2_subcmds { 27 SEND_COMMAND = 1, 28 RECEIVE_N, 29 AUTO_RECEIVE_N, 30 CANCEL_AUTO_RECEIVE, 31}; 32 33struct nvec_ps2 { 34 struct serio *ser_dev; 35 struct notifier_block notifier; 36 struct nvec_chip *nvec; 37}; 38 39static struct nvec_ps2 ps2_dev; 40 41static int ps2_startstreaming(struct serio *ser_dev) 42{ 43 unsigned char buf[] = { NVEC_PS2, AUTO_RECEIVE_N, PACKET_SIZE }; 44 45 return nvec_write_async(ps2_dev.nvec, buf, sizeof(buf)); 46} 47 48static void ps2_stopstreaming(struct serio *ser_dev) 49{ 50 unsigned char buf[] = { NVEC_PS2, CANCEL_AUTO_RECEIVE }; 51 52 nvec_write_async(ps2_dev.nvec, buf, sizeof(buf)); 53} 54 55static int nvec_ps2_notifier(struct notifier_block *nb, 56 unsigned long event_type, void *data) 57{ 58 int i; 59 unsigned char *msg = data; 60 61 switch (event_type) { 62 case NVEC_PS2_EVT: 63 for (i = 0; i < msg[1]; i++) 64 serio_interrupt(ps2_dev.ser_dev, msg[2 + i], 0); 65 return NOTIFY_STOP; 66 67 case NVEC_PS2: 68 if (msg[2] == 1) { 69 for (i = 0; i < (msg[1] - 2); i++) 70 serio_interrupt(ps2_dev.ser_dev, msg[i + 4], 0); 71 } 72 73 return NOTIFY_STOP; 74 } 75 76 return NOTIFY_DONE; 77} 78 79static int ps2_sendcommand(struct serio *ser_dev, unsigned char cmd) 80{ 81 unsigned char buf[] = { NVEC_PS2, SEND_COMMAND, ENABLE_MOUSE, 1 }; 82 struct nvec_msg *msg; 83 int ret; 84 85 buf[2] = cmd & 0xff; 86 87 dev_dbg(&ser_dev->dev, "Sending ps2 cmd %02x\n", cmd); 88 89 ret = nvec_write_sync(ps2_dev.nvec, buf, sizeof(buf), &msg); 90 if (ret < 0) 91 return ret; 92 93 nvec_ps2_notifier(NULL, NVEC_PS2, msg->data); 94 95 nvec_msg_free(ps2_dev.nvec, msg); 96 97 return 0; 98} 99 100static int nvec_mouse_probe(struct platform_device *pdev) 101{ 102 struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent); 103 struct serio *ser_dev; 104 105 ser_dev = kzalloc(sizeof(*ser_dev), GFP_KERNEL); 106 if (!ser_dev) 107 return -ENOMEM; 108 109 ser_dev->id.type = SERIO_8042; 110 ser_dev->write = ps2_sendcommand; 111 ser_dev->start = ps2_startstreaming; 112 ser_dev->stop = ps2_stopstreaming; 113 114 strscpy(ser_dev->name, "nvec mouse", sizeof(ser_dev->name)); 115 strscpy(ser_dev->phys, "nvec", sizeof(ser_dev->phys)); 116 117 ps2_dev.ser_dev = ser_dev; 118 ps2_dev.notifier.notifier_call = nvec_ps2_notifier; 119 ps2_dev.nvec = nvec; 120 nvec_register_notifier(nvec, &ps2_dev.notifier, 0); 121 122 serio_register_port(ser_dev); 123 124 return 0; 125} 126 127static void nvec_mouse_remove(struct platform_device *pdev) 128{ 129 struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent); 130 131 ps2_sendcommand(ps2_dev.ser_dev, DISABLE_MOUSE); 132 ps2_stopstreaming(ps2_dev.ser_dev); 133 nvec_unregister_notifier(nvec, &ps2_dev.notifier); 134 serio_unregister_port(ps2_dev.ser_dev); 135} 136 137#ifdef CONFIG_PM_SLEEP 138static int nvec_mouse_suspend(struct device *dev) 139{ 140 /* disable mouse */ 141 ps2_sendcommand(ps2_dev.ser_dev, DISABLE_MOUSE); 142 143 /* send cancel autoreceive */ 144 ps2_stopstreaming(ps2_dev.ser_dev); 145 146 return 0; 147} 148 149static int nvec_mouse_resume(struct device *dev) 150{ 151 /* start streaming */ 152 ps2_startstreaming(ps2_dev.ser_dev); 153 154 /* enable mouse */ 155 ps2_sendcommand(ps2_dev.ser_dev, ENABLE_MOUSE); 156 157 return 0; 158} 159#endif 160 161static SIMPLE_DEV_PM_OPS(nvec_mouse_pm_ops, nvec_mouse_suspend, 162 nvec_mouse_resume); 163 164static struct platform_driver nvec_mouse_driver = { 165 .probe = nvec_mouse_probe, 166 .remove = nvec_mouse_remove, 167 .driver = { 168 .name = "nvec-mouse", 169 .pm = &nvec_mouse_pm_ops, 170 }, 171}; 172 173module_platform_driver(nvec_mouse_driver); 174 175MODULE_DESCRIPTION("NVEC mouse driver"); 176MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>"); 177MODULE_ALIAS("platform:nvec-mouse"); 178MODULE_LICENSE("GPL");
~/
Read-only file preview.