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

display7seg.c (6280B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* display7seg.c - Driver implementation for the 7-segment display
      3 *                 present on Sun Microsystems CP1400 and CP1500
      4 *
      5 * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
      6 */
      7
      8#include <linux/device.h>
      9#include <linux/kernel.h>
     10#include <linux/module.h>
     11#include <linux/fs.h>
     12#include <linux/errno.h>
     13#include <linux/major.h>
     14#include <linux/miscdevice.h>
     15#include <linux/ioport.h>		/* request_region */
     16#include <linux/slab.h>
     17#include <linux/mutex.h>
     18#include <linux/of.h>
     19#include <linux/of_device.h>
     20#include <linux/atomic.h>
     21#include <linux/uaccess.h>		/* put_/get_user			*/
     22#include <asm/io.h>
     23
     24#include <asm/display7seg.h>
     25
     26#define DRIVER_NAME	"d7s"
     27#define PFX		DRIVER_NAME ": "
     28
     29static DEFINE_MUTEX(d7s_mutex);
     30static int sol_compat = 0;		/* Solaris compatibility mode	*/
     31
     32/* Solaris compatibility flag -
     33 * The Solaris implementation omits support for several
     34 * documented driver features (ref Sun doc 806-0180-03).  
     35 * By default, this module supports the documented driver 
     36 * abilities, rather than the Solaris implementation:
     37 *
     38 * 	1) Device ALWAYS reverts to OBP-specified FLIPPED mode
     39 * 	   upon closure of device or module unload.
     40 * 	2) Device ioctls D7SIOCRD/D7SIOCWR honor toggling of
     41 * 	   FLIP bit
     42 *
     43 * If you wish the device to operate as under Solaris,
     44 * omitting above features, set this parameter to non-zero.
     45 */
     46module_param(sol_compat, int, 0);
     47MODULE_PARM_DESC(sol_compat, 
     48		 "Disables documented functionality omitted from Solaris driver");
     49
     50MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
     51MODULE_DESCRIPTION("7-Segment Display driver for Sun Microsystems CP1400/1500");
     52MODULE_LICENSE("GPL");
     53
     54struct d7s {
     55	void __iomem	*regs;
     56	bool		flipped;
     57};
     58struct d7s *d7s_device;
     59
     60/*
     61 * Register block address- see header for details
     62 * -----------------------------------------
     63 * | DP | ALARM | FLIP | 4 | 3 | 2 | 1 | 0 |
     64 * -----------------------------------------
     65 *
     66 * DP 		- Toggles decimal point on/off 
     67 * ALARM	- Toggles "Alarm" LED green/red
     68 * FLIP		- Inverts display for upside-down mounted board
     69 * bits 0-4	- 7-segment display contents
     70 */
     71static atomic_t d7s_users = ATOMIC_INIT(0);
     72
     73static int d7s_open(struct inode *inode, struct file *f)
     74{
     75	if (D7S_MINOR != iminor(inode))
     76		return -ENODEV;
     77	atomic_inc(&d7s_users);
     78	return 0;
     79}
     80
     81static int d7s_release(struct inode *inode, struct file *f)
     82{
     83	/* Reset flipped state to OBP default only if
     84	 * no other users have the device open and we
     85	 * are not operating in solaris-compat mode
     86	 */
     87	if (atomic_dec_and_test(&d7s_users) && !sol_compat) {
     88		struct d7s *p = d7s_device;
     89		u8 regval = 0;
     90
     91		regval = readb(p->regs);
     92		if (p->flipped)
     93			regval |= D7S_FLIP;
     94		else
     95			regval &= ~D7S_FLIP;
     96		writeb(regval, p->regs);
     97	}
     98
     99	return 0;
    100}
    101
    102static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    103{
    104	struct d7s *p = d7s_device;
    105	u8 regs = readb(p->regs);
    106	int error = 0;
    107	u8 ireg = 0;
    108
    109	if (D7S_MINOR != iminor(file_inode(file)))
    110		return -ENODEV;
    111
    112	mutex_lock(&d7s_mutex);
    113	switch (cmd) {
    114	case D7SIOCWR:
    115		/* assign device register values we mask-out D7S_FLIP
    116		 * if in sol_compat mode
    117		 */
    118		if (get_user(ireg, (int __user *) arg)) {
    119			error = -EFAULT;
    120			break;
    121		}
    122		if (sol_compat) {
    123			if (regs & D7S_FLIP)
    124				ireg |= D7S_FLIP;
    125			else
    126				ireg &= ~D7S_FLIP;
    127		}
    128		writeb(ireg, p->regs);
    129		break;
    130
    131	case D7SIOCRD:
    132		/* retrieve device register values
    133		 * NOTE: Solaris implementation returns D7S_FLIP bit
    134		 * as toggled by user, even though it does not honor it.
    135		 * This driver will not misinform you about the state
    136		 * of your hardware while in sol_compat mode
    137		 */
    138		if (put_user(regs, (int __user *) arg)) {
    139			error = -EFAULT;
    140			break;
    141		}
    142		break;
    143
    144	case D7SIOCTM:
    145		/* toggle device mode-- flip display orientation */
    146		regs ^= D7S_FLIP;
    147		writeb(regs, p->regs);
    148		break;
    149	}
    150	mutex_unlock(&d7s_mutex);
    151
    152	return error;
    153}
    154
    155static const struct file_operations d7s_fops = {
    156	.owner =		THIS_MODULE,
    157	.unlocked_ioctl =	d7s_ioctl,
    158	.compat_ioctl =		compat_ptr_ioctl,
    159	.open =			d7s_open,
    160	.release =		d7s_release,
    161	.llseek = noop_llseek,
    162};
    163
    164static struct miscdevice d7s_miscdev = {
    165	.minor		= D7S_MINOR,
    166	.name		= DRIVER_NAME,
    167	.fops		= &d7s_fops
    168};
    169
    170static int d7s_probe(struct platform_device *op)
    171{
    172	struct device_node *opts;
    173	int err = -EINVAL;
    174	struct d7s *p;
    175	u8 regs;
    176
    177	if (d7s_device)
    178		goto out;
    179
    180	p = devm_kzalloc(&op->dev, sizeof(*p), GFP_KERNEL);
    181	err = -ENOMEM;
    182	if (!p)
    183		goto out;
    184
    185	p->regs = of_ioremap(&op->resource[0], 0, sizeof(u8), "d7s");
    186	if (!p->regs) {
    187		printk(KERN_ERR PFX "Cannot map chip registers\n");
    188		goto out;
    189	}
    190
    191	err = misc_register(&d7s_miscdev);
    192	if (err) {
    193		printk(KERN_ERR PFX "Unable to acquire miscdevice minor %i\n",
    194		       D7S_MINOR);
    195		goto out_iounmap;
    196	}
    197
    198	/* OBP option "d7s-flipped?" is honored as default for the
    199	 * device, and reset default when detached
    200	 */
    201	regs = readb(p->regs);
    202	opts = of_find_node_by_path("/options");
    203	if (opts &&
    204	    of_get_property(opts, "d7s-flipped?", NULL))
    205		p->flipped = true;
    206
    207	if (p->flipped)
    208		regs |= D7S_FLIP;
    209	else
    210		regs &= ~D7S_FLIP;
    211
    212	writeb(regs,  p->regs);
    213
    214	printk(KERN_INFO PFX "7-Segment Display%pOF at [%s:0x%llx] %s\n",
    215	       op->dev.of_node,
    216	       (regs & D7S_FLIP) ? " (FLIPPED)" : "",
    217	       op->resource[0].start,
    218	       sol_compat ? "in sol_compat mode" : "");
    219
    220	dev_set_drvdata(&op->dev, p);
    221	d7s_device = p;
    222	err = 0;
    223	of_node_put(opts);
    224
    225out:
    226	return err;
    227
    228out_iounmap:
    229	of_iounmap(&op->resource[0], p->regs, sizeof(u8));
    230	goto out;
    231}
    232
    233static int d7s_remove(struct platform_device *op)
    234{
    235	struct d7s *p = dev_get_drvdata(&op->dev);
    236	u8 regs = readb(p->regs);
    237
    238	/* Honor OBP d7s-flipped? unless operating in solaris-compat mode */
    239	if (sol_compat) {
    240		if (p->flipped)
    241			regs |= D7S_FLIP;
    242		else
    243			regs &= ~D7S_FLIP;
    244		writeb(regs, p->regs);
    245	}
    246
    247	misc_deregister(&d7s_miscdev);
    248	of_iounmap(&op->resource[0], p->regs, sizeof(u8));
    249
    250	return 0;
    251}
    252
    253static const struct of_device_id d7s_match[] = {
    254	{
    255		.name = "display7seg",
    256	},
    257	{},
    258};
    259MODULE_DEVICE_TABLE(of, d7s_match);
    260
    261static struct platform_driver d7s_driver = {
    262	.driver = {
    263		.name = DRIVER_NAME,
    264		.of_match_table = d7s_match,
    265	},
    266	.probe		= d7s_probe,
    267	.remove		= d7s_remove,
    268};
    269
    270module_platform_driver(d7s_driver);