cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ct82c710.c (5859B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Copyright (c) 1999-2001 Vojtech Pavlik
      4 */
      5
      6/*
      7 *  82C710 C&T mouse port chip driver for Linux
      8 */
      9
     10/*
     11 */
     12
     13#include <linux/delay.h>
     14#include <linux/module.h>
     15#include <linux/ioport.h>
     16#include <linux/init.h>
     17#include <linux/interrupt.h>
     18#include <linux/serio.h>
     19#include <linux/errno.h>
     20#include <linux/err.h>
     21#include <linux/platform_device.h>
     22#include <linux/slab.h>
     23
     24#include <asm/io.h>
     25
     26MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
     27MODULE_DESCRIPTION("82C710 C&T mouse port chip driver");
     28MODULE_LICENSE("GPL");
     29
     30/*
     31 * ct82c710 interface
     32 */
     33
     34#define CT82C710_DEV_IDLE     0x01		/* Device Idle */
     35#define CT82C710_RX_FULL      0x02		/* Device Char received */
     36#define CT82C710_TX_IDLE      0x04		/* Device XMIT Idle */
     37#define CT82C710_RESET        0x08		/* Device Reset */
     38#define CT82C710_INTS_ON      0x10		/* Device Interrupt On */
     39#define CT82C710_ERROR_FLAG   0x20		/* Device Error */
     40#define CT82C710_CLEAR        0x40		/* Device Clear */
     41#define CT82C710_ENABLE       0x80		/* Device Enable */
     42
     43#define CT82C710_IRQ          12
     44
     45#define CT82C710_DATA         ct82c710_iores.start
     46#define CT82C710_STATUS       (ct82c710_iores.start + 1)
     47
     48static struct serio *ct82c710_port;
     49static struct platform_device *ct82c710_device;
     50static struct resource ct82c710_iores;
     51
     52/*
     53 * Interrupt handler for the 82C710 mouse port. A character
     54 * is waiting in the 82C710.
     55 */
     56
     57static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id)
     58{
     59	return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0);
     60}
     61
     62/*
     63 * Wait for device to send output char and flush any input char.
     64 */
     65
     66static int ct82c170_wait(void)
     67{
     68	int timeout = 60000;
     69
     70	while ((inb(CT82C710_STATUS) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE))
     71		       != (CT82C710_DEV_IDLE | CT82C710_TX_IDLE) && timeout) {
     72
     73		if (inb_p(CT82C710_STATUS) & CT82C710_RX_FULL) inb_p(CT82C710_DATA);
     74
     75		udelay(1);
     76		timeout--;
     77	}
     78
     79	return !timeout;
     80}
     81
     82static void ct82c710_close(struct serio *serio)
     83{
     84	if (ct82c170_wait())
     85		printk(KERN_WARNING "ct82c710.c: Device busy in close()\n");
     86
     87	outb_p(inb_p(CT82C710_STATUS) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), CT82C710_STATUS);
     88
     89	if (ct82c170_wait())
     90		printk(KERN_WARNING "ct82c710.c: Device busy in close()\n");
     91
     92	free_irq(CT82C710_IRQ, NULL);
     93}
     94
     95static int ct82c710_open(struct serio *serio)
     96{
     97	unsigned char status;
     98	int err;
     99
    100	err = request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL);
    101	if (err)
    102		return err;
    103
    104	status = inb_p(CT82C710_STATUS);
    105
    106	status |= (CT82C710_ENABLE | CT82C710_RESET);
    107	outb_p(status, CT82C710_STATUS);
    108
    109	status &= ~(CT82C710_RESET);
    110	outb_p(status, CT82C710_STATUS);
    111
    112	status |= CT82C710_INTS_ON;
    113	outb_p(status, CT82C710_STATUS);	/* Enable interrupts */
    114
    115	while (ct82c170_wait()) {
    116		printk(KERN_ERR "ct82c710: Device busy in open()\n");
    117		status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON);
    118		outb_p(status, CT82C710_STATUS);
    119		free_irq(CT82C710_IRQ, NULL);
    120		return -EBUSY;
    121	}
    122
    123	return 0;
    124}
    125
    126/*
    127 * Write to the 82C710 mouse device.
    128 */
    129
    130static int ct82c710_write(struct serio *port, unsigned char c)
    131{
    132	if (ct82c170_wait()) return -1;
    133	outb_p(c, CT82C710_DATA);
    134	return 0;
    135}
    136
    137/*
    138 * See if we can find a 82C710 device. Read mouse address.
    139 */
    140
    141static int __init ct82c710_detect(void)
    142{
    143	outb_p(0x55, 0x2fa);				/* Any value except 9, ff or 36 */
    144	outb_p(0xaa, 0x3fa);				/* Inverse of 55 */
    145	outb_p(0x36, 0x3fa);				/* Address the chip */
    146	outb_p(0xe4, 0x3fa);				/* 390/4; 390 = config address */
    147	outb_p(0x1b, 0x2fa);				/* Inverse of e4 */
    148	outb_p(0x0f, 0x390);				/* Write index */
    149	if (inb_p(0x391) != 0xe4)			/* Config address found? */
    150		return -ENODEV;				/* No: no 82C710 here */
    151
    152	outb_p(0x0d, 0x390);				/* Write index */
    153	ct82c710_iores.start = inb_p(0x391) << 2;	/* Get mouse I/O address */
    154	ct82c710_iores.end = ct82c710_iores.start + 1;
    155	ct82c710_iores.flags = IORESOURCE_IO;
    156	outb_p(0x0f, 0x390);
    157	outb_p(0x0f, 0x391);				/* Close config mode */
    158
    159	return 0;
    160}
    161
    162static int ct82c710_probe(struct platform_device *dev)
    163{
    164	ct82c710_port = kzalloc(sizeof(struct serio), GFP_KERNEL);
    165	if (!ct82c710_port)
    166		return -ENOMEM;
    167
    168	ct82c710_port->id.type = SERIO_8042;
    169	ct82c710_port->dev.parent = &dev->dev;
    170	ct82c710_port->open = ct82c710_open;
    171	ct82c710_port->close = ct82c710_close;
    172	ct82c710_port->write = ct82c710_write;
    173	strlcpy(ct82c710_port->name, "C&T 82c710 mouse port",
    174		sizeof(ct82c710_port->name));
    175	snprintf(ct82c710_port->phys, sizeof(ct82c710_port->phys),
    176		 "isa%16llx/serio0", (unsigned long long)CT82C710_DATA);
    177
    178	serio_register_port(ct82c710_port);
    179
    180	printk(KERN_INFO "serio: C&T 82c710 mouse port at %#llx irq %d\n",
    181		(unsigned long long)CT82C710_DATA, CT82C710_IRQ);
    182
    183	return 0;
    184}
    185
    186static int ct82c710_remove(struct platform_device *dev)
    187{
    188	serio_unregister_port(ct82c710_port);
    189
    190	return 0;
    191}
    192
    193static struct platform_driver ct82c710_driver = {
    194	.driver		= {
    195		.name	= "ct82c710",
    196	},
    197	.probe		= ct82c710_probe,
    198	.remove		= ct82c710_remove,
    199};
    200
    201
    202static int __init ct82c710_init(void)
    203{
    204	int error;
    205
    206	error = ct82c710_detect();
    207	if (error)
    208		return error;
    209
    210	error = platform_driver_register(&ct82c710_driver);
    211	if (error)
    212		return error;
    213
    214	ct82c710_device = platform_device_alloc("ct82c710", -1);
    215	if (!ct82c710_device) {
    216		error = -ENOMEM;
    217		goto err_unregister_driver;
    218	}
    219
    220	error = platform_device_add_resources(ct82c710_device, &ct82c710_iores, 1);
    221	if (error)
    222		goto err_free_device;
    223
    224	error = platform_device_add(ct82c710_device);
    225	if (error)
    226		goto err_free_device;
    227
    228	return 0;
    229
    230 err_free_device:
    231	platform_device_put(ct82c710_device);
    232 err_unregister_driver:
    233	platform_driver_unregister(&ct82c710_driver);
    234	return error;
    235}
    236
    237static void __exit ct82c710_exit(void)
    238{
    239	platform_device_unregister(ct82c710_device);
    240	platform_driver_unregister(&ct82c710_driver);
    241}
    242
    243module_init(ct82c710_init);
    244module_exit(ct82c710_exit);