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

ams-core.c (5407B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Apple Motion Sensor driver
      4 *
      5 * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
      6 * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
      7 */
      8
      9#include <linux/module.h>
     10#include <linux/types.h>
     11#include <linux/errno.h>
     12#include <linux/init.h>
     13#include <linux/of_platform.h>
     14#include <asm/pmac_pfunc.h>
     15
     16#include "ams.h"
     17
     18/* There is only one motion sensor per machine */
     19struct ams ams_info;
     20
     21static bool verbose;
     22module_param(verbose, bool, 0644);
     23MODULE_PARM_DESC(verbose, "Show free falls and shocks in kernel output");
     24
     25/* Call with ams_info.lock held! */
     26void ams_sensors(s8 *x, s8 *y, s8 *z)
     27{
     28	u32 orient = ams_info.vflag? ams_info.orient1 : ams_info.orient2;
     29
     30	if (orient & 0x80)
     31		/* X and Y swapped */
     32		ams_info.get_xyz(y, x, z);
     33	else
     34		ams_info.get_xyz(x, y, z);
     35
     36	if (orient & 0x04)
     37		*z = ~(*z);
     38	if (orient & 0x02)
     39		*y = ~(*y);
     40	if (orient & 0x01)
     41		*x = ~(*x);
     42}
     43
     44static ssize_t ams_show_current(struct device *dev,
     45	struct device_attribute *attr, char *buf)
     46{
     47	s8 x, y, z;
     48
     49	mutex_lock(&ams_info.lock);
     50	ams_sensors(&x, &y, &z);
     51	mutex_unlock(&ams_info.lock);
     52
     53	return sysfs_emit(buf, "%d %d %d\n", x, y, z);
     54}
     55
     56static DEVICE_ATTR(current, S_IRUGO, ams_show_current, NULL);
     57
     58static void ams_handle_irq(void *data)
     59{
     60	enum ams_irq irq = *((enum ams_irq *)data);
     61
     62	spin_lock(&ams_info.irq_lock);
     63
     64	ams_info.worker_irqs |= irq;
     65	schedule_work(&ams_info.worker);
     66
     67	spin_unlock(&ams_info.irq_lock);
     68}
     69
     70static enum ams_irq ams_freefall_irq_data = AMS_IRQ_FREEFALL;
     71static struct pmf_irq_client ams_freefall_client = {
     72	.owner = THIS_MODULE,
     73	.handler = ams_handle_irq,
     74	.data = &ams_freefall_irq_data,
     75};
     76
     77static enum ams_irq ams_shock_irq_data = AMS_IRQ_SHOCK;
     78static struct pmf_irq_client ams_shock_client = {
     79	.owner = THIS_MODULE,
     80	.handler = ams_handle_irq,
     81	.data = &ams_shock_irq_data,
     82};
     83
     84/* Once hard disk parking is implemented in the kernel, this function can
     85 * trigger it.
     86 */
     87static void ams_worker(struct work_struct *work)
     88{
     89	unsigned long flags;
     90	u8 irqs_to_clear;
     91
     92	mutex_lock(&ams_info.lock);
     93
     94	spin_lock_irqsave(&ams_info.irq_lock, flags);
     95	irqs_to_clear = ams_info.worker_irqs;
     96
     97	if (ams_info.worker_irqs & AMS_IRQ_FREEFALL) {
     98		if (verbose)
     99			printk(KERN_INFO "ams: freefall detected!\n");
    100
    101		ams_info.worker_irqs &= ~AMS_IRQ_FREEFALL;
    102	}
    103
    104	if (ams_info.worker_irqs & AMS_IRQ_SHOCK) {
    105		if (verbose)
    106			printk(KERN_INFO "ams: shock detected!\n");
    107
    108		ams_info.worker_irqs &= ~AMS_IRQ_SHOCK;
    109	}
    110
    111	spin_unlock_irqrestore(&ams_info.irq_lock, flags);
    112
    113	ams_info.clear_irq(irqs_to_clear);
    114
    115	mutex_unlock(&ams_info.lock);
    116}
    117
    118/* Call with ams_info.lock held! */
    119int ams_sensor_attach(void)
    120{
    121	int result;
    122	const u32 *prop;
    123
    124	/* Get orientation */
    125	prop = of_get_property(ams_info.of_node, "orientation", NULL);
    126	if (!prop)
    127		return -ENODEV;
    128	ams_info.orient1 = *prop;
    129	ams_info.orient2 = *(prop + 1);
    130
    131	/* Register freefall interrupt handler */
    132	result = pmf_register_irq_client(ams_info.of_node,
    133			"accel-int-1",
    134			&ams_freefall_client);
    135	if (result < 0)
    136		return -ENODEV;
    137
    138	/* Reset saved irqs */
    139	ams_info.worker_irqs = 0;
    140
    141	/* Register shock interrupt handler */
    142	result = pmf_register_irq_client(ams_info.of_node,
    143			"accel-int-2",
    144			&ams_shock_client);
    145	if (result < 0)
    146		goto release_freefall;
    147
    148	/* Create device */
    149	ams_info.of_dev = of_platform_device_create(ams_info.of_node, "ams", NULL);
    150	if (!ams_info.of_dev) {
    151		result = -ENODEV;
    152		goto release_shock;
    153	}
    154
    155	/* Create attributes */
    156	result = device_create_file(&ams_info.of_dev->dev, &dev_attr_current);
    157	if (result)
    158		goto release_of;
    159
    160	ams_info.vflag = !!(ams_info.get_vendor() & 0x10);
    161
    162	/* Init input device */
    163	result = ams_input_init();
    164	if (result)
    165		goto release_device_file;
    166
    167	return result;
    168release_device_file:
    169	device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
    170release_of:
    171	of_device_unregister(ams_info.of_dev);
    172release_shock:
    173	pmf_unregister_irq_client(&ams_shock_client);
    174release_freefall:
    175	pmf_unregister_irq_client(&ams_freefall_client);
    176	return result;
    177}
    178
    179int __init ams_init(void)
    180{
    181	struct device_node *np;
    182
    183	spin_lock_init(&ams_info.irq_lock);
    184	mutex_init(&ams_info.lock);
    185	INIT_WORK(&ams_info.worker, ams_worker);
    186
    187#ifdef CONFIG_SENSORS_AMS_I2C
    188	np = of_find_node_by_name(NULL, "accelerometer");
    189	if (np && of_device_is_compatible(np, "AAPL,accelerometer_1"))
    190		/* Found I2C motion sensor */
    191		return ams_i2c_init(np);
    192#endif
    193
    194#ifdef CONFIG_SENSORS_AMS_PMU
    195	np = of_find_node_by_name(NULL, "sms");
    196	if (np && of_device_is_compatible(np, "sms"))
    197		/* Found PMU motion sensor */
    198		return ams_pmu_init(np);
    199#endif
    200	return -ENODEV;
    201}
    202
    203void ams_sensor_detach(void)
    204{
    205	/* Remove input device */
    206	ams_input_exit();
    207
    208	/* Remove attributes */
    209	device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
    210
    211	/* Flush interrupt worker
    212	 *
    213	 * We do this after ams_info.exit(), because an interrupt might
    214	 * have arrived before disabling them.
    215	 */
    216	flush_work(&ams_info.worker);
    217
    218	/* Remove device */
    219	of_device_unregister(ams_info.of_dev);
    220
    221	/* Remove handler */
    222	pmf_unregister_irq_client(&ams_shock_client);
    223	pmf_unregister_irq_client(&ams_freefall_client);
    224}
    225
    226static void __exit ams_exit(void)
    227{
    228	/* Shut down implementation */
    229	ams_info.exit();
    230}
    231
    232MODULE_AUTHOR("Stelian Pop, Michael Hanselmann");
    233MODULE_DESCRIPTION("Apple Motion Sensor driver");
    234MODULE_LICENSE("GPL");
    235
    236module_init(ams_init);
    237module_exit(ams_exit);