summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-05-04 19:07:10 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-05-04 19:15:35 -0700
commitaf82455f7dbd9dc20244d80d033721b30d22c065 (patch)
tree3b9246456e82ae116b57834a2f0b4a307a016474 /drivers/misc
parent0be75179df5e20306528800fc7c6a504b12b97db (diff)
parent2a76f89fa58c769241cfc21f2614705591519ae3 (diff)
Merge tag 'char-misc-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver updates from Greg KH: "Here is the big set of new char/misc driver drivers and features for 4.12-rc1. There's lots of new drivers added this time around, new firmware drivers from Google, more auxdisplay drivers, extcon drivers, fpga drivers, and a bunch of other driver updates. Nothing major, except if you happen to have the hardware for these drivers, and then you will be happy :) All of these have been in linux-next for a while with no reported issues" * tag 'char-misc-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (136 commits) firmware: google memconsole: Fix return value check in platform_memconsole_init() firmware: Google VPD: Fix return value check in vpd_platform_init() goldfish_pipe: fix build warning about using too much stack. goldfish_pipe: An implementation of more parallel pipe fpga fr br: update supported version numbers fpga: region: release FPGA region reference in error path fpga altera-hps2fpga: disable/unprepare clock on error in alt_fpga_bridge_probe() mei: drop the TODO from samples firmware: Google VPD sysfs driver firmware: Google VPD: import lib_vpd source files misc: lkdtm: Add volatile to intentional NULL pointer reference eeprom: idt_89hpesx: Add OF device ID table misc: ds1682: Add OF device ID table misc: tsl2550: Add OF device ID table w1: Remove unneeded use of assert() and remove w1_log.h w1: Use kernel common min() implementation uio_mf624: Align memory regions to page size and set correct offsets uio_mf624: Refactor memory info initialization uio: Allow handling of non page-aligned memory regions hangcheck-timer: Fix typo in comment ...
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Kconfig293
-rw-r--r--drivers/misc/Makefile5
-rw-r--r--drivers/misc/arm-charlcd.c368
-rw-r--r--drivers/misc/aspeed-lpc-ctrl.c266
-rw-r--r--drivers/misc/ds1682.c7
-rw-r--r--drivers/misc/eeprom/idt_89hpesx.c57
-rw-r--r--drivers/misc/lkdtm.h1
-rw-r--r--drivers/misc/lkdtm_bugs.c13
-rw-r--r--drivers/misc/lkdtm_core.c1
-rw-r--r--drivers/misc/mei/Makefile1
-rw-r--r--drivers/misc/mei/amthif.c340
-rw-r--r--drivers/misc/mei/bus-fixup.c9
-rw-r--r--drivers/misc/mei/bus.c6
-rw-r--r--drivers/misc/mei/client.c14
-rw-r--r--drivers/misc/mei/client.h5
-rw-r--r--drivers/misc/mei/hbm.c29
-rw-r--r--drivers/misc/mei/init.c14
-rw-r--r--drivers/misc/mei/interrupt.c38
-rw-r--r--drivers/misc/mei/main.c125
-rw-r--r--drivers/misc/mei/mei_dev.h51
-rw-r--r--drivers/misc/mei/pci-me.c31
-rw-r--r--drivers/misc/mei/pci-txe.c29
-rw-r--r--drivers/misc/panel.c2439
-rw-r--r--drivers/misc/tsl2550.c7
24 files changed, 523 insertions, 3626 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index c290990d73ed..39d1acb27452 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -419,16 +419,6 @@ config VMWARE_BALLOON
To compile this driver as a module, choose M here: the
module will be called vmw_balloon.
-config ARM_CHARLCD
- bool "ARM Ltd. Character LCD Driver"
- depends on PLAT_VERSATILE
- help
- This is a driver for the character LCD found on the ARM Ltd.
- Versatile and RealView Platform Baseboards. It doesn't do
- very much more than display the text "ARM Linux" on the first
- line and the Linux version on the second line, but that's
- still useful.
-
config PCH_PHUB
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB"
select GENERIC_NET_UTILS
@@ -492,284 +482,13 @@ config VEXPRESS_SYSCFG
bus. System Configuration interface is one of the possible means
of generating transactions on this bus.
-config PANEL
- tristate "Parallel port LCD/Keypad Panel support"
- depends on PARPORT
- ---help---
- Say Y here if you have an HD44780 or KS-0074 LCD connected to your
- parallel port. This driver also features 4 and 6-key keypads. The LCD
- is accessible through the /dev/lcd char device (10, 156), and the
- keypad through /dev/keypad (10, 185). This code can either be
- compiled as a module, or linked into the kernel and started at boot.
- If you don't understand what all this is about, say N.
-
-if PANEL
-
-config PANEL_PARPORT
- int "Default parallel port number (0=LPT1)"
- range 0 255
- default "0"
- ---help---
- This is the index of the parallel port the panel is connected to. One
- driver instance only supports one parallel port, so if your keypad
- and LCD are connected to two separate ports, you have to start two
- modules with different arguments. Numbering starts with '0' for LPT1,
- and so on.
-
-config PANEL_PROFILE
- int "Default panel profile (0-5, 0=custom)"
- range 0 5
- default "5"
- ---help---
- To ease configuration, the driver supports different configuration
- profiles for past and recent wirings. These profiles can also be
- used to define an approximative configuration, completed by a few
- other options. Here are the profiles :
-
- 0 = custom (see further)
- 1 = 2x16 parallel LCD, old keypad
- 2 = 2x16 serial LCD (KS-0074), new keypad
- 3 = 2x16 parallel LCD (Hantronix), no keypad
- 4 = 2x16 parallel LCD (Nexcom NSA1045) with Nexcom's keypad
- 5 = 2x40 parallel LCD (old one), with old keypad
-
- Custom configurations allow you to define how your display is
- wired to the parallel port, and how it works. This is only intended
- for experts.
-
-config PANEL_KEYPAD
- depends on PANEL_PROFILE="0"
- int "Keypad type (0=none, 1=old 6 keys, 2=new 6 keys, 3=Nexcom 4 keys)"
- range 0 3
- default 0
- ---help---
- This enables and configures a keypad connected to the parallel port.
- The keys will be read from character device 10,185. Valid values are :
-
- 0 : do not enable this driver
- 1 : old 6 keys keypad
- 2 : new 6 keys keypad, as used on the server at www.ant-computing.com
- 3 : Nexcom NSA1045's 4 keys keypad
-
- New profiles can be described in the driver source. The driver also
- supports simultaneous keys pressed when the keypad supports them.
-
-config PANEL_LCD
- depends on PANEL_PROFILE="0"
- int "LCD type (0=none, 1=custom, 2=old //, 3=ks0074, 4=hantronix, 5=Nexcom)"
- range 0 5
- default 0
- ---help---
- This enables and configures an LCD connected to the parallel port.
- The driver includes an interpreter for escape codes starting with
- '\e[L' which are specific to the LCD, and a few ANSI codes. The
- driver will be registered as character device 10,156, usually
- under the name '/dev/lcd'. There are a total of 6 supported types :
-
- 0 : do not enable the driver
- 1 : custom configuration and wiring (see further)
- 2 : 2x16 & 2x40 parallel LCD (old wiring)
- 3 : 2x16 serial LCD (KS-0074 based)
- 4 : 2x16 parallel LCD (Hantronix wiring)
- 5 : 2x16 parallel LCD (Nexcom wiring)
-
- When type '1' is specified, other options will appear to configure
- more precise aspects (wiring, dimensions, protocol, ...). Please note
- that those values changed from the 2.4 driver for better consistency.
-
-config PANEL_LCD_HEIGHT
- depends on PANEL_PROFILE="0" && PANEL_LCD="1"
- int "Number of lines on the LCD (1-2)"
- range 1 2
- default 2
- ---help---
- This is the number of visible character lines on the LCD in custom profile.
- It can either be 1 or 2.
-
-config PANEL_LCD_WIDTH
- depends on PANEL_PROFILE="0" && PANEL_LCD="1"
- int "Number of characters per line on the LCD (1-40)"
- range 1 40
- default 40
- ---help---
- This is the number of characters per line on the LCD in custom profile.
- Common values are 16,20,24,40.
-
-config PANEL_LCD_BWIDTH
- depends on PANEL_PROFILE="0" && PANEL_LCD="1"
- int "Internal LCD line width (1-40, 40 by default)"
- range 1 40
- default 40
- ---help---
- Most LCDs use a standard controller which supports hardware lines of 40
- characters, although sometimes only 16, 20 or 24 of them are really wired
- to the terminal. This results in some non-visible but addressable characters,
- and is the case for most parallel LCDs. Other LCDs, and some serial ones,
- however, use the same line width internally as what is visible. The KS0074
- for example, uses 16 characters per line for 16 visible characters per line.
-
- This option lets you configure the value used by your LCD in 'custom' profile.
- If you don't know, put '40' here.
-
-config PANEL_LCD_HWIDTH
- depends on PANEL_PROFILE="0" && PANEL_LCD="1"
- int "Hardware LCD line width (1-64, 64 by default)"
- range 1 64
- default 64
- ---help---
- Most LCDs use a single address bit to differentiate line 0 and line 1. Since
- some of them need to be able to address 40 chars with the lower bits, they
- often use the immediately superior power of 2, which is 64, to address the
- next line.
-
- If you don't know what your LCD uses, in doubt let 16 here for a 2x16, and
- 64 here for a 2x40.
-
-config PANEL_LCD_CHARSET
- depends on PANEL_PROFILE="0" && PANEL_LCD="1"
- int "LCD character set (0=normal, 1=KS0074)"
- range 0 1
- default 0
- ---help---
- Some controllers such as the KS0074 use a somewhat strange character set
- where many symbols are at unusual places. The driver knows how to map
- 'standard' ASCII characters to the character sets used by these controllers.
- Valid values are :
-
- 0 : normal (untranslated) character set
- 1 : KS0074 character set
-
- If you don't know, use the normal one (0).
-
-config PANEL_LCD_PROTO
- depends on PANEL_PROFILE="0" && PANEL_LCD="1"
- int "LCD communication mode (0=parallel 8 bits, 1=serial)"
- range 0 1
- default 0
- ---help---
- This driver now supports any serial or parallel LCD wired to a parallel
- port. But before assigning signals, the driver needs to know if it will
- be driving a serial LCD or a parallel one. Serial LCDs only use 2 wires
- (SDA/SCL), while parallel ones use 2 or 3 wires for the control signals
- (E, RS, sometimes RW), and 4 or 8 for the data. Use 0 here for a 8 bits
- parallel LCD, and 1 for a serial LCD.
-
-config PANEL_LCD_PIN_E
- depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0"
- int "Parallel port pin number & polarity connected to the LCD E signal (-17...17) "
- range -17 17
- default 14
+config ASPEED_LPC_CTRL
+ depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON
+ tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control"
---help---
- This describes the number of the parallel port pin to which the LCD 'E'
- signal has been connected. It can be :
-
- 0 : no connection (eg: connected to ground)
- 1..17 : directly connected to any of these pins on the DB25 plug
- -1..-17 : connected to the same pin through an inverter (eg: transistor).
-
- Default for the 'E' pin in custom profile is '14' (AUTOFEED).
-
-config PANEL_LCD_PIN_RS
- depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0"
- int "Parallel port pin number & polarity connected to the LCD RS signal (-17...17) "
- range -17 17
- default 17
- ---help---
- This describes the number of the parallel port pin to which the LCD 'RS'
- signal has been connected. It can be :
-
- 0 : no connection (eg: connected to ground)
- 1..17 : directly connected to any of these pins on the DB25 plug
- -1..-17 : connected to the same pin through an inverter (eg: transistor).
-
- Default for the 'RS' pin in custom profile is '17' (SELECT IN).
-
-config PANEL_LCD_PIN_RW
- depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0"
- int "Parallel port pin number & polarity connected to the LCD RW signal (-17...17) "
- range -17 17
- default 16
- ---help---
- This describes the number of the parallel port pin to which the LCD 'RW'
- signal has been connected. It can be :
-
- 0 : no connection (eg: connected to ground)
- 1..17 : directly connected to any of these pins on the DB25 plug
- -1..-17 : connected to the same pin through an inverter (eg: transistor).
-
- Default for the 'RW' pin in custom profile is '16' (INIT).
-
-config PANEL_LCD_PIN_SCL
- depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0"
- int "Parallel port pin number & polarity connected to the LCD SCL signal (-17...17) "
- range -17 17
- default 1
- ---help---
- This describes the number of the parallel port pin to which the serial
- LCD 'SCL' signal has been connected. It can be :
-
- 0 : no connection (eg: connected to ground)
- 1..17 : directly connected to any of these pins on the DB25 plug
- -1..-17 : connected to the same pin through an inverter (eg: transistor).
-
- Default for the 'SCL' pin in custom profile is '1' (STROBE).
-
-config PANEL_LCD_PIN_SDA
- depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0"
- int "Parallel port pin number & polarity connected to the LCD SDA signal (-17...17) "
- range -17 17
- default 2
- ---help---
- This describes the number of the parallel port pin to which the serial
- LCD 'SDA' signal has been connected. It can be :
-
- 0 : no connection (eg: connected to ground)
- 1..17 : directly connected to any of these pins on the DB25 plug
- -1..-17 : connected to the same pin through an inverter (eg: transistor).
-
- Default for the 'SDA' pin in custom profile is '2' (D0).
-
-config PANEL_LCD_PIN_BL
- depends on PANEL_PROFILE="0" && PANEL_LCD="1"
- int "Parallel port pin number & polarity connected to the LCD backlight signal (-17...17) "
- range -17 17
- default 0
- ---help---
- This describes the number of the parallel port pin to which the LCD 'BL' signal
- has been connected. It can be :
-
- 0 : no connection (eg: connected to ground)
- 1..17 : directly connected to any of these pins on the DB25 plug
- -1..-17 : connected to the same pin through an inverter (eg: transistor).
-
- Default for the 'BL' pin in custom profile is '0' (uncontrolled).
-
-config PANEL_CHANGE_MESSAGE
- bool "Change LCD initialization message ?"
- default "n"
- ---help---
- This allows you to replace the boot message indicating the kernel version
- and the driver version with a custom message. This is useful on appliances
- where a simple 'Starting system' message can be enough to stop a customer
- from worrying.
-
- If you say 'Y' here, you'll be able to choose a message yourself. Otherwise,
- say 'N' and keep the default message with the version.
-
-config PANEL_BOOT_MESSAGE
- depends on PANEL_CHANGE_MESSAGE="y"
- string "New initialization message"
- default ""
- ---help---
- This allows you to replace the boot message indicating the kernel version
- and the driver version with a custom message. This is useful on appliances
- where a simple 'Starting system' message can be enough to stop a customer
- from worrying.
-
- An empty message will only clear the display at driver init time. Any other
- printf()-formatted message is valid with newline and escape codes.
-
-endif # PANEL
+ Control Aspeed ast2400/2500 HOST LPC to BMC mappings through
+ ioctl()s, the driver also provides a read/write interface to a BMC ram
+ region where the host LPC read/write region can be buffered.
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 7a3ea89339b4..4fb10af2ea1c 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -37,7 +37,6 @@ obj-y += eeprom/
obj-y += cb710/
obj-$(CONFIG_SPEAR13XX_PCIE_GADGET) += spear13xx_pcie_gadget.o
obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o
-obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o
obj-$(CONFIG_PCH_PHUB) += pch_phub.o
obj-y += ti-st/
obj-y += lis3lv02d/
@@ -53,7 +52,7 @@ obj-$(CONFIG_GENWQE) += genwqe/
obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
obj-$(CONFIG_CXL_BASE) += cxl/
-obj-$(CONFIG_PANEL) += panel.o
+obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o
@@ -62,6 +61,8 @@ lkdtm-$(CONFIG_LKDTM) += lkdtm_perms.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o
+KCOV_INSTRUMENT_lkdtm_rodata.o := n
+
OBJCOPYFLAGS :=
OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \
--set-section-flags .text=alloc,readonly \
diff --git a/drivers/misc/arm-charlcd.c b/drivers/misc/arm-charlcd.c
deleted file mode 100644
index b3176ee92b90..000000000000
--- a/drivers/misc/arm-charlcd.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Driver for the on-board character LCD found on some ARM reference boards
- * This is basically an Hitachi HD44780 LCD with a custom IP block to drive it
- * http://en.wikipedia.org/wiki/HD44780_Character_LCD
- * Currently it will just display the text "ARM Linux" and the linux version
- *
- * License terms: GNU General Public License (GPL) version 2
- * Author: Linus Walleij <triad@df.lth.se>
- */
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <generated/utsrelease.h>
-
-#define DRIVERNAME "arm-charlcd"
-#define CHARLCD_TIMEOUT (msecs_to_jiffies(1000))
-
-/* Offsets to registers */
-#define CHAR_COM 0x00U
-#define CHAR_DAT 0x04U
-#define CHAR_RD 0x08U
-#define CHAR_RAW 0x0CU
-#define CHAR_MASK 0x10U
-#define CHAR_STAT 0x14U
-
-#define CHAR_RAW_CLEAR 0x00000000U
-#define CHAR_RAW_VALID 0x00000100U
-
-/* Hitachi HD44780 display commands */
-#define HD_CLEAR 0x01U
-#define HD_HOME 0x02U
-#define HD_ENTRYMODE 0x04U
-#define HD_ENTRYMODE_INCREMENT 0x02U
-#define HD_ENTRYMODE_SHIFT 0x01U
-#define HD_DISPCTRL 0x08U
-#define HD_DISPCTRL_ON 0x04U
-#define HD_DISPCTRL_CURSOR_ON 0x02U
-#define HD_DISPCTRL_CURSOR_BLINK 0x01U
-#define HD_CRSR_SHIFT 0x10U
-#define HD_CRSR_SHIFT_DISPLAY 0x08U
-#define HD_CRSR_SHIFT_DISPLAY_RIGHT 0x04U
-#define HD_FUNCSET 0x20U
-#define HD_FUNCSET_8BIT 0x10U
-#define HD_FUNCSET_2_LINES 0x08U
-#define HD_FUNCSET_FONT_5X10 0x04U
-#define HD_SET_CGRAM 0x40U
-#define HD_SET_DDRAM 0x80U
-#define HD_BUSY_FLAG 0x80U
-
-/**
- * @dev: a pointer back to containing device
- * @phybase: the offset to the controller in physical memory
- * @physize: the size of the physical page
- * @virtbase: the offset to the controller in virtual memory
- * @irq: reserved interrupt number
- * @complete: completion structure for the last LCD command
- */
-struct charlcd {
- struct device *dev;
- u32 phybase;
- u32 physize;
- void __iomem *virtbase;
- int irq;
- struct completion complete;
- struct delayed_work init_work;
-};
-
-static irqreturn_t charlcd_interrupt(int irq, void *data)
-{
- struct charlcd *lcd = data;
- u8 status;
-
- status = readl(lcd->virtbase + CHAR_STAT) & 0x01;
- /* Clear IRQ */
- writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW);
- if (status)
- complete(&lcd->complete);
- else
- dev_info(lcd->dev, "Spurious IRQ (%02x)\n", status);
- return IRQ_HANDLED;
-}
-
-
-static void charlcd_wait_complete_irq(struct charlcd *lcd)
-{
- int ret;
-
- ret = wait_for_completion_interruptible_timeout(&lcd->complete,
- CHARLCD_TIMEOUT);
- /* Disable IRQ after completion */
- writel(0x00, lcd->virtbase + CHAR_MASK);
-
- if (ret < 0) {
- dev_err(lcd->dev,
- "wait_for_completion_interruptible_timeout() "
- "returned %d waiting for ready\n", ret);
- return;
- }
-
- if (ret == 0) {
- dev_err(lcd->dev, "charlcd controller timed out "
- "waiting for ready\n");
- return;
- }
-}
-
-static u8 charlcd_4bit_read_char(struct charlcd *lcd)
-{
- u8 data;
- u32 val;
- int i;
-
- /* If we can, use an IRQ to wait for the data, else poll */
- if (lcd->irq >= 0)
- charlcd_wait_complete_irq(lcd);
- else {
- i = 0;
- val = 0;
- while (!(val & CHAR_RAW_VALID) && i < 10) {
- udelay(100);
- val = readl(lcd->virtbase + CHAR_RAW);
- i++;
- }
-
- writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW);
- }
- msleep(1);
-
- /* Read the 4 high bits of the data */
- data = readl(lcd->virtbase + CHAR_RD) & 0xf0;
-
- /*
- * The second read for the low bits does not trigger an IRQ
- * so in this case we have to poll for the 4 lower bits
- */
- i = 0;
- val = 0;
- while (!(val & CHAR_RAW_VALID) && i < 10) {
- udelay(100);
- val = readl(lcd->virtbase + CHAR_RAW);
- i++;
- }
- writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW);
- msleep(1);
-
- /* Read the 4 low bits of the data */
- data |= (readl(lcd->virtbase + CHAR_RD) >> 4) & 0x0f;
-
- return data;
-}
-
-static bool charlcd_4bit_read_bf(struct charlcd *lcd)
-{
- if (lcd->irq >= 0) {
- /*
- * If we'll use IRQs to wait for the busyflag, clear any
- * pending flag and enable IRQ
- */
- writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW);
- init_completion(&lcd->complete);
- writel(0x01, lcd->virtbase + CHAR_MASK);
- }
- readl(lcd->virtbase + CHAR_COM);
- return charlcd_4bit_read_char(lcd) & HD_BUSY_FLAG ? true : false;
-}
-
-static void charlcd_4bit_wait_busy(struct charlcd *lcd)
-{
- int retries = 50;
-
- udelay(100);
- while (charlcd_4bit_read_bf(lcd) && retries)
- retries--;
- if (!retries)
- dev_err(lcd->dev, "timeout waiting for busyflag\n");
-}
-
-static void charlcd_4bit_command(struct charlcd *lcd, u8 cmd)
-{
- u32 cmdlo = (cmd << 4) & 0xf0;
- u32 cmdhi = (cmd & 0xf0);
-
- writel(cmdhi, lcd->virtbase + CHAR_COM);
- udelay(10);
- writel(cmdlo, lcd->virtbase + CHAR_COM);
- charlcd_4bit_wait_busy(lcd);
-}
-
-static void charlcd_4bit_char(struct charlcd *lcd, u8 ch)
-{
- u32 chlo = (ch << 4) & 0xf0;
- u32 chhi = (ch & 0xf0);
-
- writel(chhi, lcd->virtbase + CHAR_DAT);
- udelay(10);
- writel(chlo, lcd->virtbase + CHAR_DAT);
- charlcd_4bit_wait_busy(lcd);
-}
-
-static void charlcd_4bit_print(struct charlcd *lcd, int line, const char *str)
-{
- u8 offset;
- int i;
-
- /*
- * We support line 0, 1
- * Line 1 runs from 0x00..0x27
- * Line 2 runs from 0x28..0x4f
- */
- if (line == 0)
- offset = 0;
- else if (line == 1)
- offset = 0x28;
- else
- return;
-
- /* Set offset */
- charlcd_4bit_command(lcd, HD_SET_DDRAM | offset);
-
- /* Send string */
- for (i = 0; i < strlen(str) && i < 0x28; i++)
- charlcd_4bit_char(lcd, str[i]);
-}
-
-static void charlcd_4bit_init(struct charlcd *lcd)
-{
- /* These commands cannot be checked with the busy flag */
- writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM);
- msleep(5);
- writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM);
- udelay(100);
- writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM);
- udelay(100);
- /* Go to 4bit mode */
- writel(HD_FUNCSET, lcd->virtbase + CHAR_COM);
- udelay(100);
- /*
- * 4bit mode, 2 lines, 5x8 font, after this the number of lines
- * and the font cannot be changed until the next initialization sequence
- */
- charlcd_4bit_command(lcd, HD_FUNCSET | HD_FUNCSET_2_LINES);
- charlcd_4bit_command(lcd, HD_DISPCTRL | HD_DISPCTRL_ON);
- charlcd_4bit_command(lcd, HD_ENTRYMODE | HD_ENTRYMODE_INCREMENT);
- charlcd_4bit_command(lcd, HD_CLEAR);
- charlcd_4bit_command(lcd, HD_HOME);
- /* Put something useful in the display */
- charlcd_4bit_print(lcd, 0, "ARM Linux");
- charlcd_4bit_print(lcd, 1, UTS_RELEASE);
-}
-
-static void charlcd_init_work(struct work_struct *work)
-{
- struct charlcd *lcd =
- container_of(work, struct charlcd, init_work.work);
-
- charlcd_4bit_init(lcd);
-}
-
-static int __init charlcd_probe(struct platform_device *pdev)
-{
- int ret;
- struct charlcd *lcd;
- struct resource *res;
-
- lcd = kzalloc(sizeof(struct charlcd), GFP_KERNEL);
- if (!lcd)
- return -ENOMEM;
-
- lcd->dev = &pdev->dev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -ENOENT;
- goto out_no_resource;
- }
- lcd->phybase = res->start;
- lcd->physize = resource_size(res);
-
- if (request_mem_region(lcd->phybase, lcd->physize,
- DRIVERNAME) == NULL) {
- ret = -EBUSY;
- goto out_no_memregion;
- }
-
- lcd->virtbase = ioremap(lcd->phybase, lcd->physize);
- if (!lcd->virtbase) {
- ret = -ENOMEM;
- goto out_no_memregion;
- }
-
- lcd->irq = platform_get_irq(pdev, 0);
- /* If no IRQ is supplied, we'll survive without it */
- if (lcd->irq >= 0) {
- if (request_irq(lcd->irq, charlcd_interrupt, 0,
- DRIVERNAME, lcd)) {
- ret = -EIO;
- goto out_no_irq;
- }
- }
-
- platform_set_drvdata(pdev, lcd);
-
- /*
- * Initialize the display in a delayed work, because
- * it is VERY slow and would slow down the boot of the system.
- */
- INIT_DELAYED_WORK(&lcd->init_work, charlcd_init_work);
- schedule_delayed_work(&lcd->init_work, 0);
-
- dev_info(&pdev->dev, "initialized ARM character LCD at %08x\n",
- lcd->phybase);
-
- return 0;
-
-out_no_irq:
- iounmap(lcd->virtbase);
-out_no_memregion:
- release_mem_region(lcd->phybase, SZ_4K);
-out_no_resource:
- kfree(lcd);
- return ret;
-}
-
-static int charlcd_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct charlcd *lcd = platform_get_drvdata(pdev);
-
- /* Power the display off */
- charlcd_4bit_command(lcd, HD_DISPCTRL);
- return 0;
-}
-
-static int charlcd_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct charlcd *lcd = platform_get_drvdata(pdev);
-
- /* Turn the display back on */
- charlcd_4bit_command(lcd, HD_DISPCTRL | HD_DISPCTRL_ON);
- return 0;
-}
-
-static const struct dev_pm_ops charlcd_pm_ops = {
- .suspend = charlcd_suspend,
- .resume = charlcd_resume,
-};
-
-static const struct of_device_id charlcd_match[] = {
- { .compatible = "arm,versatile-lcd", },
- {}
-};
-
-static struct platform_driver charlcd_driver = {
- .driver = {
- .name = DRIVERNAME,
- .pm = &charlcd_pm_ops,
- .suppress_bind_attrs = true,
- .of_match_table = of_match_ptr(charlcd_match),
- },
-};
-builtin_platform_driver_probe(charlcd_driver, charlcd_probe);
diff --git a/drivers/misc/aspeed-lpc-ctrl.c b/drivers/misc/aspeed-lpc-ctrl.c
new file mode 100644
index 000000000000..b5439643f54b
--- /dev/null
+++ b/drivers/misc/aspeed-lpc-ctrl.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2017 IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/mfd/syscon.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/regmap.h>
+
+#include <linux/aspeed-lpc-ctrl.h>
+
+#define DEVICE_NAME "aspeed-lpc-ctrl"
+
+#define HICR7 0x8
+#define HICR8 0xc
+
+struct aspeed_lpc_ctrl {
+ struct miscdevice miscdev;
+ struct regmap *regmap;
+ phys_addr_t mem_base;
+ resource_size_t mem_size;
+ u32 pnor_size;
+ u32 pnor_base;
+};
+
+static struct aspeed_lpc_ctrl *file_aspeed_lpc_ctrl(struct file *file)
+{
+ return container_of(file->private_data, struct aspeed_lpc_ctrl,
+ miscdev);
+}
+
+static int aspeed_lpc_ctrl_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file);
+ unsigned long vsize = vma->vm_end - vma->vm_start;
+ pgprot_t prot = vma->vm_page_prot;
+
+ if (vma->vm_pgoff + vsize > lpc_ctrl->mem_base + lpc_ctrl->mem_size)
+ return -EINVAL;
+
+ /* ast2400/2500 AHB accesses are not cache coherent */
+ prot = pgprot_noncached(prot);
+
+ if (remap_pfn_range(vma, vma->vm_start,
+ (lpc_ctrl->mem_base >> PAGE_SHIFT) + vma->vm_pgoff,
+ vsize, prot))
+ return -EAGAIN;
+
+ return 0;
+}
+
+static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd,
+ unsigned long param)
+{
+ struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file);
+ void __user *p = (void __user *)param;
+ struct aspeed_lpc_ctrl_mapping map;
+ u32 addr;
+ u32 size;
+ long rc;
+
+ if (copy_from_user(&map, p, sizeof(map)))
+ return -EFAULT;
+
+ if (map.flags != 0)
+ return -EINVAL;
+
+ switch (cmd) {
+ case ASPEED_LPC_CTRL_IOCTL_GET_SIZE:
+ /* The flash windows don't report their size */
+ if (map.window_type != ASPEED_LPC_CTRL_WINDOW_MEMORY)
+ return -EINVAL;
+
+ /* Support more than one window id in the future */
+ if (map.window_id != 0)
+ return -EINVAL;
+
+ map.size = lpc_ctrl->mem_size;
+
+ return copy_to_user(p, &map, sizeof(map)) ? -EFAULT : 0;
+ case ASPEED_LPC_CTRL_IOCTL_MAP:
+
+ /*
+ * The top half of HICR7 is the MSB of the BMC address of the
+ * mapping.
+ * The bottom half of HICR7 is the MSB of the HOST LPC
+ * firmware space address of the mapping.
+ *
+ * The 1 bits in the top of half of HICR8 represent the bits
+ * (in the requested address) that should be ignored and
+ * replaced with those from the top half of HICR7.
+ * The 1 bits in the bottom half of HICR8 represent the bits
+ * (in the requested address) that should be kept and pass
+ * into the BMC address space.
+ */
+
+ /*
+ * It doesn't make sense to talk about a size or offset with
+ * low 16 bits set. Both HICR7 and HICR8 talk about the top 16
+ * bits of addresses and sizes.
+ */
+
+ if ((map.size & 0x0000ffff) || (map.offset & 0x0000ffff))
+ return -EINVAL;
+
+ /*
+ * Because of the way the masks work in HICR8 offset has to
+ * be a multiple of size.
+ */
+ if (map.offset & (map.size - 1))
+ return -EINVAL;
+
+ if (map.window_type == ASPEED_LPC_CTRL_WINDOW_FLASH) {
+ addr = lpc_ctrl->pnor_base;
+ size = lpc_ctrl->pnor_size;
+ } else if (map.window_type == ASPEED_LPC_CTRL_WINDOW_MEMORY) {
+ addr = lpc_ctrl->mem_base;
+ size = lpc_ctrl->mem_size;
+ } else {
+ return -EINVAL;
+ }
+
+ /* Check overflow first! */
+ if (map.offset + map.size < map.offset ||
+ map.offset + map.size > size)
+ return -EINVAL;
+
+ if (map.size == 0 || map.size > size)
+ return -EINVAL;
+
+ addr += map.offset;
+
+ /*
+ * addr (host lpc address) is safe regardless of values. This
+ * simply changes the address the host has to request on its
+ * side of the LPC bus. This cannot impact the hosts own
+ * memory space by surprise as LPC specific accessors are
+ * required. The only strange thing that could be done is
+ * setting the lower 16 bits but the shift takes care of that.
+ */
+
+ rc = regmap_write(lpc_ctrl->regmap, HICR7,
+ (addr | (map.addr >> 16)));
+ if (rc)
+ return rc;
+
+ return regmap_write(lpc_ctrl->regmap, HICR8,
+ (~(map.size - 1)) | ((map.size >> 16) - 1));
+ }
+
+ return -EINVAL;
+}
+
+static const struct file_operations aspeed_lpc_ctrl_fops = {
+ .owner = THIS_MODULE,
+ .mmap = aspeed_lpc_ctrl_mmap,
+ .unlocked_ioctl = aspeed_lpc_ctrl_ioctl,
+};
+
+static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
+{
+ struct aspeed_lpc_ctrl *lpc_ctrl;
+ struct device_node *node;
+ struct resource resm;
+ struct device *dev;
+ int rc;
+
+ dev = &pdev->dev;
+
+ lpc_ctrl = devm_kzalloc(dev, sizeof(*lpc_ctrl), GFP_KERNEL);
+ if (!lpc_ctrl)
+ return -ENOMEM;
+
+ node = of_parse_phandle(dev->of_node, "flash", 0);
+ if (!node) {
+ dev_err(dev, "Didn't find host pnor flash node\n");
+ return -ENODEV;
+ }
+
+ rc = of_address_to_resource(node, 1, &resm);
+ of_node_put(node);
+ if (rc) {
+ dev_err(dev, "Couldn't address to resource for flash\n");
+ return rc;
+ }
+
+ lpc_ctrl->pnor_size = resource_size(&resm);
+ lpc_ctrl->pnor_base = resm.start;
+
+ dev_set_drvdata(&pdev->dev, lpc_ctrl);
+
+ node = of_parse_phandle(dev->of_node, "memory-region", 0);
+ if (!node) {
+ dev_err(dev, "Didn't find reserved memory\n");
+ return -EINVAL;
+ }
+
+ rc = of_address_to_resource(node, 0, &resm);
+ of_node_put(node);
+ if (rc) {
+ dev_err(dev, "Couldn't address to resource for reserved memory\n");
+ return -ENOMEM;
+ }
+
+ lpc_ctrl->mem_size = resource_size(&resm);
+ lpc_ctrl->mem_base = resm.start;
+
+ lpc_ctrl->regmap = syscon_node_to_regmap(
+ pdev->dev.parent->of_node);
+ if (IS_ERR(lpc_ctrl->regmap)) {
+ dev_err(dev, "Couldn't get regmap\n");
+ return -ENODEV;
+ }
+
+ lpc_ctrl->miscdev.minor = MISC_DYNAMIC_MINOR;
+ lpc_ctrl->miscdev.name = DEVICE_NAME;
+ lpc_ctrl->miscdev.fops = &aspeed_lpc_ctrl_fops;
+ lpc_ctrl->miscdev.parent = dev;
+ rc = misc_register(&lpc_ctrl->miscdev);
+ if (rc)
+ dev_err(dev, "Unable to register device\n");
+ else
+ dev_info(dev, "Loaded at %pr\n", &resm);
+
+ return rc;
+}
+
+static int aspeed_lpc_ctrl_remove(struct platform_device *pdev)
+{
+ struct aspeed_lpc_ctrl *lpc_ctrl = dev_get_drvdata(&pdev->dev);
+
+ misc_deregister(&lpc_ctrl->miscdev);
+
+ return 0;
+}
+
+static const struct of_device_id aspeed_lpc_ctrl_match[] = {
+ { .compatible = "aspeed,ast2400-lpc-ctrl" },
+ { .compatible = "aspeed,ast2500-lpc-ctrl" },
+ { },
+};
+
+static struct platform_driver aspeed_lpc_ctrl_driver = {
+ .driver = {
+ .name = DEVICE_NAME,
+ .of_match_table = aspeed_lpc_ctrl_match,
+ },
+ .probe = aspeed_lpc_ctrl_probe,
+ .remove = aspeed_lpc_ctrl_remove,
+};
+
+module_platform_driver(aspeed_lpc_ctrl_driver);
+
+MODULE_DEVICE_TABLE(of, aspeed_lpc_ctrl_match);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cyril Bur <cyrilbur@gmail.com>");
+MODULE_DESCRIPTION("Control for aspeed 2400/2500 LPC HOST to BMC mappings");
diff --git a/drivers/misc/ds1682.c b/drivers/misc/ds1682.c
index c7112276a039..28bb495f0cf1 100644
--- a/drivers/misc/ds1682.c
+++ b/drivers/misc/ds1682.c
@@ -227,9 +227,16 @@ static const struct i2c_device_id ds1682_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ds1682_id);
+static const struct of_device_id ds1682_of_match[] = {
+ { .compatible = "dallas,ds1682", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ds1682_of_match);
+
static struct i2c_driver ds1682_driver = {
.driver = {
.name = "ds1682",
+ .of_match_table = ds1682_of_match,
},
.probe = ds1682_probe,
.remove = ds1682_remove,
diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c
index 4a22a1d99395..ab0df6a17690 100644
--- a/drivers/misc/eeprom/idt_89hpesx.c
+++ b/drivers/misc/eeprom/idt_89hpesx.c
@@ -1541,12 +1541,69 @@ static const struct i2c_device_id idt_ids[] = {
};
MODULE_DEVICE_TABLE(i2c, idt_ids);
+static const struct of_device_id idt_of_match[] = {
+ { .compatible = "idt,89hpes8nt2", },
+ { .compatible = "idt,89hpes12nt3", },
+
+ { .compatible = "idt,89hpes24nt6ag2", },
+ { .compatible = "idt,89hpes32nt8ag2", },
+ { .compatible = "idt,89hpes32nt8bg2", },
+ { .compatible = "idt,89hpes12nt12g2", },
+ { .compatible = "idt,89hpes16nt16g2", },
+ { .compatible = "idt,89hpes24nt24g2", },
+ { .compatible = "idt,89hpes32nt24ag2", },
+ { .compatible = "idt,89hpes32nt24bg2", },
+
+ { .compatible = "idt,89hpes12n3", },
+ { .compatible = "idt,89hpes12n3a", },
+ { .compatible = "idt,89hpes24n3", },
+ { .compatible = "idt,89hpes24n3a", },
+
+ { .compatible = "idt,89hpes32h8", },
+ { .compatible = "idt,89hpes32h8g2", },
+ { .compatible = "idt,89hpes48h12", },
+ { .compatible = "idt,89hpes48h12g2", },
+ { .compatible = "idt,89hpes48h12ag2", },
+ { .compatible = "idt,89hpes16h16", },
+ { .compatible = "idt,89hpes22h16", },
+ { .compatible = "idt,89hpes22h16g2", },
+ { .compatible = "idt,89hpes34h16", },
+ { .compatible = "idt,89hpes34h16g2", },
+ { .compatible = "idt,89hpes64h16", },
+ { .compatible = "idt,89hpes64h16g2", },
+ { .compatible = "idt,89hpes64h16ag2", },
+
+ { .compatible = "idt,89hpes12t3g2", },
+ { .compatible = "idt,89hpes24t3g2", },
+
+ { .compatible = "idt,89hpes16t4", },
+ { .compatible = "idt,89hpes4t4g2", },
+ { .compatible = "idt,89hpes10t4g2", },
+ { .compatible = "idt,89hpes16t4g2", },
+ { .compatible = "idt,89hpes16t4ag2", },
+ { .compatible = "idt,89hpes5t5", },
+ { .compatible = "idt,89hpes6t5", },
+ { .compatible = "idt,89hpes8t5", },
+ { .compatible = "idt,89hpes8t5a", },
+ { .compatible = "idt,89hpes24t6", },
+ { .compatible = "idt,89hpes6t6g2", },
+ { .compatible = "idt,89hpes24t6g2", },
+ { .compatible = "idt,89hpes16t7", },
+ { .compatible = "idt,89hpes32t8", },
+ { .compatible = "idt,89hpes32t8g2", },
+ { .compatible = "idt,89hpes48t12", },
+ { .compatible = "idt,89hpes48t12g2", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, idt_of_match);
+
/*
* idt_driver - IDT 89HPESx driver structure
*/
static struct i2c_driver idt_driver = {
.driver = {
.name = IDT_NAME,
+ .of_match_table = idt_of_match,
},
.probe = idt_probe,
.remove = idt_remove,
diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h
index 67d27be60405..3b4976396ec4 100644
--- a/drivers/misc/lkdtm.h
+++ b/drivers/misc/lkdtm.h
@@ -27,6 +27,7 @@ void lkdtm_REFCOUNT_ZERO_SUB(void);
void lkdtm_REFCOUNT_ZERO_ADD(void);
void lkdtm_CORRUPT_LIST_ADD(void);
void lkdtm_CORRUPT_LIST_DEL(void);
+void lkdtm_CORRUPT_USER_DS(void);
/* lkdtm_heap.c */
void lkdtm_OVERWRITE_ALLOCATION(void);
diff --git a/drivers/misc/lkdtm_bugs.c b/drivers/misc/lkdtm_bugs.c
index e3f4cd8876b5..d9028ef50fbe 100644
--- a/drivers/misc/lkdtm_bugs.c
+++ b/drivers/misc/lkdtm_bugs.c
@@ -8,6 +8,8 @@
#include <linux/list.h>
#include <linux/refcount.h>
#include <linux/sched.h>
+#include <linux/sched/signal.h>
+#include <linux/uaccess.h>
struct lkdtm_list {
struct list_head node;
@@ -67,7 +69,7 @@ void lkdtm_WARNING(void)
void lkdtm_EXCEPTION(void)
{
- *((int *) 0) = 0;
+ *((volatile int *) 0) = 0;
}
void lkdtm_LOOP(void)
@@ -279,3 +281,12 @@ void lkdtm_CORRUPT_LIST_DEL(void)
else
pr_err("list_del() corruption not detected!\n");
}
+
+void lkdtm_CORRUPT_USER_DS(void)
+{
+ pr_info("setting bad task size limit\n");
+ set_fs(KERNEL_DS);
+
+ /* Make sure we do not keep running with a KERNEL_DS! */
+ force_sig(SIGKILL, current);
+}
diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c
index b9a4cd4a9b68..42d2b8e31e6b 100644
--- a/drivers/misc/lkdtm_core.c
+++ b/drivers/misc/lkdtm_core.c
@@ -199,6 +199,7 @@ struct crashtype crashtypes[] = {
CRASHTYPE(OVERFLOW),
CRASHTYPE(CORRUPT_LIST_ADD),
CRASHTYPE(CORRUPT_LIST_DEL),
+ CRASHTYPE(CORRUPT_USER_DS),
CRASHTYPE(CORRUPT_STACK),
CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
CRASHTYPE(OVERWRITE_ALLOCATION),
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 59e6b0aede34..12cceb011a23 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -8,7 +8,6 @@ mei-objs += hbm.o
mei-objs += interrupt.o
mei-objs += client.o
mei-objs += main.o
-mei-objs += amthif.o
mei-objs += bus.o
mei-objs += bus-fixup.o
mei-$(CONFIG_DEBUG_FS) += debugfs.o
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
deleted file mode 100644
index 0e7406ccb6dd..000000000000
--- a/drivers/misc/mei/amthif.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- *
- * Intel Management Engine Interface (Intel MEI) Linux driver
- * Copyright (c) 2003-2012, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/ioctl.h>
-#include <linux/cdev.h>
-#include <linux/list.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/uuid.h>
-#include <linux/jiffies.h>
-#include <linux/uaccess.h>
-#include <linux/slab.h>
-
-#include <linux/mei.h>
-
-#include "mei_dev.h"
-#include "hbm.h"
-#include "client.h"
-
-const uuid_le mei_amthif_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,
- 0xac, 0xa8, 0x46, 0xe0,
- 0xff, 0x65, 0x81, 0x4c);
-
-/**
- * mei_amthif_reset_params - initializes mei device iamthif
- *
- * @dev: the device structure
- */
-void mei_amthif_reset_params(struct mei_device *dev)
-{
- /* reset iamthif parameters. */
- dev->iamthif_canceled = false;
- dev->iamthif_state = MEI_IAMTHIF_IDLE;
- dev->iamthif_stall_timer = 0;
- dev->iamthif_open_count = 0;
-}
-
-/**
- * mei_amthif_host_init - mei initialization amthif client.
- *
- * @dev: the device structure
- * @me_cl: me client
- *
- * Return: 0 on success, <0 on failure.
- */
-int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
-{
- struct mei_cl *cl = &dev->iamthif_cl;
- int ret;
-
- mutex_lock(&dev->device_lock);
-
- if (mei_cl_is_connected(cl)) {
- ret = 0;
- goto out;
- }
-
- dev->iamthif_state = MEI_IAMTHIF_IDLE;
-
- mei_cl_init(cl, dev);
-
- ret = mei_cl_link(cl);
- if (ret < 0) {
- dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
- goto out;
- }
-
- ret = mei_cl_connect(cl, me_cl, NULL);
-
-out:
- mutex_unlock(&dev->device_lock);
- return ret;
-}
-
-/**
- * mei_amthif_read_start - queue message for sending read credential
- *
- * @cl: host client
- * @fp: file pointer of message recipient
- *
- * Return: 0 on success, <0 on failure.
- */
-static int mei_amthif_read_start(struct mei_cl *cl, const struct file *fp)
-{
- struct mei_device *dev = cl->dev;
- struct mei_cl_cb *cb;
-
- cb = mei_cl_enqueue_ctrl_wr_cb(cl, mei_cl_mtu(cl), MEI_FOP_READ, fp);
- if (!cb)
- return -ENOMEM;
-
- cl->rx_flow_ctrl_creds++;
-
- dev->iamthif_state = MEI_IAMTHIF_READING;
- cl->fp = cb->fp;
-
- return 0;
-}
-
-/**
- * mei_amthif_run_next_cmd - send next amt command from queue
- *
- * @dev: the device structure
- *
- * Return: 0 on success, <0 on failure.
- */
-int mei_amthif_run_next_cmd(struct mei_device *dev)
-{
- struct mei_cl *cl = &dev->iamthif_cl;
- struct mei_cl_cb *cb;
- int ret;
-
- dev->iamthif_canceled = false;
-
- dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
-
- cb = list_first_entry_or_null(&dev->amthif_cmd_list, typeof(*cb), list);
- if (!cb) {
- dev->iamthif_state = MEI_IAMTHIF_IDLE;
- cl->fp = NULL;
- return 0;
- }
-
- list_del_init(&cb->list);
- dev->iamthif_state = MEI_IAMTHIF_WRITING;
- cl->fp = cb->fp;
-
- ret = mei_cl_write(cl, cb);
- if (ret < 0)
- return ret;
-
- if (cb->completed)
- cb->status = mei_amthif_read_start(cl, cb->fp);
-
- return 0;
-}
-
-/**
- * mei_amthif_write - write amthif data to amthif client
- *
- * @cl: host client
- * @cb: mei call back struct
- *
- * Return: 0 on success, <0 on failure.
- */
-int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
-{
-
- struct mei_device *dev = cl->dev;
-
- list_add_tail(&cb->list, &dev->amthif_cmd_list);
-
- /*
- * The previous request is still in processing, queue this one.
- */
- if (dev->iamthif_state != MEI_IAMTHIF_IDLE)
- return 0;
-
- return mei_amthif_run_next_cmd(dev);
-}
-
-/**
- * mei_amthif_poll - the amthif poll function
- *
- * @file: pointer to file structure
- * @wait: pointer to poll_table structure
- *
- * Return: poll mask
- *
- * Locking: called under "dev->device_lock" lock
- */
-unsigned int mei_amthif_poll(struct file *file, poll_table *wait)
-{
- struct mei_cl *cl = file->private_data;
- struct mei_cl_cb *cb = mei_cl_read_cb(cl, file);
- unsigned int mask = 0;
-
- poll_wait(file, &cl->rx_wait, wait);
- if (cb)
- mask |= POLLIN | POLLRDNORM;
-
- return mask;
-}
-
-/**
- * mei_amthif_irq_write - write iamthif command in irq thread context.
- *
- * @cl: private data of the file object.
- * @cb: callback block.
- * @cmpl_list: complete list.
- *
- * Return: 0, OK; otherwise, error.
- */
-int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
- struct list_head *cmpl_list)
-{
- int ret;
-
- ret = mei_cl_irq_write(cl, cb, cmpl_list);
- if (ret)
- return ret;
-
- if (cb->completed)
- cb->status = mei_amthif_read_start(cl, cb->fp);
-
- return 0;
-}
-
-/**
- * mei_amthif_irq_read_msg - read routine after ISR to
- * handle the read amthif message
- *
- * @cl: mei client
- * @mei_hdr: header of amthif message
- * @cmpl_list: completed callbacks list
- *
- * Return: -ENODEV if cb is NULL 0 otherwise; error message is in cb->status
- */
-int mei_amthif_irq_read_msg(struct mei_cl *cl,
- struct mei_msg_hdr *mei_hdr,
- struct list_head *cmpl_list)
-{
- struct mei_device *dev;
- int ret;
-
- dev = cl->dev;
-
- if (dev->iamthif_state != MEI_IAMTHIF_READING) {
- mei_irq_discard_msg(dev, mei_hdr);
- return 0;
- }
-
- ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list);
- if (ret)
- return ret;
-
- if (!mei_hdr->msg_complete)
- return 0;
-
- dev_dbg(dev->dev, "completed amthif read.\n ");
- dev->iamthif_stall_timer = 0;
-
- return 0;
-}
-
-/**
- * mei_amthif_complete - complete amthif callback.
- *
- * @cl: host client
- * @cb: callback block.
- */
-void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
-{
- struct mei_device *dev = cl->dev;
-
- dev_dbg(dev->dev, "completing amthif call back.\n");
- switch (cb->fop_type) {
- case MEI_FOP_WRITE:
- if (!cb->status) {
- dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
- mei_schedule_stall_timer(dev);
- mei_io_cb_free(cb);
- return;
- }
- dev->iamthif_state = MEI_IAMTHIF_IDLE;
- cl->fp = NULL;
- if (!dev->iamthif_canceled) {
- /*
- * in case of error enqueue the write cb to complete
- * read list so it can be propagated to the reader
- */
- list_add_tail(&cb->list, &cl->rd_completed);
- wake_up_interruptible(&cl->rx_wait);
- } else {
- mei_io_cb_free(cb);
- }
- break;
- case MEI_FOP_READ:
- if (!dev->iamthif_canceled) {
- list_add_tail(&cb->list, &cl->rd_completed);
- dev_dbg(dev->dev, "amthif read completed\n");
- wake_up_interruptible(&cl->rx_wait);
- } else {
- mei_io_cb_free(cb);
- }
-
- dev->iamthif_stall_timer = 0;
- mei_amthif_run_next_cmd(dev);
- break;
- default:
- WARN_ON(1);
- }
-}
-
-/**
-* mei_amthif_release - the release function
-*
-* @dev: device structure
-* @fp: pointer to file structure
-*
-* Return: 0 on success, <0 on error
-*/
-int mei_amthif_release(struct mei_device *dev, struct file *fp)
-{
- struct mei_cl *cl = fp->private_data;
-
- if (dev->iamthif_open_count > 0)
- dev->iamthif_open_count--;
-
- if (cl->fp == fp && dev->iamthif_state != MEI_IAMTHIF_IDLE) {
-
- dev_dbg(dev->dev, "amthif canceled iamthif state %d\n",
- dev->iamthif_state);
- dev->iamthif_canceled = true;
- }
-
- /* Don't clean ctrl_rd_list here, the reads has to be completed */
- mei_io_list_free_fp(&dev->amthif_cmd_list, fp);
- mei_io_list_free_fp(&cl->rd_completed, fp);
-
- return 0;
-}
diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c
index 29f2daed37e0..0208c4b027c5 100644
--- a/drivers/misc/mei/bus-fixup.c
+++ b/drivers/misc/mei/bus-fixup.c
@@ -110,12 +110,13 @@ struct mkhi_msg {
u8 data[0];
} __packed;
+#define MKHI_OSVER_BUF_LEN (sizeof(struct mkhi_msg_hdr) + \
+ sizeof(struct mkhi_fwcaps) + \
+ sizeof(struct mei_os_ver))
static int mei_osver(struct mei_cl_device *cldev)
{
- const size_t size = sizeof(struct mkhi_msg_hdr) +
- sizeof(struct mkhi_fwcaps) +
- sizeof(struct mei_os_ver);
- char buf[size];
+ const size_t size = MKHI_OSVER_BUF_LEN;
+ char buf[MKHI_OSVER_BUF_LEN];
struct mkhi_msg *req;
struct mkhi_fwcaps *fwcaps;
struct mei_os_ver *os_ver;
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index df5f78ae3d25..d1928fdd0f43 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -1076,12 +1076,6 @@ void mei_cl_bus_rescan_work(struct work_struct *work)
{
struct mei_device *bus =
container_of(work, struct mei_device, bus_rescan_work);
- struct mei_me_client *me_cl;
-
- me_cl = mei_me_cl_by_uuid(bus, &mei_amthif_guid);
- if (me_cl)
- mei_amthif_host_init(bus, me_cl);
- mei_me_cl_put(me_cl);
mei_cl_bus_rescan(bus);
}
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index d3e3372424d6..be64969d986a 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -428,7 +428,7 @@ static inline void mei_io_list_free_cl(struct list_head *head,
* @head: io list
* @fp: file pointer (matching cb file object), may be NULL
*/
-void mei_io_list_free_fp(struct list_head *head, const struct file *fp)
+static void mei_io_list_free_fp(struct list_head *head, const struct file *fp)
{
struct mei_cl_cb *cb, *next;
@@ -554,7 +554,7 @@ int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp)
* @cl: host client to be initialized
* @dev: mei device
*/
-void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
+static void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
{
memset(cl, 0, sizeof(struct mei_cl));
init_waitqueue_head(&cl->wait);
@@ -600,7 +600,6 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev)
int mei_cl_link(struct mei_cl *cl)
{
struct mei_device *dev;
- long open_handle_count;
int id;
if (WARN_ON(!cl || !cl->dev))
@@ -614,8 +613,7 @@ int mei_cl_link(struct mei_cl *cl)
return -EMFILE;
}
- open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
- if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
+ if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
dev_err(dev->dev, "open_handle_count exceeded %d",
MEI_MAX_OPEN_HANDLE_COUNT);
return -EMFILE;
@@ -649,8 +647,7 @@ int mei_cl_unlink(struct mei_cl *cl)
if (!cl)
return 0;
- /* amthif might not be initialized */
- if (!cl->dev)
+ if (WARN_ON(!cl->dev))
return 0;
dev = cl->dev;
@@ -763,7 +760,6 @@ static void mei_cl_set_disconnected(struct mei_cl *cl)
mei_io_list_free_cl(&dev->write_waiting_list, cl);
mei_io_list_flush_cl(&dev->ctrl_rd_list, cl);
mei_io_list_flush_cl(&dev->ctrl_wr_list, cl);
- mei_io_list_free_cl(&dev->amthif_cmd_list, cl);
mei_cl_wake_all(cl);
cl->rx_flow_ctrl_creds = 0;
cl->tx_flow_ctrl_creds = 0;
@@ -1478,7 +1474,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
return -ENOTTY;
}
- if (mei_cl_is_fixed_address(cl) || cl == &dev->iamthif_cl)
+ if (mei_cl_is_fixed_address(cl))
return 0;
/* HW currently supports only one pending read */
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 545ae319ba90..5371df4d8af3 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -83,15 +83,12 @@ static inline u8 mei_me_cl_ver(const struct mei_me_client *me_cl)
* MEI IO Functions
*/
void mei_io_cb_free(struct mei_cl_cb *priv_cb);
-void mei_io_list_free_fp(struct list_head *head, const struct file *fp);
/*
* MEI Host Client Functions
*/
struct mei_cl *mei_cl_allocate(struct mei_device *dev);
-void mei_cl_init(struct mei_cl *cl, struct mei_device *dev);
-
int mei_cl_link(struct mei_cl *cl);
int mei_cl_unlink(struct mei_cl *cl);
@@ -205,8 +202,6 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
struct list_head *cmpl_list);
int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp);
-int mei_cl_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *hdr,
- struct list_head *cmpl_list);
int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb);
int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
struct list_head *cmpl_list);
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index ba3a774c8d71..fe6595fe94f1 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -166,9 +166,8 @@ void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
*
* Return: 0 on success, <0 on failure.
*/
-static inline
-int mei_hbm_cl_write(struct mei_device *dev, struct mei_cl *cl,
- u8 hbm_cmd, u8 *buf, size_t len)
+static inline int mei_hbm_cl_write(struct mei_device *dev, struct mei_cl *cl,
+ u8 hbm_cmd, void *buf, size_t len)
{
struct mei_msg_hdr mei_hdr;
@@ -632,11 +631,11 @@ static int mei_hbm_stop_req(struct mei_device *dev)
*/
int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
{
- const size_t len = sizeof(struct hbm_flow_control);
- u8 buf[len];
+ struct hbm_flow_control req;
cl_dbg(dev, cl, "sending flow control\n");
- return mei_hbm_cl_write(dev, cl, MEI_FLOW_CONTROL_CMD, buf, len);
+ return mei_hbm_cl_write(dev, cl, MEI_FLOW_CONTROL_CMD,
+ &req, sizeof(req));
}
/**
@@ -710,10 +709,10 @@ static void mei_hbm_cl_tx_flow_ctrl_creds_res(struct mei_device *dev,
*/
int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
{
- const size_t len = sizeof(struct hbm_client_connect_request);
- u8 buf[len];
+ struct hbm_client_connect_request req;
- return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_REQ_CMD, buf, len);
+ return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_REQ_CMD,
+ &req, sizeof(req));
}
/**
@@ -726,10 +725,10 @@ int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
*/
int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl)
{
- const size_t len = sizeof(struct hbm_client_connect_response);
- u8 buf[len];
+ struct hbm_client_connect_response resp;
- return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_RES_CMD, buf, len);
+ return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_RES_CMD,
+ &resp, sizeof(resp));
}
/**
@@ -763,10 +762,10 @@ static void mei_hbm_cl_disconnect_res(struct mei_device *dev, struct mei_cl *cl,
*/
int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl)
{
- const size_t len = sizeof(struct hbm_client_connect_request);
- u8 buf[len];
+ struct hbm_client_connect_request req;
- return mei_hbm_cl_write(dev, cl, CLIENT_CONNECT_REQ_CMD, buf, len);
+ return mei_hbm_cl_write(dev, cl, CLIENT_CONNECT_REQ_CMD,
+ &req, sizeof(req));
}
/**
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 13c55b8f9261..c8ad9ee7cb80 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -146,18 +146,9 @@ int mei_reset(struct mei_device *dev)
/* fall through and remove the sw state even if hw reset has failed */
/* no need to clean up software state in case of power up */
- if (state != MEI_DEV_INITIALIZING &&
- state != MEI_DEV_POWER_UP) {
-
- /* remove all waiting requests */
+ if (state != MEI_DEV_INITIALIZING && state != MEI_DEV_POWER_UP)
mei_cl_all_disconnect(dev);
- /* remove entry if already in list */
- dev_dbg(dev->dev, "remove iamthif from the file list.\n");
- mei_cl_unlink(&dev->iamthif_cl);
- mei_amthif_reset_params(dev);
- }
-
mei_hbm_reset(dev);
dev->rd_msg_hdr = 0;
@@ -401,9 +392,6 @@ void mei_device_init(struct mei_device *dev,
INIT_WORK(&dev->reset_work, mei_reset_work);
INIT_WORK(&dev->bus_rescan_work, mei_cl_bus_rescan_work);
- INIT_LIST_HEAD(&dev->iamthif_cl.link);
- INIT_LIST_HEAD(&dev->amthif_cmd_list);
-
bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
dev->open_handle_count = 0;
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 406e9e2b2fff..c14e35201721 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -47,10 +47,7 @@ void mei_irq_compl_handler(struct mei_device *dev, struct list_head *cmpl_list)
list_del_init(&cb->list);
dev_dbg(dev->dev, "completing call back.\n");
- if (cl == &dev->iamthif_cl)
- mei_amthif_complete(cl, cb);
- else
- mei_cl_complete(cl, cb);
+ mei_cl_complete(cl, cb);
}
}
EXPORT_SYMBOL_GPL(mei_irq_compl_handler);
@@ -76,7 +73,7 @@ static inline int mei_cl_hbm_equal(struct mei_cl *cl,
* @dev: mei device
* @hdr: message header
*/
-void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr)
+static void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr)
{
/*
* no need to check for size as it is guarantied
@@ -96,9 +93,9 @@ void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr)
*
* Return: always 0
*/
-int mei_cl_irq_read_msg(struct mei_cl *cl,
- struct mei_msg_hdr *mei_hdr,
- struct list_head *cmpl_list)
+static int mei_cl_irq_read_msg(struct mei_cl *cl,
+ struct mei_msg_hdr *mei_hdr,
+ struct list_head *cmpl_list)
{
struct mei_device *dev = cl->dev;
struct mei_cl_cb *cb;
@@ -313,11 +310,7 @@ int mei_irq_read_handler(struct mei_device *dev,
goto end;
}
- if (cl == &dev->iamthif_cl) {
- ret = mei_amthif_irq_read_msg(cl, mei_hdr, cmpl_list);
- } else {
- ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list);
- }
+ ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list);
reset_slots:
@@ -423,10 +416,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct list_head *cmpl_list)
dev_dbg(dev->dev, "complete write list cb.\n");
list_for_each_entry_safe(cb, next, &dev->write_list, list) {
cl = cb->cl;
- if (cl == &dev->iamthif_cl)
- ret = mei_amthif_irq_write(cl, cb, cmpl_list);
- else
- ret = mei_cl_irq_write(cl, cb, cmpl_list);
+ ret = mei_cl_irq_write(cl, cb, cmpl_list);
if (ret)
return ret;
}
@@ -512,20 +502,6 @@ void mei_timer(struct work_struct *work)
}
}
- if (!mei_cl_is_connected(&dev->iamthif_cl))
- goto out;
-
- if (dev->iamthif_stall_timer) {
- if (--dev->iamthif_stall_timer == 0) {
- dev_err(dev->dev, "timer: amthif hanged.\n");
- mei_reset(dev);
-
- mei_amthif_run_next_cmd(dev);
- goto out;
- }
- reschedule_timer = true;
- }
-
out:
if (dev->dev_state != MEI_DEV_DISABLED && reschedule_timer)
mei_schedule_stall_timer(dev);
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index bf816449cd40..e825f013e54e 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -103,10 +103,7 @@ static int mei_release(struct inode *inode, struct file *file)
dev = cl->dev;
mutex_lock(&dev->device_lock);
- if (cl == &dev->iamthif_cl) {
- rets = mei_amthif_release(dev, file);
- goto out;
- }
+
rets = mei_cl_disconnect(cl);
mei_cl_flush_queues(cl, file);
@@ -117,7 +114,7 @@ static int mei_release(struct inode *inode, struct file *file)
file->private_data = NULL;
kfree(cl);
-out:
+
mutex_unlock(&dev->device_lock);
return rets;
}
@@ -182,8 +179,6 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
goto out;
}
-
-again:
mutex_unlock(&dev->device_lock);
if (wait_event_interruptible(cl->rx_wait,
!list_empty(&cl->rd_completed) ||
@@ -201,14 +196,6 @@ again:
cb = mei_cl_read_cb(cl, file);
if (!cb) {
- /*
- * For amthif all the waiters are woken up,
- * but only fp with matching cb->fp get the cb,
- * the others have to return to wait on read.
- */
- if (cl == &dev->iamthif_cl)
- goto again;
-
rets = 0;
goto out;
}
@@ -319,13 +306,6 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
goto out;
}
- if (cl == &dev->iamthif_cl) {
- rets = mei_amthif_write(cl, cb);
- if (!rets)
- rets = length;
- goto out;
- }
-
rets = mei_cl_write(cl, cb);
out:
mutex_unlock(&dev->device_lock);
@@ -388,30 +368,6 @@ static int mei_ioctl_connect_client(struct file *file,
dev_dbg(dev->dev, "FW Client - Max Msg Len = %d\n",
me_cl->props.max_msg_length);
- /* if we're connecting to amthif client then we will use the
- * existing connection
- */
- if (uuid_le_cmp(data->in_client_uuid, mei_amthif_guid) == 0) {
- dev_dbg(dev->dev, "FW Client is amthi\n");
- if (!mei_cl_is_connected(&dev->iamthif_cl)) {
- rets = -ENODEV;
- goto end;
- }
- mei_cl_unlink(cl);
-
- kfree(cl);
- cl = NULL;
- dev->iamthif_open_count++;
- file->private_data = &dev->iamthif_cl;
-
- client = &data->out_client_properties;
- client->max_msg_length = me_cl->props.max_msg_length;
- client->protocol_version = me_cl->props.protocol_version;
- rets = dev->iamthif_cl.status;
-
- goto end;
- }
-
/* prepare the output buffer */
client = &data->out_client_properties;
client->max_msg_length = me_cl->props.max_msg_length;
@@ -615,11 +571,6 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
mask |= POLLPRI;
}
- if (cl == &dev->iamthif_cl) {
- mask |= mei_amthif_poll(file, wait);
- goto out;
- }
-
if (req_events & (POLLIN | POLLRDNORM)) {
poll_wait(file, &cl->rx_wait, wait);
@@ -635,6 +586,77 @@ out:
}
/**
+ * mei_cl_is_write_queued - check if the client has pending writes.
+ *
+ * @cl: writing host client
+ *
+ * Return: true if client is writing, false otherwise.
+ */
+static bool mei_cl_is_write_queued(struct mei_cl *cl)
+{
+ struct mei_device *dev = cl->dev;
+ struct mei_cl_cb *cb;
+
+ list_for_each_entry(cb, &dev->write_list, list)
+ if (cb->cl == cl)
+ return true;
+ list_for_each_entry(cb, &dev->write_waiting_list, list)
+ if (cb->cl == cl)
+ return true;
+ return false;
+}
+
+/**
+ * mei_fsync - the fsync handler
+ *
+ * @fp: pointer to file structure
+ * @start: unused
+ * @end: unused
+ * @datasync: unused
+ *
+ * Return: 0 on success, -ENODEV if client is not connected
+ */
+static int mei_fsync(struct file *fp, loff_t start, loff_t end, int datasync)
+{
+ struct mei_cl *cl = fp->private_data;
+ struct mei_device *dev;
+ int rets;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ mutex_lock(&dev->device_lock);
+
+ if (dev->dev_state != MEI_DEV_ENABLED || !mei_cl_is_connected(cl)) {
+ rets = -ENODEV;
+ goto out;
+ }
+
+ while (mei_cl_is_write_queued(cl)) {
+ mutex_unlock(&dev->device_lock);
+ rets = wait_event_interruptible(cl->tx_wait,
+ cl->writing_state == MEI_WRITE_COMPLETE ||
+ !mei_cl_is_connected(cl));
+ mutex_lock(&dev->device_lock);
+ if (rets) {
+ if (signal_pending(current))
+ rets = -EINTR;
+ goto out;
+ }
+ if (!mei_cl_is_connected(cl)) {
+ rets = -ENODEV;
+ goto out;
+ }
+ }
+ rets = 0;
+out:
+ mutex_unlock(&dev->device_lock);
+ return rets;
+}
+
+/**
* mei_fasync - asynchronous io support
*
* @fd: file descriptor
@@ -749,6 +771,7 @@ static const struct file_operations mei_fops = {
.release = mei_release,
.write = mei_write,
.poll = mei_poll,
+ .fsync = mei_fsync,
.fasync = mei_fasync,
.llseek = no_llseek
};
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index d41aac53a2ac..63a67c99fc78 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -26,12 +26,6 @@
#include "hw.h"
#include "hbm.h"
-
-/*
- * AMTHI Client UUID
- */
-extern const uuid_le mei_amthif_guid;
-
#define MEI_RD_MSG_BUF_SIZE (128 * sizeof(u32))
/*
@@ -78,12 +72,6 @@ enum mei_dev_state {
const char *mei_dev_state_str(int state);
-enum iamthif_states {
- MEI_IAMTHIF_IDLE,
- MEI_IAMTHIF_WRITING,
- MEI_IAMTHIF_READING,
-};
-
enum mei_file_transaction_states {
MEI_IDLE,
MEI_WRITING,
@@ -418,13 +406,6 @@ const char *mei_pg_state_str(enum mei_pg_state state);
* @allow_fixed_address: allow user space to connect a fixed client
* @override_fixed_address: force allow fixed address behavior
*
- * @amthif_cmd_list : amthif list for cmd waiting
- * @iamthif_cl : amthif host client
- * @iamthif_open_count : number of opened amthif connections
- * @iamthif_stall_timer : timer to detect amthif hang
- * @iamthif_state : amthif processor state
- * @iamthif_canceled : current amthif command is canceled
- *
* @reset_work : work item for the device reset
* @bus_rescan_work : work item for the bus rescan
*
@@ -500,14 +481,6 @@ struct mei_device {
bool allow_fixed_address;
bool override_fixed_address;
- /* amthif list for cmd waiting */
- struct list_head amthif_cmd_list;
- struct mei_cl iamthif_cl;
- long iamthif_open_count;
- u32 iamthif_stall_timer;
- enum iamthif_states iamthif_state;
- bool iamthif_canceled;
-
struct work_struct reset_work;
struct work_struct bus_rescan_work;
@@ -579,28 +552,6 @@ int mei_irq_write_handler(struct mei_device *dev, struct list_head *cmpl_list);
void mei_irq_compl_handler(struct mei_device *dev, struct list_head *cmpl_list);
/*
- * AMTHIF - AMT Host Interface Functions
- */
-void mei_amthif_reset_params(struct mei_device *dev);
-
-int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl);
-
-unsigned int mei_amthif_poll(struct file *file, poll_table *wait);
-
-int mei_amthif_release(struct mei_device *dev, struct file *file);
-
-int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb);
-int mei_amthif_run_next_cmd(struct mei_device *dev);
-int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
- struct list_head *cmpl_list);
-
-void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb);
-int mei_amthif_irq_read_msg(struct mei_cl *cl,
- struct mei_msg_hdr *mei_hdr,
- struct list_head *cmpl_list);
-int mei_amthif_irq_read(struct mei_device *dev, s32 *slots);
-
-/*
* Register Access Function
*/
@@ -711,8 +662,6 @@ bool mei_hbuf_acquire(struct mei_device *dev);
bool mei_write_is_idle(struct mei_device *dev);
-void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr);
-
#if IS_ENABLED(CONFIG_DEBUG_FS)
int mei_dbgfs_register(struct mei_device *dev, const char *name);
void mei_dbgfs_deregister(struct mei_device *dev);
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index 0a668fdfbbe9..8621a198a2ce 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -242,11 +242,38 @@ end:
}
/**
+ * mei_me_shutdown - Device Removal Routine
+ *
+ * @pdev: PCI device structure
+ *
+ * mei_me_shutdown is called from the reboot notifier
+ * it's a simplified version of remove so we go down
+ * faster.
+ */
+static void mei_me_shutdown(struct pci_dev *pdev)
+{
+ struct mei_device *dev;
+
+ dev = pci_get_drvdata(pdev);
+ if (!dev)
+ return;
+
+ dev_dbg(&pdev->dev, "shutdown\n");
+ mei_stop(dev);
+
+ if (!pci_dev_run_wake(pdev))
+ mei_me_unset_pm_domain(dev);
+
+ mei_disable_interrupts(dev);
+ free_irq(pdev->irq, dev);
+}
+
+/**
* mei_me_remove - Device Removal Routine
*
* @pdev: PCI device structure
*
- * mei_remove is called by the PCI subsystem to alert the driver
+ * mei_me_remove is called by the PCI subsystem to alert the driver
* that it should release a PCI device.
*/
static void mei_me_remove(struct pci_dev *pdev)
@@ -456,7 +483,7 @@ static struct pci_driver mei_me_driver = {
.id_table = mei_me_pci_tbl,
.probe = mei_me_probe,
.remove = mei_me_remove,
- .shutdown = mei_me_remove,
+ .shutdown = mei_me_shutdown,
.driver.pm = MEI_ME_PM_OPS,
};
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c
index fe088b40daf9..f811cd524468 100644
--- a/drivers/misc/mei/pci-txe.c
+++ b/drivers/misc/mei/pci-txe.c
@@ -161,6 +161,33 @@ end:
}
/**
+ * mei_txe_remove - Device Shutdown Routine
+ *
+ * @pdev: PCI device structure
+ *
+ * mei_txe_shutdown is called from the reboot notifier
+ * it's a simplified version of remove so we go down
+ * faster.
+ */
+static void mei_txe_shutdown(struct pci_dev *pdev)
+{
+ struct mei_device *dev;
+
+ dev = pci_get_drvdata(pdev);
+ if (!dev)
+ return;
+
+ dev_dbg(&pdev->dev, "shutdown\n");
+ mei_stop(dev);
+
+ if (!pci_dev_run_wake(pdev))
+ mei_txe_unset_pm_domain(dev);
+
+ mei_disable_interrupts(dev);
+ free_irq(pdev->irq, dev);
+}
+
+/**
* mei_txe_remove - Device Removal Routine
*
* @pdev: PCI device structure
@@ -386,7 +413,7 @@ static struct pci_driver mei_txe_driver = {
.id_table = mei_txe_pci_tbl,
.probe = mei_txe_probe,
.remove = mei_txe_remove,
- .shutdown = mei_txe_remove,
+ .shutdown = mei_txe_shutdown,
.driver.pm = MEI_TXE_PM_OPS,
};
diff --git a/drivers/misc/panel.c b/drivers/misc/panel.c
deleted file mode 100644
index ef2ece0f26af..000000000000
--- a/drivers/misc/panel.c
+++ /dev/null
@@ -1,2439 +0,0 @@
-/*
- * Front panel driver for Linux
- * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * This code drives an LCD module (/dev/lcd), and a keypad (/dev/keypad)
- * connected to a parallel printer port.
- *
- * The LCD module may either be an HD44780-like 8-bit parallel LCD, or a 1-bit
- * serial module compatible with Samsung's KS0074. The pins may be connected in
- * any combination, everything is programmable.
- *
- * The keypad consists in a matrix of push buttons connecting input pins to
- * data output pins or to the ground. The combinations have to be hard-coded
- * in the driver, though several profiles exist and adding new ones is easy.
- *
- * Several profiles are provided for commonly found LCD+keypad modules on the
- * market, such as those found in Nexcom's appliances.
- *
- * FIXME:
- * - the initialization/deinitialization process is very dirty and should
- * be rewritten. It may even be buggy.
- *
- * TODO:
- * - document 24 keys keyboard (3 rows of 8 cols, 32 diodes + 2 inputs)
- * - make the LCD a part of a virtual screen of Vx*Vy
- * - make the inputs list smp-safe
- * - change the keyboard to a double mapping : signals -> key_id -> values
- * so that applications can change values without knowing signals
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/ctype.h>
-#include <linux/parport.h>
-#include <linux/list.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/workqueue.h>
-#include <generated/utsrelease.h>
-
-#include <linux/io.h>
-#include <linux/uaccess.h>
-
-#define LCD_MINOR 156
-#define KEYPAD_MINOR 185
-
-#define LCD_MAXBYTES 256 /* max burst write */
-
-#define KEYPAD_BUFFER 64
-
-/* poll the keyboard this every second */
-#define INPUT_POLL_TIME (HZ / 50)
-/* a key starts to repeat after this times INPUT_POLL_TIME */
-#define KEYPAD_REP_START (10)
-/* a key repeats this times INPUT_POLL_TIME */
-#define KEYPAD_REP_DELAY (2)
-
-/* keep the light on this many seconds for each flash */
-#define FLASH_LIGHT_TEMPO (4)
-
-/* converts an r_str() input to an active high, bits string : 000BAOSE */
-#define PNL_PINPUT(a) ((((unsigned char)(a)) ^ 0x7F) >> 3)
-
-#define PNL_PBUSY 0x80 /* inverted input, active low */
-#define PNL_PACK 0x40 /* direct input, active low */
-#define PNL_POUTPA 0x20 /* direct input, active high */
-#define PNL_PSELECD 0x10 /* direct input, active high */
-#define PNL_PERRORP 0x08 /* direct input, active low */
-
-#define PNL_PBIDIR 0x20 /* bi-directional ports */
-/* high to read data in or-ed with data out */
-#define PNL_PINTEN 0x10
-#define PNL_PSELECP 0x08 /* inverted output, active low */
-#define PNL_PINITP 0x04 /* direct output, active low */
-#define PNL_PAUTOLF 0x02 /* inverted output, active low */
-#define PNL_PSTROBE 0x01 /* inverted output */
-
-#define PNL_PD0 0x01
-#define PNL_PD1 0x02
-#define PNL_PD2 0x04
-#define PNL_PD3 0x08
-#define PNL_PD4 0x10
-#define PNL_PD5 0x20
-#define PNL_PD6 0x40
-#define PNL_PD7 0x80
-
-#define PIN_NONE 0
-#define PIN_STROBE 1
-#define PIN_D0 2
-#define PIN_D1 3
-#define PIN_D2 4
-#define PIN_D3 5
-#define PIN_D4 6
-#define PIN_D5 7
-#define PIN_D6 8
-#define PIN_D7 9
-#define PIN_AUTOLF 14
-#define PIN_INITP 16
-#define PIN_SELECP 17
-#define PIN_NOT_SET 127
-
-#define LCD_FLAG_B 0x0004 /* blink on */
-#define LCD_FLAG_C 0x0008 /* cursor on */
-#define LCD_FLAG_D 0x0010 /* display on */
-#define LCD_FLAG_F 0x0020 /* large font mode */
-#define LCD_FLAG_N 0x0040 /* 2-rows mode */
-#define LCD_FLAG_L 0x0080 /* backlight enabled */
-
-/* LCD commands */
-#define LCD_CMD_DISPLAY_CLEAR 0x01 /* Clear entire display */
-
-#define LCD_CMD_ENTRY_MODE 0x04 /* Set entry mode */
-#define LCD_CMD_CURSOR_INC 0x02 /* Increment cursor */
-
-#define LCD_CMD_DISPLAY_CTRL 0x08 /* Display control */
-#define LCD_CMD_DISPLAY_ON 0x04 /* Set display on */
-#define LCD_CMD_CURSOR_ON 0x02 /* Set cursor on */
-#define LCD_CMD_BLINK_ON 0x01 /* Set blink on */
-
-#define LCD_CMD_SHIFT 0x10 /* Shift cursor/display */
-#define LCD_CMD_DISPLAY_SHIFT 0x08 /* Shift display instead of cursor */
-#define LCD_CMD_SHIFT_RIGHT 0x04 /* Shift display/cursor to the right */
-
-#define LCD_CMD_FUNCTION_SET 0x20 /* Set function */
-#define LCD_CMD_DATA_LEN_8BITS 0x10 /* Set data length to 8 bits */
-#define LCD_CMD_TWO_LINES 0x08 /* Set to two display lines */
-#define LCD_CMD_FONT_5X10_DOTS 0x04 /* Set char font to 5x10 dots */
-
-#define LCD_CMD_SET_CGRAM_ADDR 0x40 /* Set char generator RAM address */
-
-#define LCD_CMD_SET_DDRAM_ADDR 0x80 /* Set display data RAM address */
-
-#define LCD_ESCAPE_LEN 24 /* max chars for LCD escape command */
-#define LCD_ESCAPE_CHAR 27 /* use char 27 for escape command */
-
-#define NOT_SET -1
-
-/* macros to simplify use of the parallel port */
-#define r_ctr(x) (parport_read_control((x)->port))
-#define r_dtr(x) (parport_read_data((x)->port))
-#define r_str(x) (parport_read_status((x)->port))
-#define w_ctr(x, y) (parport_write_control((x)->port, (y)))
-#define w_dtr(x, y) (parport_write_data((x)->port, (y)))
-
-/* this defines which bits are to be used and which ones to be ignored */
-/* logical or of the output bits involved in the scan matrix */
-static __u8 scan_mask_o;
-/* logical or of the input bits involved in the scan matrix */
-static __u8 scan_mask_i;
-
-enum input_type {
- INPUT_TYPE_STD,
- INPUT_TYPE_KBD,
-};
-
-enum input_state {
- INPUT_ST_LOW,
- INPUT_ST_RISING,
- INPUT_ST_HIGH,
- INPUT_ST_FALLING,
-};
-
-struct logical_input {
- struct list_head list;
- __u64 mask;
- __u64 value;
- enum input_type type;
- enum input_state state;
- __u8 rise_time, fall_time;
- __u8 rise_timer, fall_timer, high_timer;
-
- union {
- struct { /* valid when type == INPUT_TYPE_STD */
- void (*press_fct)(int);
- void (*release_fct)(int);
- int press_data;
- int release_data;
- } std;
- struct { /* valid when type == INPUT_TYPE_KBD */
- /* strings can be non null-terminated */
- char press_str[sizeof(void *) + sizeof(int)];
- char repeat_str[sizeof(void *) + sizeof(int)];
- char release_str[sizeof(void *) + sizeof(int)];
- } kbd;
- } u;
-};
-
-static LIST_HEAD(logical_inputs); /* list of all defined logical inputs */
-
-/* physical contacts history
- * Physical contacts are a 45 bits string of 9 groups of 5 bits each.
- * The 8 lower groups correspond to output bits 0 to 7, and the 9th group
- * corresponds to the ground.
- * Within each group, bits are stored in the same order as read on the port :
- * BAPSE (busy=4, ack=3, paper empty=2, select=1, error=0).
- * So, each __u64 is represented like this :
- * 0000000000000000000BAPSEBAPSEBAPSEBAPSEBAPSEBAPSEBAPSEBAPSEBAPSE
- * <-----unused------><gnd><d07><d06><d05><d04><d03><d02><d01><d00>
- */
-
-/* what has just been read from the I/O ports */
-static __u64 phys_read;
-/* previous phys_read */
-static __u64 phys_read_prev;
-/* stabilized phys_read (phys_read|phys_read_prev) */
-static __u64 phys_curr;
-/* previous phys_curr */
-static __u64 phys_prev;
-/* 0 means that at least one logical signal needs be computed */
-static char inputs_stable;
-
-/* these variables are specific to the keypad */
-static struct {
- bool enabled;
-} keypad;
-
-static char keypad_buffer[KEYPAD_BUFFER];
-static int keypad_buflen;
-static int keypad_start;
-static char keypressed;
-static wait_queue_head_t keypad_read_wait;
-
-/* lcd-specific variables */
-static struct {
- bool enabled;
- bool initialized;
- bool must_clear;
-
- int height;
- int width;
- int bwidth;
- int hwidth;
- int charset;
- int proto;
-
- struct delayed_work bl_work;
- struct mutex bl_tempo_lock; /* Protects access to bl_tempo */
- bool bl_tempo;
-
- /* TODO: use union here? */
- struct {
- int e;
- int rs;
- int rw;
- int cl;
- int da;
- int bl;
- } pins;
-
- /* contains the LCD config state */
- unsigned long int flags;
-
- /* Contains the LCD X and Y offset */
- struct {
- unsigned long int x;
- unsigned long int y;
- } addr;
-
- /* Current escape sequence and it's length or -1 if outside */
- struct {
- char buf[LCD_ESCAPE_LEN + 1];
- int len;
- } esc_seq;
-} lcd;
-
-/* Needed only for init */
-static int selected_lcd_type = NOT_SET;
-
-/*
- * Bit masks to convert LCD signals to parallel port outputs.
- * _d_ are values for data port, _c_ are for control port.
- * [0] = signal OFF, [1] = signal ON, [2] = mask
- */
-#define BIT_CLR 0
-#define BIT_SET 1
-#define BIT_MSK 2
-#define BIT_STATES 3
-/*
- * one entry for each bit on the LCD
- */
-#define LCD_BIT_E 0
-#define LCD_BIT_RS 1
-#define LCD_BIT_RW 2
-#define LCD_BIT_BL 3
-#define LCD_BIT_CL 4
-#define LCD_BIT_DA 5
-#define LCD_BITS 6
-
-/*
- * each bit can be either connected to a DATA or CTRL port
- */
-#define LCD_PORT_C 0
-#define LCD_PORT_D 1
-#define LCD_PORTS 2
-
-static unsigned char lcd_bits[LCD_PORTS][LCD_BITS][BIT_STATES];
-
-/*
- * LCD protocols
- */
-#define LCD_PROTO_PARALLEL 0
-#define LCD_PROTO_SERIAL 1
-#define LCD_PROTO_TI_DA8XX_LCD 2
-
-/*
- * LCD character sets
- */
-#define LCD_CHARSET_NORMAL 0
-#define LCD_CHARSET_KS0074 1
-
-/*
- * LCD types
- */
-#define LCD_TYPE_NONE 0
-#define LCD_TYPE_CUSTOM 1
-#define LCD_TYPE_OLD 2
-#define LCD_TYPE_KS0074 3
-#define LCD_TYPE_HANTRONIX 4
-#define LCD_TYPE_NEXCOM 5
-
-/*
- * keypad types
- */
-#define KEYPAD_TYPE_NONE 0
-#define KEYPAD_TYPE_OLD 1
-#define KEYPAD_TYPE_NEW 2
-#define KEYPAD_TYPE_NEXCOM 3
-
-/*
- * panel profiles
- */
-#define PANEL_PROFILE_CUSTOM 0
-#define PANEL_PROFILE_OLD 1
-#define PANEL_PROFILE_NEW 2
-#define PANEL_PROFILE_HANTRONIX 3
-#define PANEL_PROFILE_NEXCOM 4
-#define PANEL_PROFILE_LARGE 5
-
-/*
- * Construct custom config from the kernel's configuration
- */
-#define DEFAULT_PARPORT 0
-#define DEFAULT_PROFILE PANEL_PROFILE_LARGE
-#define DEFAULT_KEYPAD_TYPE KEYPAD_TYPE_OLD
-#define DEFAULT_LCD_TYPE LCD_TYPE_OLD
-#define DEFAULT_LCD_HEIGHT 2
-#define DEFAULT_LCD_WIDTH 40
-#define DEFAULT_LCD_BWIDTH 40
-#define DEFAULT_LCD_HWIDTH 64
-#define DEFAULT_LCD_CHARSET LCD_CHARSET_NORMAL
-#define DEFAULT_LCD_PROTO LCD_PROTO_PARALLEL
-
-#define DEFAULT_LCD_PIN_E PIN_AUTOLF
-#define DEFAULT_LCD_PIN_RS PIN_SELECP
-#define DEFAULT_LCD_PIN_RW PIN_INITP
-#define DEFAULT_LCD_PIN_SCL PIN_STROBE
-#define DEFAULT_LCD_PIN_SDA PIN_D0
-#define DEFAULT_LCD_PIN_BL PIN_NOT_SET
-
-#ifdef CONFIG_PANEL_PARPORT
-#undef DEFAULT_PARPORT
-#define DEFAULT_PARPORT CONFIG_PANEL_PARPORT
-#endif
-
-#ifdef CONFIG_PANEL_PROFILE
-#undef DEFAULT_PROFILE
-#define DEFAULT_PROFILE CONFIG_PANEL_PROFILE
-#endif
-
-#if DEFAULT_PROFILE == 0 /* custom */
-#ifdef CONFIG_PANEL_KEYPAD
-#undef DEFAULT_KEYPAD_TYPE
-#define DEFAULT_KEYPAD_TYPE CONFIG_PANEL_KEYPAD
-#endif
-
-#ifdef CONFIG_PANEL_LCD
-#undef DEFAULT_LCD_TYPE
-#define DEFAULT_LCD_TYPE CONFIG_PANEL_LCD
-#endif
-
-#ifdef CONFIG_PANEL_LCD_HEIGHT
-#undef DEFAULT_LCD_HEIGHT
-#define DEFAULT_LCD_HEIGHT CONFIG_PANEL_LCD_HEIGHT
-#endif
-
-#ifdef CONFIG_PANEL_LCD_WIDTH
-#undef DEFAULT_LCD_WIDTH
-#define DEFAULT_LCD_WIDTH CONFIG_PANEL_LCD_WIDTH
-#endif
-
-#ifdef CONFIG_PANEL_LCD_BWIDTH
-#undef DEFAULT_LCD_BWIDTH
-#define DEFAULT_LCD_BWIDTH CONFIG_PANEL_LCD_BWIDTH
-#endif
-
-#ifdef CONFIG_PANEL_LCD_HWIDTH
-#undef DEFAULT_LCD_HWIDTH
-#define DEFAULT_LCD_HWIDTH CONFIG_PANEL_LCD_HWIDTH
-#endif
-
-#ifdef CONFIG_PANEL_LCD_CHARSET
-#undef DEFAULT_LCD_CHARSET
-#define DEFAULT_LCD_CHARSET CONFIG_PANEL_LCD_CHARSET
-#endif
-
-#ifdef CONFIG_PANEL_LCD_PROTO
-#undef DEFAULT_LCD_PROTO
-#define DEFAULT_LCD_PROTO CONFIG_PANEL_LCD_PROTO
-#endif
-
-#ifdef CONFIG_PANEL_LCD_PIN_E
-#undef DEFAULT_LCD_PIN_E
-#define DEFAULT_LCD_PIN_E CONFIG_PANEL_LCD_PIN_E
-#endif
-
-#ifdef CONFIG_PANEL_LCD_PIN_RS
-#undef DEFAULT_LCD_PIN_RS
-#define DEFAULT_LCD_PIN_RS CONFIG_PANEL_LCD_PIN_RS
-#endif
-
-#ifdef CONFIG_PANEL_LCD_PIN_RW
-#undef DEFAULT_LCD_PIN_RW
-#define DEFAULT_LCD_PIN_RW CONFIG_PANEL_LCD_PIN_RW
-#endif
-
-#ifdef CONFIG_PANEL_LCD_PIN_SCL
-#undef DEFAULT_LCD_PIN_SCL
-#define DEFAULT_LCD_PIN_SCL CONFIG_PANEL_LCD_PIN_SCL
-#endif
-
-#ifdef CONFIG_PANEL_LCD_PIN_SDA
-#undef DEFAULT_LCD_PIN_SDA
-#define DEFAULT_LCD_PIN_SDA CONFIG_PANEL_LCD_PIN_SDA
-#endif
-
-#ifdef CONFIG_PANEL_LCD_PIN_BL
-#undef DEFAULT_LCD_PIN_BL
-#define DEFAULT_LCD_PIN_BL CONFIG_PANEL_LCD_PIN_BL
-#endif
-
-#endif /* DEFAULT_PROFILE == 0 */
-
-/* global variables */
-
-/* Device single-open policy control */
-static atomic_t lcd_available = ATOMIC_INIT(1);
-static atomic_t keypad_available = ATOMIC_INIT(1);
-
-static struct pardevice *pprt;
-
-static int keypad_initialized;
-
-static void (*lcd_write_cmd)(int);
-static void (*lcd_write_data)(int);
-static void (*lcd_clear_fast)(void);
-
-static DEFINE_SPINLOCK(pprt_lock);
-static struct timer_list scan_timer;
-
-MODULE_DESCRIPTION("Generic parallel port LCD/Keypad driver");
-
-static int parport = DEFAULT_PARPORT;
-module_param(parport, int, 0000);
-MODULE_PARM_DESC(parport, "Parallel port index (0=lpt1, 1=lpt2, ...)");
-
-static int profile = DEFAULT_PROFILE;
-module_param(profile, int, 0000);
-MODULE_PARM_DESC(profile,
- "1=16x2 old kp; 2=serial 16x2, new kp; 3=16x2 hantronix; "
- "4=16x2 nexcom; default=40x2, old kp");
-
-static int keypad_type = NOT_SET;
-module_param(keypad_type, int, 0000);
-MODULE_PARM_DESC(keypad_type,
- "Keypad type: 0=none, 1=old 6 keys, 2=new 6+1 keys, 3=nexcom 4 keys");
-
-static int lcd_type = NOT_SET;
-module_param(lcd_type, int, 0000);
-MODULE_PARM_DESC(lcd_type,
- "LCD type: 0=none, 1=compiled-in, 2=old, 3=serial ks0074, 4=hantronix, 5=nexcom");
-
-static int lcd_height = NOT_SET;
-module_param(lcd_height, int, 0000);
-MODULE_PARM_DESC(lcd_height, "Number of lines on the LCD");
-
-static int lcd_width = NOT_SET;
-module_param(lcd_width, int, 0000);
-MODULE_PARM_DESC(lcd_width, "Number of columns on the LCD");
-
-static int lcd_bwidth = NOT_SET; /* internal buffer width (usually 40) */
-module_param(lcd_bwidth, int, 0000);
-MODULE_PARM_DESC(lcd_bwidth, "Internal LCD line width (40)");
-
-static int lcd_hwidth = NOT_SET; /* hardware buffer width (usually 64) */
-module_param(lcd_hwidth, int, 0000);
-MODULE_PARM_DESC(lcd_hwidth, "LCD line hardware address (64)");
-
-static int lcd_charset = NOT_SET;
-module_param(lcd_charset, int, 0000);
-MODULE_PARM_DESC(lcd_charset, "LCD character set: 0=standard, 1=KS0074");
-
-static int lcd_proto = NOT_SET;
-module_param(lcd_proto, int, 0000);
-MODULE_PARM_DESC(lcd_proto,
- "LCD communication: 0=parallel (//), 1=serial, 2=TI LCD Interface");
-
-/*
- * These are the parallel port pins the LCD control signals are connected to.
- * Set this to 0 if the signal is not used. Set it to its opposite value
- * (negative) if the signal is negated. -MAXINT is used to indicate that the
- * pin has not been explicitly specified.
- *
- * WARNING! no check will be performed about collisions with keypad !
- */
-
-static int lcd_e_pin = PIN_NOT_SET;
-module_param(lcd_e_pin, int, 0000);
-MODULE_PARM_DESC(lcd_e_pin,
- "# of the // port pin connected to LCD 'E' signal, with polarity (-17..17)");
-
-static int lcd_rs_pin = PIN_NOT_SET;
-module_param(lcd_rs_pin, int, 0000);
-MODULE_PARM_DESC(lcd_rs_pin,
- "# of the // port pin connected to LCD 'RS' signal, with polarity (-17..17)");
-
-static int lcd_rw_pin = PIN_NOT_SET;
-module_param(lcd_rw_pin, int, 0000);
-MODULE_PARM_DESC(lcd_rw_pin,
- "# of the // port pin connected to LCD 'RW' signal, with polarity (-17..17)");
-
-static int lcd_cl_pin = PIN_NOT_SET;
-module_param(lcd_cl_pin, int, 0000);
-MODULE_PARM_DESC(lcd_cl_pin,
- "# of the // port pin connected to serial LCD 'SCL' signal, with polarity (-17..17)");
-
-static int lcd_da_pin = PIN_NOT_SET;
-module_param(lcd_da_pin, int, 0000);
-MODULE_PARM_DESC(lcd_da_pin,
- "# of the // port pin connected to serial LCD 'SDA' signal, with polarity (-17..17)");
-
-static int lcd_bl_pin = PIN_NOT_SET;
-module_param(lcd_bl_pin, int, 0000);
-MODULE_PARM_DESC(lcd_bl_pin,
- "# of the // port pin connected to LCD backlight, with polarity (-17..17)");
-
-/* Deprecated module parameters - consider not using them anymore */
-
-static int lcd_enabled = NOT_SET;
-module_param(lcd_enabled, int, 0000);
-MODULE_PARM_DESC(lcd_enabled, "Deprecated option, use lcd_type instead");
-
-static int keypad_enabled = NOT_SET;
-module_param(keypad_enabled, int, 0000);
-MODULE_PARM_DESC(keypad_enabled, "Deprecated option, use keypad_type instead");
-
-static const unsigned char *lcd_char_conv;
-
-/* for some LCD drivers (ks0074) we need a charset conversion table. */
-static const unsigned char lcd_char_conv_ks0074[256] = {
- /* 0|8 1|9 2|A 3|B 4|C 5|D 6|E 7|F */
- /* 0x00 */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- /* 0x08 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- /* 0x10 */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- /* 0x18 */ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- /* 0x20 */ 0x20, 0x21, 0x22, 0x23, 0xa2, 0x25, 0x26, 0x27,
- /* 0x28 */ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
- /* 0x30 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
- /* 0x38 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- /* 0x40 */ 0xa0, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- /* 0x48 */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- /* 0x50 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- /* 0x58 */ 0x58, 0x59, 0x5a, 0xfa, 0xfb, 0xfc, 0x1d, 0xc4,
- /* 0x60 */ 0x96, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- /* 0x68 */ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
- /* 0x70 */ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
- /* 0x78 */ 0x78, 0x79, 0x7a, 0xfd, 0xfe, 0xff, 0xce, 0x20,
- /* 0x80 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- /* 0x88 */ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
- /* 0x90 */ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
- /* 0x98 */ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
- /* 0xA0 */ 0x20, 0x40, 0xb1, 0xa1, 0x24, 0xa3, 0xfe, 0x5f,
- /* 0xA8 */ 0x22, 0xc8, 0x61, 0x14, 0x97, 0x2d, 0xad, 0x96,
- /* 0xB0 */ 0x80, 0x8c, 0x82, 0x83, 0x27, 0x8f, 0x86, 0xdd,
- /* 0xB8 */ 0x2c, 0x81, 0x6f, 0x15, 0x8b, 0x8a, 0x84, 0x60,
- /* 0xC0 */ 0xe2, 0xe2, 0xe2, 0x5b, 0x5b, 0xae, 0xbc, 0xa9,
- /* 0xC8 */ 0xc5, 0xbf, 0xc6, 0xf1, 0xe3, 0xe3, 0xe3, 0xe3,
- /* 0xD0 */ 0x44, 0x5d, 0xa8, 0xe4, 0xec, 0xec, 0x5c, 0x78,
- /* 0xD8 */ 0xab, 0xa6, 0xe5, 0x5e, 0x5e, 0xe6, 0xaa, 0xbe,
- /* 0xE0 */ 0x7f, 0xe7, 0xaf, 0x7b, 0x7b, 0xaf, 0xbd, 0xc8,
- /* 0xE8 */ 0xa4, 0xa5, 0xc7, 0xf6, 0xa7, 0xe8, 0x69, 0x69,
- /* 0xF0 */ 0xed, 0x7d, 0xa8, 0xe4, 0xec, 0x5c, 0x5c, 0x25,
- /* 0xF8 */ 0xac, 0xa6, 0xea, 0xef, 0x7e, 0xeb, 0xb2, 0x79,
-};
-
-static const char old_keypad_profile[][4][9] = {
- {"S0", "Left\n", "Left\n", ""},
- {"S1", "Down\n", "Down\n", ""},
- {"S2", "Up\n", "Up\n", ""},
- {"S3", "Right\n", "Right\n", ""},
- {"S4", "Esc\n", "Esc\n", ""},
- {"S5", "Ret\n", "Ret\n", ""},
- {"", "", "", ""}
-};
-
-/* signals, press, repeat, release */
-static const char new_keypad_profile[][4][9] = {
- {"S0", "Left\n", "Left\n", ""},
- {"S1", "Down\n", "Down\n", ""},
- {"S2", "Up\n", "Up\n", ""},
- {"S3", "Right\n", "Right\n", ""},
- {"S4s5", "", "Esc\n", "Esc\n"},
- {"s4S5", "", "Ret\n", "Ret\n"},
- {"S4S5", "Help\n", "", ""},
- /* add new signals above this line */
- {"", "", "", ""}
-};
-
-/* signals, press, repeat, release */
-static const char nexcom_keypad_profile[][4][9] = {
- {"a-p-e-", "Down\n", "Down\n", ""},
- {"a-p-E-", "Ret\n", "Ret\n", ""},
- {"a-P-E-", "Esc\n", "Esc\n", ""},
- {"a-P-e-", "Up\n", "Up\n", ""},
- /* add new signals above this line */
- {"", "", "", ""}
-};
-
-static const char (*keypad_profile)[4][9] = old_keypad_profile;
-
-static DECLARE_BITMAP(bits, LCD_BITS);
-
-static void lcd_get_bits(unsigned int port, int *val)
-{
- unsigned int bit, state;
-
- for (bit = 0; bit < LCD_BITS; bit++) {
- state = test_bit(bit, bits) ? BIT_SET : BIT_CLR;
- *val &= lcd_bits[port][bit][BIT_MSK];
- *val |= lcd_bits[port][bit][state];
- }
-}
-
-/* sets data port bits according to current signals values */
-static int set_data_bits(void)
-{
- int val;
-
- val = r_dtr(pprt);
- lcd_get_bits(LCD_PORT_D, &val);
- w_dtr(pprt, val);
- return val;
-}
-
-/* sets ctrl port bits according to current signals values */
-static int set_ctrl_bits(void)
-{
- int val;
-
- val = r_ctr(pprt);
- lcd_get_bits(LCD_PORT_C, &val);
- w_ctr(pprt, val);
- return val;
-}
-
-/* sets ctrl & data port bits according to current signals values */
-static void panel_set_bits(void)
-{
- set_data_bits();
- set_ctrl_bits();
-}
-
-/*
- * Converts a parallel port pin (from -25 to 25) to data and control ports
- * masks, and data and control port bits. The signal will be considered
- * unconnected if it's on pin 0 or an invalid pin (<-25 or >25).
- *
- * Result will be used this way :
- * out(dport, in(dport) & d_val[2] | d_val[signal_state])
- * out(cport, in(cport) & c_val[2] | c_val[signal_state])
- */
-static void pin_to_bits(int pin, unsigned char *d_val, unsigned char *c_val)
-{
- int d_bit, c_bit, inv;
-
- d_val[0] = 0;
- c_val[0] = 0;
- d_val[1] = 0;
- c_val[1] = 0;
- d_val[2] = 0xFF;
- c_val[2] = 0xFF;
-
- if (pin == 0)
- return;
-
- inv = (pin < 0);
- if (inv)
- pin = -pin;
-
- d_bit = 0;
- c_bit = 0;
-
- switch (pin) {
- case PIN_STROBE: /* strobe, inverted */
- c_bit = PNL_PSTROBE;
- inv = !inv;
- break;
- case PIN_D0...PIN_D7: /* D0 - D7 = 2 - 9 */
- d_bit = 1 << (pin - 2);
- break;
- case PIN_AUTOLF: /* autofeed, inverted */
- c_bit = PNL_PAUTOLF;
- inv = !inv;
- break;
- case PIN_INITP: /* init, direct */
- c_bit = PNL_PINITP;
- break;
- case PIN_SELECP: /* select_in, inverted */
- c_bit = PNL_PSELECP;
- inv = !inv;
- break;
- default: /* unknown pin, ignore */
- break;
- }
-
- if (c_bit) {
- c_val[2] &= ~c_bit;
- c_val[!inv] = c_bit;
- } else if (d_bit) {
- d_val[2] &= ~d_bit;
- d_val[!inv] = d_bit;
- }
-}
-
-/* sleeps that many milliseconds with a reschedule */
-static void long_sleep(int ms)
-{
- if (in_interrupt())
- mdelay(ms);
- else
- schedule_timeout_interruptible(msecs_to_jiffies(ms));
-}
-
-/*
- * send a serial byte to the LCD panel. The caller is responsible for locking
- * if needed.
- */
-static void lcd_send_serial(int byte)
-{
- int bit;
-
- /*
- * the data bit is set on D0, and the clock on STROBE.
- * LCD reads D0 on STROBE's rising edge.
- */
- for (bit = 0; bit < 8; bit++) {
- clear_bit(LCD_BIT_CL, bits); /* CLK low */
- panel_set_bits();
- if (byte & 1) {
- set_bit(LCD_BIT_DA, bits);
- } else {
- clear_bit(LCD_BIT_DA, bits);
- }
-
- panel_set_bits();
- udelay(2); /* maintain the data during 2 us before CLK up */
- set_bit(LCD_BIT_CL, bits); /* CLK high */
- panel_set_bits();
- udelay(1); /* maintain the strobe during 1 us */
- byte >>= 1;
- }
-}
-
-/* turn the backlight on or off */
-static void __lcd_backlight(int on)
-{
- /* The backlight is activated by setting the AUTOFEED line to +5V */
- spin_lock_irq(&pprt_lock);
- if (on)
- set_bit(LCD_BIT_BL, bits);
- else
- clear_bit(LCD_BIT_BL, bits);
- panel_set_bits();
- spin_unlock_irq(&pprt_lock);
-}
-
-static void lcd_backlight(int on)
-{
- if (lcd.pins.bl == PIN_NONE)
- return;
-
- mutex_lock(&lcd.bl_tempo_lock);
- if (!lcd.bl_tempo)
- __lcd_backlight(on);
- mutex_unlock(&lcd.bl_tempo_lock);
-}
-
-static void lcd_bl_off(struct work_struct *work)
-{
- mutex_lock(&lcd.bl_tempo_lock);
- if (lcd.bl_tempo) {
- lcd.bl_tempo = false;
- if (!(lcd.flags & LCD_FLAG_L))
- __lcd_backlight(0);
- }
- mutex_unlock(&lcd.bl_tempo_lock);
-}
-
-/* turn the backlight on for a little while */
-static void lcd_poke(void)
-{
- if (lcd.pins.bl == PIN_NONE)
- return;
-
- cancel_delayed_work_sync(&lcd.bl_work);
-
- mutex_lock(&lcd.bl_tempo_lock);
- if (!lcd.bl_tempo && !(lcd.flags & LCD_FLAG_L))
- __lcd_backlight(1);
- lcd.bl_tempo = true;
- schedule_delayed_work(&lcd.bl_work, FLASH_LIGHT_TEMPO * HZ);
- mutex_unlock(&lcd.bl_tempo_lock);
-}
-
-/* send a command to the LCD panel in serial mode */
-static void lcd_write_cmd_s(int cmd)
-{
- spin_lock_irq(&pprt_lock);
- lcd_send_serial(0x1F); /* R/W=W, RS=0 */
- lcd_send_serial(cmd & 0x0F);
- lcd_send_serial((cmd >> 4) & 0x0F);
- udelay(40); /* the shortest command takes at least 40 us */
- spin_unlock_irq(&pprt_lock);
-}
-
-/* send data to the LCD panel in serial mode */
-static void lcd_write_data_s(int data)
-{
- spin_lock_irq(&pprt_lock);
- lcd_send_serial(0x5F); /* R/W=W, RS=1 */
- lcd_send_serial(data & 0x0F);
- lcd_send_serial((data >> 4) & 0x0F);
- udelay(40); /* the shortest data takes at least 40 us */
- spin_unlock_irq(&pprt_lock);
-}
-
-/* send a command to the LCD panel in 8 bits parallel mode */
-static void lcd_write_cmd_p8(int cmd)
-{
- spin_lock_irq(&pprt_lock);
- /* present the data to the data port */
- w_dtr(pprt, cmd);
- udelay(20); /* maintain the data during 20 us before the strobe */
-
- set_bit(LCD_BIT_E, bits);
- clear_bit(LCD_BIT_RS, bits);
- clear_bit(LCD_BIT_RW, bits);
- set_ctrl_bits();
-
- udelay(40); /* maintain the strobe during 40 us */
-
- clear_bit(LCD_BIT_E, bits);
- set_ctrl_bits();
-
- udelay(120); /* the shortest command takes at least 120 us */
- spin_unlock_irq(&pprt_lock);
-}
-
-/* send data to the LCD panel in 8 bits parallel mode */
-static void lcd_write_data_p8(int data)
-{
- spin_lock_irq(&pprt_lock);
- /* present the data to the data port */
- w_dtr(pprt, data);
- udelay(20); /* maintain the data during 20 us before the strobe */
-
- set_bit(LCD_BIT_E, bits);
- set_bit(LCD_BIT_RS, bits);
- clear_bit(LCD_BIT_RW, bits);
- set_ctrl_bits();
-
- udelay(40); /* maintain the strobe during 40 us */
-
- clear_bit(LCD_BIT_E, bits);
- set_ctrl_bits();
-
- udelay(45); /* the shortest data takes at least 45 us */
- spin_unlock_irq(&pprt_lock);
-}
-
-/* send a command to the TI LCD panel */
-static void lcd_write_cmd_tilcd(int cmd)
-{
- spin_lock_irq(&pprt_lock);
- /* present the data to the control port */
- w_ctr(pprt, cmd);
- udelay(60);
- spin_unlock_irq(&pprt_lock);
-}
-
-/* send data to the TI LCD panel */
-static void lcd_write_data_tilcd(int data)
-{
- spin_lock_irq(&pprt_lock);
- /* present the data to the data port */
- w_dtr(pprt, data);
- udelay(60);
- spin_unlock_irq(&pprt_lock);
-}
-
-static void lcd_gotoxy(void)
-{
- lcd_write_cmd(LCD_CMD_SET_DDRAM_ADDR
- | (lcd.addr.y ? lcd.hwidth : 0)
- /*
- * we force the cursor to stay at the end of the
- * line if it wants to go farther
- */
- | ((lcd.addr.x < lcd.bwidth) ? lcd.addr.x &
- (lcd.hwidth - 1) : lcd.bwidth - 1));
-}
-
-static void lcd_home(void)
-{
- lcd.addr.x = 0;
- lcd.addr.y = 0;
- lcd_gotoxy();
-}
-
-static void lcd_print(char c)
-{
- if (lcd.addr.x < lcd.bwidth) {
- if (lcd_char_conv)
- c = lcd_char_conv[(unsigned char)c];
- lcd_write_data(c);
- lcd.addr.x++;
- }
- /* prevents the cursor from wrapping onto the next line */
- if (lcd.addr.x == lcd.bwidth)
- lcd_gotoxy();
-}
-
-/* fills the display with spaces and resets X/Y */
-static void lcd_clear_fast_s(void)
-{
- int pos;
-
- lcd_home();
-
- spin_lock_irq(&pprt_lock);
- for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) {
- lcd_send_serial(0x5F); /* R/W=W, RS=1 */
- lcd_send_serial(' ' & 0x0F);
- lcd_send_serial((' ' >> 4) & 0x0F);
- /* the shortest data takes at least 40 us */
- udelay(40);
- }
- spin_unlock_irq(&pprt_lock);
-
- lcd_home();
-}
-
-/* fills the display with spaces and resets X/Y */
-static void lcd_clear_fast_p8(void)
-{
- int pos;
-
- lcd_home();
-
- spin_lock_irq(&pprt_lock);
- for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) {
- /* present the data to the data port */
- w_dtr(pprt, ' ');
-
- /* maintain the data during 20 us before the strobe */
- udelay(20);
-
- set_bit(LCD_BIT_E, bits);
- set_bit(LCD_BIT_RS, bits);
- clear_bit(LCD_BIT_RW, bits);
- set_ctrl_bits();
-
- /* maintain the strobe during 40 us */
- udelay(40);
-
- clear_bit(LCD_BIT_E, bits);
- set_ctrl_bits();
-
- /* the shortest data takes at least 45 us */
- udelay(45);
- }
- spin_unlock_irq(&pprt_lock);
-
- lcd_home();
-}
-
-/* fills the display with spaces and resets X/Y */
-static void lcd_clear_fast_tilcd(void)
-{
- int pos;
-
- lcd_home();
-
- spin_lock_irq(&pprt_lock);
- for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) {
- /* present the data to the data port */
- w_dtr(pprt, ' ');
- udelay(60);
- }
-
- spin_unlock_irq(&pprt_lock);
-
- lcd_home();
-}
-
-/* clears the display and resets X/Y */
-static void lcd_clear_display(void)
-{
- lcd_write_cmd(LCD_CMD_DISPLAY_CLEAR);
- lcd.addr.x = 0;
- lcd.addr.y = 0;
- /* we must wait a few milliseconds (15) */
- long_sleep(15);
-}
-
-static void lcd_init_display(void)
-{
- lcd.flags = ((lcd.height > 1) ? LCD_FLAG_N : 0)
- | LCD_FLAG_D | LCD_FLAG_C | LCD_FLAG_B;
-
- long_sleep(20); /* wait 20 ms after power-up for the paranoid */
-
- /* 8bits, 1 line, small fonts; let's do it 3 times */
- lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS);
- long_sleep(10);
- lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS);
- long_sleep(10);
- lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS);
- long_sleep(10);
-
- /* set font height and lines number */
- lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS
- | ((lcd.flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0)
- | ((lcd.flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0)
- );
- long_sleep(10);
-
- /* display off, cursor off, blink off */
- lcd_write_cmd(LCD_CMD_DISPLAY_CTRL);
- long_sleep(10);
-
- lcd_write_cmd(LCD_CMD_DISPLAY_CTRL /* set display mode */
- | ((lcd.flags & LCD_FLAG_D) ? LCD_CMD_DISPLAY_ON : 0)
- | ((lcd.flags & LCD_FLAG_C) ? LCD_CMD_CURSOR_ON : 0)
- | ((lcd.flags & LCD_FLAG_B) ? LCD_CMD_BLINK_ON : 0)
- );
-
- lcd_backlight((lcd.flags & LCD_FLAG_L) ? 1 : 0);
-
- long_sleep(10);
-
- /* entry mode set : increment, cursor shifting */
- lcd_write_cmd(LCD_CMD_ENTRY_MODE | LCD_CMD_CURSOR_INC);
-
- lcd_clear_display();
-}
-
-/*
- * These are the file operation function for user access to /dev/lcd
- * This function can also be called from inside the kernel, by
- * setting file and ppos to NULL.
- *
- */
-
-static inline int handle_lcd_special_code(void)
-{
- /* LCD special codes */
-
- int processed = 0;
-
- char *esc = lcd.esc_seq.buf + 2;
- int oldflags = lcd.flags;
-
- /* check for display mode flags */
- switch (*esc) {
- case 'D': /* Display ON */
- lcd.flags |= LCD_FLAG_D;
- processed = 1;
- break;
- case 'd': /* Display OFF */
- lcd.flags &= ~LCD_FLAG_D;
- processed = 1;
- break;
- case 'C': /* Cursor ON */
- lcd.flags |= LCD_FLAG_C;
- processed = 1;
- break;
- case 'c': /* Cursor OFF */
- lcd.flags &= ~LCD_FLAG_C;
- processed = 1;
- break;
- case 'B': /* Blink ON */
- lcd.flags |= LCD_FLAG_B;
- processed = 1;
- break;
- case 'b': /* Blink OFF */
- lcd.flags &= ~LCD_FLAG_B;
- processed = 1;
- break;
- case '+': /* Back light ON */
- lcd.flags |= LCD_FLAG_L;
- processed = 1;
- break;
- case '-': /* Back light OFF */
- lcd.flags &= ~LCD_FLAG_L;
- processed = 1;
- break;
- case '*':
- /* flash back light */
- lcd_poke();
- processed = 1;
- break;
- case 'f': /* Small Font */
- lcd.flags &= ~LCD_FLAG_F;
- processed = 1;
- break;
- case 'F': /* Large Font */
- lcd.flags |= LCD_FLAG_F;
- processed = 1;
- break;
- case 'n': /* One Line */
- lcd.flags &= ~LCD_FLAG_N;
- processed = 1;
- break;
- case 'N': /* Two Lines */
- lcd.flags |= LCD_FLAG_N;
- break;
- case 'l': /* Shift Cursor Left */
- if (lcd.addr.x > 0) {
- /* back one char if not at end of line */
- if (lcd.addr.x < lcd.bwidth)
- lcd_write_cmd(LCD_CMD_SHIFT);
- lcd.addr.x--;
- }
- processed = 1;
- break;
- case 'r': /* shift cursor right */
- if (lcd.addr.x < lcd.width) {
- /* allow the cursor to pass the end of the line */
- if (lcd.addr.x < (lcd.bwidth - 1))
- lcd_write_cmd(LCD_CMD_SHIFT |
- LCD_CMD_SHIFT_RIGHT);
- lcd.addr.x++;
- }
- processed = 1;
- break;
- case 'L': /* shift display left */
- lcd_write_cmd(LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT);
- processed = 1;
- break;
- case 'R': /* shift display right */
- lcd_write_cmd(LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT |
- LCD_CMD_SHIFT_RIGHT);
- processed = 1;
- break;
- case 'k': { /* kill end of line */
- int x;
-
- for (x = lcd.addr.x; x < lcd.bwidth; x++)
- lcd_write_data(' ');
-
- /* restore cursor position */
- lcd_gotoxy();
- processed = 1;
- break;
- }
- case 'I': /* reinitialize display */
- lcd_init_display();
- processed = 1;
- break;
- case 'G': {
- /* Generator : LGcxxxxx...xx; must have <c> between '0'
- * and '7', representing the numerical ASCII code of the
- * redefined character, and <xx...xx> a sequence of 16
- * hex digits representing 8 bytes for each character.
- * Most LCDs will only use 5 lower bits of the 7 first
- * bytes.
- */
-
- unsigned char cgbytes[8];
- unsigned char cgaddr;
- int cgoffset;
- int shift;
- char value;
- int addr;
-
- if (!strchr(esc, ';'))
- break;
-
- esc++;
-
- cgaddr = *(esc++) - '0';
- if (cgaddr > 7) {
- processed = 1;
- break;
- }
-
- cgoffset = 0;
- shift = 0;
- value = 0;
- while (*esc && cgoffset < 8) {
- shift ^= 4;
- if (*esc >= '0' && *esc <= '9') {
- value |= (*esc - '0') << shift;
- } else if (*esc >= 'A' && *esc <= 'Z') {
- value |= (*esc - 'A' + 10) << shift;
- } else if (*esc >= 'a' && *esc <= 'z') {
- value |= (*esc - 'a' + 10) << shift;
- } else {
- esc++;
- continue;
- }
-
- if (shift == 0) {
- cgbytes[cgoffset++] = value;
- value = 0;
- }
-
- esc++;
- }
-
- lcd_write_cmd(LCD_CMD_SET_CGRAM_ADDR | (cgaddr * 8));
- for (addr = 0; addr < cgoffset; addr++)
- lcd_write_data(cgbytes[addr]);
-
- /* ensures that we stop writing to CGRAM */
- lcd_gotoxy();
- processed = 1;
- break;
- }
- case 'x': /* gotoxy : LxXXX[yYYY]; */
- case 'y': /* gotoxy : LyYYY[xXXX]; */
- if (!strchr(esc, ';'))
- break;
-
- while (*esc) {
- if (*esc == 'x') {
- esc++;
- if (kstrtoul(esc, 10, &lcd.addr.x) < 0)
- break;
- } else if (*esc == 'y') {
- esc++;
- if (kstrtoul(esc, 10, &lcd.addr.y) < 0)
- break;
- } else {
- break;
- }
- }
-
- lcd_gotoxy();
- processed = 1;
- break;
- }
-
- /* TODO: This indent party here got ugly, clean it! */
- /* Check whether one flag was changed */
- if (oldflags != lcd.flags) {
- /* check whether one of B,C,D flags were changed */
- if ((oldflags ^ lcd.flags) &
- (LCD_FLAG_B | LCD_FLAG_C | LCD_FLAG_D))
- /* set display mode */
- lcd_write_cmd(LCD_CMD_DISPLAY_CTRL
- | ((lcd.flags & LCD_FLAG_D)
- ? LCD_CMD_DISPLAY_ON : 0)
- | ((lcd.flags & LCD_FLAG_C)
- ? LCD_CMD_CURSOR_ON : 0)
- | ((lcd.flags & LCD_FLAG_B)
- ? LCD_CMD_BLINK_ON : 0));
- /* check whether one of F,N flags was changed */
- else if ((oldflags ^ lcd.flags) & (LCD_FLAG_F | LCD_FLAG_N))
- lcd_write_cmd(LCD_CMD_FUNCTION_SET
- | LCD_CMD_DATA_LEN_8BITS
- | ((lcd.flags & LCD_FLAG_F)
- ? LCD_CMD_FONT_5X10_DOTS
- : 0)
- | ((lcd.flags & LCD_FLAG_N)
- ? LCD_CMD_TWO_LINES
- : 0));
- /* check whether L flag was changed */
- else if ((oldflags ^ lcd.flags) & (LCD_FLAG_L))
- lcd_backlight(!!(lcd.flags & LCD_FLAG_L));
- }
-
- return processed;
-}
-
-static void lcd_write_char(char c)
-{
- /* first, we'll test if we're in escape mode */
- if ((c != '\n') && lcd.esc_seq.len >= 0) {
- /* yes, let's add this char to the buffer */
- lcd.esc_seq.buf[lcd.esc_seq.len++] = c;
- lcd.esc_seq.buf[lcd.esc_seq.len] = 0;
- } else {
- /* aborts any previous escape sequence */
- lcd.esc_seq.len = -1;
-
- switch (c) {
- case LCD_ESCAPE_CHAR:
- /* start of an escape sequence */
- lcd.esc_seq.len = 0;
- lcd.esc_seq.buf[lcd.esc_seq.len] = 0;
- break;
- case '\b':
- /* go back one char and clear it */
- if (lcd.addr.x > 0) {
- /*
- * check if we're not at the
- * end of the line
- */
- if (lcd.addr.x < lcd.bwidth)
- /* back one char */
- lcd_write_cmd(LCD_CMD_SHIFT);
- lcd.addr.x--;
- }
- /* replace with a space */
- lcd_write_data(' ');
- /* back one char again */
- lcd_write_cmd(LCD_CMD_SHIFT);
- break;
- case '\014':
- /* quickly clear the display */
- lcd_clear_fast();
- break;
- case '\n':
- /*
- * flush the remainder of the current line and
- * go to the beginning of the next line
- */
- for (; lcd.addr.x < lcd.bwidth; lcd.addr.x++)
- lcd_write_data(' ');
- lcd.addr.x = 0;
- lcd.addr.y = (lcd.addr.y + 1) % lcd.height;
- lcd_gotoxy();
- break;
- case '\r':
- /* go to the beginning of the same line */
- lcd.addr.x = 0;
- lcd_gotoxy();
- break;
- case '\t':
- /* print a space instead of the tab */
- lcd_print(' ');
- break;
- default:
- /* simply print this char */
- lcd_print(c);
- break;
- }
- }
-
- /*
- * now we'll see if we're in an escape mode and if the current
- * escape sequence can be understood.
- */
- if (lcd.esc_seq.len >= 2) {
- int processed = 0;
-
- if (!strcmp(lcd.esc_seq.buf, "[2J")) {
- /* clear the display */
- lcd_clear_fast();
- processed = 1;
- } else if (!strcmp(lcd.esc_seq.buf, "[H")) {
- /* cursor to home */
- lcd_home();
- processed = 1;
- }
- /* codes starting with ^[[L */
- else if ((lcd.esc_seq.len >= 3) &&
- (lcd.esc_seq.buf[0] == '[') &&
- (lcd.esc_seq.buf[1] == 'L')) {
- processed = handle_lcd_special_code();
- }
-
- /* LCD special escape codes */
- /*
- * flush the escape sequence if it's been processed
- * or if it is getting too long.
- */
- if (processed || (lcd.esc_seq.len >= LCD_ESCAPE_LEN))
- lcd.esc_seq.len = -1;
- } /* escape codes */
-}
-
-static ssize_t lcd_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos)
-{
- const char __user *tmp = buf;
- char c;
-
- for (; count-- > 0; (*ppos)++, tmp++) {
- if (!in_interrupt() && (((count + 1) & 0x1f) == 0))
- /*
- * let's be a little nice with other processes
- * that need some CPU
- */
- schedule();
-
- if (get_user(c, tmp))
- return -EFAULT;
-
- lcd_write_char(c);
- }
-
- return tmp - buf;
-}
-
-static int lcd_open(struct inode *inode, struct file *file)
-{
- if (!atomic_dec_and_test(&lcd_available))
- return -EBUSY; /* open only once at a time */
-
- if (file->f_mode & FMODE_READ) /* device is write-only */
- return -EPERM;
-
- if (lcd.must_clear) {
- lcd_clear_display();
- lcd.must_clear = false;
- }
- return nonseekable_open(inode, file);
-}
-
-static int lcd_release(struct inode *inode, struct file *file)
-{
- atomic_inc(&lcd_available);
- return 0;
-}
-
-static const struct file_operations lcd_fops = {
- .write = lcd_write,
- .open = lcd_open,
- .release = lcd_release,
- .llseek = no_llseek,
-};
-
-static struct miscdevice lcd_dev = {
- .minor = LCD_MINOR,
- .name = "lcd",
- .fops = &lcd_fops,
-};
-
-/* public function usable from the kernel for any purpose */
-static void panel_lcd_print(const char *s)
-{
- const char *tmp = s;
- int count = strlen(s);
-
- if (lcd.enabled && lcd.initialized) {
- for (; count-- > 0; tmp++) {
- if (!in_interrupt() && (((count + 1) & 0x1f) == 0))
- /*
- * let's be a little nice with other processes
- * that need some CPU
- */
- schedule();
-
- lcd_write_char(*tmp);
- }
- }
-}
-
-/* initialize the LCD driver */
-static void lcd_init(void)
-{
- switch (selected_lcd_type) {
- case LCD_TYPE_OLD:
- /* parallel mode, 8 bits */
- lcd.proto = LCD_PROTO_PARALLEL;
- lcd.charset = LCD_CHARSET_NORMAL;
- lcd.pins.e = PIN_STROBE;
- lcd.pins.rs = PIN_AUTOLF;
-
- lcd.width = 40;
- lcd.bwidth = 40;
- lcd.hwidth = 64;
- lcd.height = 2;
- break;
- case LCD_TYPE_KS0074:
- /* serial mode, ks0074 */
- lcd.proto = LCD_PROTO_SERIAL;
- lcd.charset = LCD_CHARSET_KS0074;
- lcd.pins.bl = PIN_AUTOLF;
- lcd.pins.cl = PIN_STROBE;
- lcd.pins.da = PIN_D0;
-
- lcd.width = 16;
- lcd.bwidth = 40;
- lcd.hwidth = 16;
- lcd.height = 2;
- break;
- case LCD_TYPE_NEXCOM:
- /* parallel mode, 8 bits, generic */
- lcd.proto = LCD_PROTO_PARALLEL;
- lcd.charset = LCD_CHARSET_NORMAL;
- lcd.pins.e = PIN_AUTOLF;
- lcd.pins.rs = PIN_SELECP;
- lcd.pins.rw = PIN_INITP;
-
- lcd.width = 16;
- lcd.bwidth = 40;
- lcd.hwidth = 64;
- lcd.height = 2;
- break;
- case LCD_TYPE_CUSTOM:
- /* customer-defined */
- lcd.proto = DEFAULT_LCD_PROTO;
- lcd.charset = DEFAULT_LCD_CHARSET;
- /* default geometry will be set later */
- break;
- case LCD_TYPE_HANTRONIX:
- /* parallel mode, 8 bits, hantronix-like */
- default:
- lcd.proto = LCD_PROTO_PARALLEL;
- lcd.charset = LCD_CHARSET_NORMAL;
- lcd.pins.e = PIN_STROBE;
- lcd.pins.rs = PIN_SELECP;
-
- lcd.width = 16;
- lcd.bwidth = 40;
- lcd.hwidth = 64;
- lcd.height = 2;
- break;
- }
-
- /* Overwrite with module params set on loading */
- if (lcd_height != NOT_SET)
- lcd.height = lcd_height;
- if (lcd_width != NOT_SET)
- lcd.width = lcd_width;
- if (lcd_bwidth != NOT_SET)
- lcd.bwidth = lcd_bwidth;
- if (lcd_hwidth != NOT_SET)
- lcd.hwidth = lcd_hwidth;
- if (lcd_charset != NOT_SET)
- lcd.charset = lcd_charset;
- if (lcd_proto != NOT_SET)
- lcd.proto = lcd_proto;
- if (lcd_e_pin != PIN_NOT_SET)
- lcd.pins.e = lcd_e_pin;
- if (lcd_rs_pin != PIN_NOT_SET)
- lcd.pins.rs = lcd_rs_pin;
- if (lcd_rw_pin != PIN_NOT_SET)
- lcd.pins.rw = lcd_rw_pin;
- if (lcd_cl_pin != PIN_NOT_SET)
- lcd.pins.cl = lcd_cl_pin;
- if (lcd_da_pin != PIN_NOT_SET)
- lcd.pins.da = lcd_da_pin;
- if (lcd_bl_pin != PIN_NOT_SET)
- lcd.pins.bl = lcd_bl_pin;
-
- /* this is used to catch wrong and default values */
- if (lcd.width <= 0)
- lcd.width = DEFAULT_LCD_WIDTH;
- if (lcd.bwidth <= 0)
- lcd.bwidth = DEFAULT_LCD_BWIDTH;
- if (lcd.hwidth <= 0)
- lcd.hwidth = DEFAULT_LCD_HWIDTH;
- if (lcd.height <= 0)
- lcd.height = DEFAULT_LCD_HEIGHT;
-
- if (lcd.proto == LCD_PROTO_SERIAL) { /* SERIAL */
- lcd_write_cmd = lcd_write_cmd_s;
- lcd_write_data = lcd_write_data_s;
- lcd_clear_fast = lcd_clear_fast_s;
-
- if (lcd.pins.cl == PIN_NOT_SET)
- lcd.pins.cl = DEFAULT_LCD_PIN_SCL;
- if (lcd.pins.da == PIN_NOT_SET)
- lcd.pins.da = DEFAULT_LCD_PIN_SDA;
-
- } else if (lcd.proto == LCD_PROTO_PARALLEL) { /* PARALLEL */
- lcd_write_cmd = lcd_write_cmd_p8;
- lcd_write_data = lcd_write_data_p8;
- lcd_clear_fast = lcd_clear_fast_p8;
-
- if (lcd.pins.e == PIN_NOT_SET)
- lcd.pins.e = DEFAULT_LCD_PIN_E;
- if (lcd.pins.rs == PIN_NOT_SET)
- lcd.pins.rs = DEFAULT_LCD_PIN_RS;
- if (lcd.pins.rw == PIN_NOT_SET)
- lcd.pins.rw = DEFAULT_LCD_PIN_RW;
- } else {
- lcd_write_cmd = lcd_write_cmd_tilcd;
- lcd_write_data = lcd_write_data_tilcd;
- lcd_clear_fast = lcd_clear_fast_tilcd;
- }
-
- if (lcd.pins.bl == PIN_NOT_SET)
- lcd.pins.bl = DEFAULT_LCD_PIN_BL;
-
- if (lcd.pins.e == PIN_NOT_SET)
- lcd.pins.e = PIN_NONE;
- if (lcd.pins.rs == PIN_NOT_SET)
- lcd.pins.rs = PIN_NONE;
- if (lcd.pins.rw == PIN_NOT_SET)
- lcd.pins.rw = PIN_NONE;
- if (lcd.pins.bl == PIN_NOT_SET)
- lcd.pins.bl = PIN_NONE;
- if (lcd.pins.cl == PIN_NOT_SET)
- lcd.pins.cl = PIN_NONE;
- if (lcd.pins.da == PIN_NOT_SET)
- lcd.pins.da = PIN_NONE;
-
- if (lcd.charset == NOT_SET)
- lcd.charset = DEFAULT_LCD_CHARSET;
-
- if (lcd.charset == LCD_CHARSET_KS0074)
- lcd_char_conv = lcd_char_conv_ks0074;
- else
- lcd_char_conv = NULL;
-
- if (lcd.pins.bl != PIN_NONE) {
- mutex_init(&lcd.bl_tempo_lock);
- INIT_DELAYED_WORK(&lcd.bl_work, lcd_bl_off);
- }
-
- pin_to_bits(lcd.pins.e, lcd_bits[LCD_PORT_D][LCD_BIT_E],
- lcd_bits[LCD_PORT_C][LCD_BIT_E]);
- pin_to_bits(lcd.pins.rs, lcd_bits[LCD_PORT_D][LCD_BIT_RS],
- lcd_bits[LCD_PORT_C][LCD_BIT_RS]);
- pin_to_bits(lcd.pins.rw, lcd_bits[LCD_PORT_D][LCD_BIT_RW],
- lcd_bits[LCD_PORT_C][LCD_BIT_RW]);
- pin_to_bits(lcd.pins.bl, lcd_bits[LCD_PORT_D][LCD_BIT_BL],
- lcd_bits[LCD_PORT_C][LCD_BIT_BL]);
- pin_to_bits(lcd.pins.cl, lcd_bits[LCD_PORT_D][LCD_BIT_CL],
- lcd_bits[LCD_PORT_C][LCD_BIT_CL]);
- pin_to_bits(lcd.pins.da, lcd_bits[LCD_PORT_D][LCD_BIT_DA],
- lcd_bits[LCD_PORT_C][LCD_BIT_DA]);
-
- /*
- * before this line, we must NOT send anything to the display.
- * Since lcd_init_display() needs to write data, we have to
- * enable mark the LCD initialized just before.
- */
- lcd.initialized = true;
- lcd_init_display();
-
- /* display a short message */
-#ifdef CONFIG_PANEL_CHANGE_MESSAGE
-#ifdef CONFIG_PANEL_BOOT_MESSAGE
- panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE);
-#endif
-#else
- panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE);
-#endif
- /* clear the display on the next device opening */
- lcd.must_clear = true;
- lcd_home();
-}
-
-/*
- * These are the file operation function for user access to /dev/keypad
- */
-
-static ssize_t keypad_read(struct file *file,
- char __user *buf, size_t count, loff_t *ppos)
-{
- unsigned i = *ppos;
- char __user *tmp = buf;
-
- if (keypad_buflen == 0) {
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
-
- if (wait_event_interruptible(keypad_read_wait,
- keypad_buflen != 0))
- return -EINTR;
- }
-
- for (; count-- > 0 && (keypad_buflen > 0);
- ++i, ++tmp, --keypad_buflen) {
- put_user(keypad_buffer[keypad_start], tmp);
- keypad_start = (keypad_start + 1) % KEYPAD_BUFFER;
- }
- *ppos = i;
-
- return tmp - buf;
-}
-
-static int keypad_open(struct inode *inode, struct file *file)
-{
- if (!atomic_dec_and_test(&keypad_available))
- return -EBUSY; /* open only once at a time */
-
- if (file->f_mode & FMODE_WRITE) /* device is read-only */
- return -EPERM;
-
- keypad_buflen = 0; /* flush the buffer on opening */
- return 0;
-}
-
-static int keypad_release(struct inode *inode, struct file *file)
-{
- atomic_inc(&keypad_available);
- return 0;
-}
-
-static const struct file_operations keypad_fops = {
- .read = keypad_read, /* read */
- .open = keypad_open, /* open */
- .release = keypad_release, /* close */
- .llseek = default_llseek,
-};
-
-static struct miscdevice keypad_dev = {
- .minor = KEYPAD_MINOR,
- .name = "keypad",
- .fops = &keypad_fops,
-};
-
-static void keypad_send_key(const char *string, int max_len)
-{
- /* send the key to the device only if a process is attached to it. */
- if (!atomic_read(&keypad_available)) {
- while (max_len-- && keypad_buflen < KEYPAD_BUFFER && *string) {
- keypad_buffer[(keypad_start + keypad_buflen++) %
- KEYPAD_BUFFER] = *string++;
- }
- wake_up_interruptible(&keypad_read_wait);
- }
-}
-
-/* this function scans all the bits involving at least one logical signal,
- * and puts the results in the bitfield "phys_read" (one bit per established
- * contact), and sets "phys_read_prev" to "phys_read".
- *
- * Note: to debounce input signals, we will only consider as switched a signal
- * which is stable across 2 measures. Signals which are different between two
- * reads will be kept as they previously were in their logical form (phys_prev).
- * A signal which has just switched will have a 1 in
- * (phys_read ^ phys_read_prev).
- */
-static void phys_scan_contacts(void)
-{
- int bit, bitval;
- char oldval;
- char bitmask;
- char gndmask;
-
- phys_prev = phys_curr;
- phys_read_prev = phys_read;
- phys_read = 0; /* flush all signals */
-
- /* keep track of old value, with all outputs disabled */
- oldval = r_dtr(pprt) | scan_mask_o;
- /* activate all keyboard outputs (active low) */
- w_dtr(pprt, oldval & ~scan_mask_o);
-
- /* will have a 1 for each bit set to gnd */
- bitmask = PNL_PINPUT(r_str(pprt)) & scan_mask_i;
- /* disable all matrix signals */
- w_dtr(pprt, oldval);
-
- /* now that all outputs are cleared, the only active input bits are
- * directly connected to the ground
- */
-
- /* 1 for each grounded input */
- gndmask = PNL_PINPUT(r_str(pprt)) & scan_mask_i;
-
- /* grounded inputs are signals 40-44 */
- phys_read |= (__u64)gndmask << 40;
-
- if (bitmask != gndmask) {
- /*
- * since clearing the outputs changed some inputs, we know
- * that some input signals are currently tied to some outputs.
- * So we'll scan them.
- */
- for (bit = 0; bit < 8; bit++) {
- bitval = BIT(bit);
-
- if (!(scan_mask_o & bitval)) /* skip unused bits */
- continue;
-
- w_dtr(pprt, oldval & ~bitval); /* enable this output */
- bitmask = PNL_PINPUT(r_str(pprt)) & ~gndmask;
- phys_read |= (__u64)bitmask << (5 * bit);
- }
- w_dtr(pprt, oldval); /* disable all outputs */
- }
- /*
- * this is easy: use old bits when they are flapping,
- * use new ones when stable
- */
- phys_curr = (phys_prev & (phys_read ^ phys_read_prev)) |
- (phys_read & ~(phys_read ^ phys_read_prev));
-}
-
-static inline int input_state_high(struct logical_input *input)
-{
-#if 0
- /* FIXME:
- * this is an invalid test. It tries to catch
- * transitions from single-key to multiple-key, but
- * doesn't take into account the contacts polarity.
- * The only solution to the problem is to parse keys
- * from the most complex to the simplest combinations,
- * and mark them as 'caught' once a combination
- * matches, then unmatch it for all other ones.
- */
-
- /* try to catch dangerous transitions cases :
- * someone adds a bit, so this signal was a false
- * positive resulting from a transition. We should
- * invalidate the signal immediately and not call the
- * release function.
- * eg: 0 -(press A)-> A -(press B)-> AB : don't match A's release.
- */
- if (((phys_prev & input->mask) == input->value) &&
- ((phys_curr & input->mask) > input->value)) {
- input->state = INPUT_ST_LOW; /* invalidate */
- return 1;
- }
-#endif
-
- if ((phys_curr & input->mask) == input->value) {
- if ((input->type == INPUT_TYPE_STD) &&
- (input->high_timer == 0)) {
- input->high_timer++;
- if (input->u.std.press_fct)
- input->u.std.press_fct(input->u.std.press_data);
- } else if (input->type == INPUT_TYPE_KBD) {
- /* will turn on the light */
- keypressed = 1;
-
- if (input->high_timer == 0) {
- char *press_str = input->u.kbd.press_str;
-
- if (press_str[0]) {
- int s = sizeof(input->u.kbd.press_str);
-
- keypad_send_key(press_str, s);
- }
- }
-
- if (input->u.kbd.repeat_str[0]) {
- char *repeat_str = input->u.kbd.repeat_str;
-
- if (input->high_timer >= KEYPAD_REP_START) {
- int s = sizeof(input->u.kbd.repeat_str);
-
- input->high_timer -= KEYPAD_REP_DELAY;
- keypad_send_key(repeat_str, s);
- }
- /* we will need to come back here soon */
- inputs_stable = 0;
- }
-
- if (input->high_timer < 255)
- input->high_timer++;
- }
- return 1;
- }
-
- /* else signal falling down. Let's fall through. */
- input->state = INPUT_ST_FALLING;
- input->fall_timer = 0;
-
- return 0;
-}
-
-static inline void input_state_falling(struct logical_input *input)
-{
-#if 0
- /* FIXME !!! same comment as in input_state_high */
- if (((phys_prev & input->mask) == input->value) &&
- ((phys_curr & input->mask) > input->value)) {
- input->state = INPUT_ST_LOW; /* invalidate */
- return;
- }
-#endif
-
- if ((phys_curr & input->mask) == input->value) {
- if (input->type == INPUT_TYPE_KBD) {
- /* will turn on the light */
- keypressed = 1;
-
- if (input->u.kbd.repeat_str[0]) {
- char *repeat_str = input->u.kbd.repeat_str;
-
- if (input->high_timer >= KEYPAD_REP_START) {
- int s = sizeof(input->u.kbd.repeat_str);
-
- input->high_timer -= KEYPAD_REP_DELAY;
- keypad_send_key(repeat_str, s);
- }
- /* we will need to come back here soon */
- inputs_stable = 0;
- }
-
- if (input->high_timer < 255)
- input->high_timer++;
- }
- input->state = INPUT_ST_HIGH;
- } else if (input->fall_timer >= input->fall_time) {
- /* call release event */
- if (input->type == INPUT_TYPE_STD) {
- void (*release_fct)(int) = input->u.std.release_fct;
-
- if (release_fct)
- release_fct(input->u.std.release_data);
- } else if (input->type == INPUT_TYPE_KBD) {
- char *release_str = input->u.kbd.release_str;
-
- if (release_str[0]) {
- int s = sizeof(input->u.kbd.release_str);
-
- keypad_send_key(release_str, s);
- }
- }
-
- input->state = INPUT_ST_LOW;
- } else {
- input->fall_timer++;
- inputs_stable = 0;
- }
-}
-
-static void panel_process_inputs(void)
-{
- struct list_head *item;
- struct logical_input *input;
-
- keypressed = 0;
- inputs_stable = 1;
- list_for_each(item, &logical_inputs) {
- input = list_entry(item, struct logical_input, list);
-
- switch (input->state) {
- case INPUT_ST_LOW:
- if ((phys_curr & input->mask) != input->value)
- break;
- /* if all needed ones were already set previously,
- * this means that this logical signal has been
- * activated by the releasing of another combined
- * signal, so we don't want to match.
- * eg: AB -(release B)-> A -(release A)-> 0 :
- * don't match A.
- */
- if ((phys_prev & input->mask) == input->value)
- break;
- input->rise_timer = 0;
- input->state = INPUT_ST_RISING;
- /* no break here, fall through */
- case INPUT_ST_RISING:
- if ((phys_curr & input->mask) != input->value) {
- input->state = INPUT_ST_LOW;
- break;
- }
- if (input->rise_timer < input->rise_time) {
- inputs_stable = 0;
- input->rise_timer++;
- break;
- }
- input->high_timer = 0;
- input->state = INPUT_ST_HIGH;
- /* no break here, fall through */
- case INPUT_ST_HIGH:
- if (input_state_high(input))
- break;
- /* no break here, fall through */
- case INPUT_ST_FALLING:
- input_state_falling(input);
- }
- }
-}
-
-static void panel_scan_timer(void)
-{
- if (keypad.enabled && keypad_initialized) {
- if (spin_trylock_irq(&pprt_lock)) {
- phys_scan_contacts();
-
- /* no need for the parport anymore */
- spin_unlock_irq(&pprt_lock);
- }
-
- if (!inputs_stable || phys_curr != phys_prev)
- panel_process_inputs();
- }
-
- if (keypressed && lcd.enabled && lcd.initialized)
- lcd_poke();
-
- mod_timer(&scan_timer, jiffies + INPUT_POLL_TIME);
-}
-
-static void init_scan_timer(void)
-{
- if (scan_timer.function)
- return; /* already started */
-
- setup_timer(&scan_timer, (void *)&panel_scan_timer, 0);
- scan_timer.expires = jiffies + INPUT_POLL_TIME;
- add_timer(&scan_timer);
-}
-
-/* converts a name of the form "({BbAaPpSsEe}{01234567-})*" to a series of bits.
- * if <omask> or <imask> are non-null, they will be or'ed with the bits
- * corresponding to out and in bits respectively.
- * returns 1 if ok, 0 if error (in which case, nothing is written).
- */
-static u8 input_name2mask(const char *name, __u64 *mask, __u64 *value,
- u8 *imask, u8 *omask)
-{
- const char sigtab[] = "EeSsPpAaBb";
- u8 im, om;
- __u64 m, v;
-
- om = 0;
- im = 0;
- m = 0ULL;
- v = 0ULL;
- while (*name) {
- int in, out, bit, neg;
- const char *idx;
-
- idx = strchr(sigtab, *name);
- if (!idx)
- return 0; /* input name not found */
-
- in = idx - sigtab;
- neg = (in & 1); /* odd (lower) names are negated */
- in >>= 1;
- im |= BIT(in);
-
- name++;
- if (*name >= '0' && *name <= '7') {
- out = *name - '0';
- om |= BIT(out);
- } else if (*name == '-') {
- out = 8;
- } else {
- return 0; /* unknown bit name */
- }
-
- bit = (out * 5) + in;
-
- m |= 1ULL << bit;
- if (!neg)
- v |= 1ULL << bit;
- name++;
- }
- *mask = m;
- *value = v;
- if (imask)
- *imask |= im;
- if (omask)
- *omask |= om;
- return 1;
-}
-
-/* tries to bind a key to the signal name <name>. The key will send the
- * strings <press>, <repeat>, <release> for these respective events.
- * Returns the pointer to the new key if ok, NULL if the key could not be bound.
- */
-static struct logical_input *panel_bind_key(const char *name, const char *press,
- const char *repeat,
- const char *release)
-{
- struct logical_input *key;
-
- key = kzalloc(sizeof(*key), GFP_KERNEL);
- if (!key)
- return NULL;
-
- if (!input_name2mask(name, &key->mask, &key->value, &scan_mask_i,
- &scan_mask_o)) {
- kfree(key);
- return NULL;
- }
-
- key->type = INPUT_TYPE_KBD;
- key->state = INPUT_ST_LOW;
- key->rise_time = 1;
- key->fall_time = 1;
-
- strncpy(key->u.kbd.press_str, press, sizeof(key->u.kbd.press_str));
- strncpy(key->u.kbd.repeat_str, repeat, sizeof(key->u.kbd.repeat_str));
- strncpy(key->u.kbd.release_str, release,
- sizeof(key->u.kbd.release_str));
- list_add(&key->list, &logical_inputs);
- return key;
-}
-
-#if 0
-/* tries to bind a callback function to the signal name <name>. The function
- * <press_fct> will be called with the <press_data> arg when the signal is
- * activated, and so on for <release_fct>/<release_data>
- * Returns the pointer to the new signal if ok, NULL if the signal could not
- * be bound.
- */
-static struct logical_input *panel_bind_callback(char *name,
- void (*press_fct)(int),
- int press_data,
- void (*release_fct)(int),
- int release_data)
-{
- struct logical_input *callback;
-
- callback = kmalloc(sizeof(*callback), GFP_KERNEL);
- if (!callback)
- return NULL;
-
- memset(callback, 0, sizeof(struct logical_input));
- if (!input_name2mask(name, &callback->mask, &callback->value,
- &scan_mask_i, &scan_mask_o))
- return NULL;
-
- callback->type = INPUT_TYPE_STD;
- callback->state = INPUT_ST_LOW;
- callback->rise_time = 1;
- callback->fall_time = 1;
- callback->u.std.press_fct = press_fct;
- callback->u.std.press_data = press_data;
- callback->u.std.release_fct = release_fct;
- callback->u.std.release_data = release_data;
- list_add(&callback->list, &logical_inputs);
- return callback;
-}
-#endif
-
-static void keypad_init(void)
-{
- int keynum;
-
- init_waitqueue_head(&keypad_read_wait);
- keypad_buflen = 0; /* flushes any eventual noisy keystroke */
-
- /* Let's create all known keys */
-
- for (keynum = 0; keypad_profile[keynum][0][0]; keynum++) {
- panel_bind_key(keypad_profile[keynum][0],
- keypad_profile[keynum][1],
- keypad_profile[keynum][2],
- keypad_profile[keynum][3]);
- }
-
- init_scan_timer();
- keypad_initialized = 1;
-}
-
-/**************************************************/
-/* device initialization */
-/**************************************************/
-
-static int panel_notify_sys(struct notifier_block *this, unsigned long code,
- void *unused)
-{
- if (lcd.enabled && lcd.initialized) {
- switch (code) {
- case SYS_DOWN:
- panel_lcd_print
- ("\x0cReloading\nSystem...\x1b[Lc\x1b[Lb\x1b[L+");
- break;
- case SYS_HALT:
- panel_lcd_print
- ("\x0cSystem Halted.\x1b[Lc\x1b[Lb\x1b[L+");
- break;
- case SYS_POWER_OFF:
- panel_lcd_print("\x0cPower off.\x1b[Lc\x1b[Lb\x1b[L+");
- break;
- default:
- break;
- }
- }
- return NOTIFY_DONE;
-}
-
-static struct notifier_block panel_notifier = {
- panel_notify_sys,
- NULL,
- 0
-};
-
-static void panel_attach(struct parport *port)
-{
- struct pardev_cb panel_cb;
-
- if (port->number != parport)
- return;
-
- if (pprt) {
- pr_err("%s: port->number=%d parport=%d, already registered!\n",
- __func__, port->number, parport);
- return;
- }
-
- memset(&panel_cb, 0, sizeof(panel_cb));
- panel_cb.private = &pprt;
- /* panel_cb.flags = 0 should be PARPORT_DEV_EXCL? */
-
- pprt = parport_register_dev_model(port, "panel", &panel_cb, 0);
- if (!pprt) {
- pr_err("%s: port->number=%d parport=%d, parport_register_device() failed\n",
- __func__, port->number, parport);
- return;
- }
-
- if (parport_claim(pprt)) {
- pr_err("could not claim access to parport%d. Aborting.\n",
- parport);
- goto err_unreg_device;
- }
-
- /* must init LCD first, just in case an IRQ from the keypad is
- * generated at keypad init
- */
- if (lcd.enabled) {
- lcd_init();
- if (misc_register(&lcd_dev))
- goto err_unreg_device;
- }
-
- if (keypad.enabled) {
- keypad_init();
- if (misc_register(&keypad_dev))
- goto err_lcd_unreg;
- }
- register_reboot_notifier(&panel_notifier);
- return;
-
-err_lcd_unreg:
- if (lcd.enabled)
- misc_deregister(&lcd_dev);
-err_unreg_device:
- parport_unregister_device(pprt);
- pprt = NULL;
-}
-
-static void panel_detach(struct parport *port)
-{
- if (port->number != parport)
- return;
-
- if (!pprt) {
- pr_err("%s: port->number=%d parport=%d, nothing to unregister.\n",
- __func__, port->number, parport);
- return;
- }
- if (scan_timer.function)
- del_timer_sync(&scan_timer);
-
- if (keypad.enabled) {
- misc_deregister(&keypad_dev);
- keypad_initialized = 0;
- }
-
- if (lcd.enabled) {
- panel_lcd_print("\x0cLCD driver unloaded.\x1b[Lc\x1b[Lb\x1b[L-");
- misc_deregister(&lcd_dev);
- if (lcd.pins.bl != PIN_NONE) {
- cancel_delayed_work_sync(&lcd.bl_work);
- __lcd_backlight(0);
- }
- lcd.initialized = false;
- }
-
- /* TODO: free all input signals */
- parport_release(pprt);
- parport_unregister_device(pprt);
- pprt = NULL;
- unregister_reboot_notifier(&panel_notifier);
-}
-
-static struct parport_driver panel_driver = {
- .name = "panel",
- .match_port = panel_attach,
- .detach = panel_detach,
- .devmodel = true,
-};
-
-/* init function */
-static int __init panel_init_module(void)
-{
- int selected_keypad_type = NOT_SET, err;
-
- /* take care of an eventual profile */
- switch (profile) {
- case PANEL_PROFILE_CUSTOM:
- /* custom profile */
- selected_keypad_type = DEFAULT_KEYPAD_TYPE;
- selected_lcd_type = DEFAULT_LCD_TYPE;
- break;
- case PANEL_PROFILE_OLD:
- /* 8 bits, 2*16, old keypad */
- selected_keypad_type = KEYPAD_TYPE_OLD;
- selected_lcd_type = LCD_TYPE_OLD;
-
- /* TODO: This two are a little hacky, sort it out later */
- if (lcd_width == NOT_SET)
- lcd_width = 16;
- if (lcd_hwidth == NOT_SET)
- lcd_hwidth = 16;
- break;
- case PANEL_PROFILE_NEW:
- /* serial, 2*16, new keypad */
- selected_keypad_type = KEYPAD_TYPE_NEW;
- selected_lcd_type = LCD_TYPE_KS0074;
- break;
- case PANEL_PROFILE_HANTRONIX:
- /* 8 bits, 2*16 hantronix-like, no keypad */
- selected_keypad_type = KEYPAD_TYPE_NONE;
- selected_lcd_type = LCD_TYPE_HANTRONIX;
- break;
- case PANEL_PROFILE_NEXCOM:
- /* generic 8 bits, 2*16, nexcom keypad, eg. Nexcom. */
- selected_keypad_type = KEYPAD_TYPE_NEXCOM;
- selected_lcd_type = LCD_TYPE_NEXCOM;
- break;
- case PANEL_PROFILE_LARGE:
- /* 8 bits, 2*40, old keypad */
- selected_keypad_type = KEYPAD_TYPE_OLD;
- selected_lcd_type = LCD_TYPE_OLD;
- break;
- }
-
- /*
- * Overwrite selection with module param values (both keypad and lcd),
- * where the deprecated params have lower prio.
- */
- if (keypad_enabled != NOT_SET)
- selected_keypad_type = keypad_enabled;
- if (keypad_type != NOT_SET)
- selected_keypad_type = keypad_type;
-
- keypad.enabled = (selected_keypad_type > 0);
-
- if (lcd_enabled != NOT_SET)
- selected_lcd_type = lcd_enabled;
- if (lcd_type != NOT_SET)
- selected_lcd_type = lcd_type;
-
- lcd.enabled = (selected_lcd_type > 0);
-
- if (lcd.enabled) {
- /*
- * Init lcd struct with load-time values to preserve exact
- * current functionality (at least for now).
- */
- lcd.height = lcd_height;
- lcd.width = lcd_width;
- lcd.bwidth = lcd_bwidth;
- lcd.hwidth = lcd_hwidth;
- lcd.charset = lcd_charset;
- lcd.proto = lcd_proto;
- lcd.pins.e = lcd_e_pin;
- lcd.pins.rs = lcd_rs_pin;
- lcd.pins.rw = lcd_rw_pin;
- lcd.pins.cl = lcd_cl_pin;
- lcd.pins.da = lcd_da_pin;
- lcd.pins.bl = lcd_bl_pin;
-
- /* Leave it for now, just in case */
- lcd.esc_seq.len = -1;
- }
-
- switch (selected_keypad_type) {
- case KEYPAD_TYPE_OLD:
- keypad_profile = old_keypad_profile;
- break;
- case KEYPAD_TYPE_NEW:
- keypad_profile = new_keypad_profile;
- break;
- case KEYPAD_TYPE_NEXCOM:
- keypad_profile = nexcom_keypad_profile;
- break;
- default:
- keypad_profile = NULL;
- break;
- }
-
- if (!lcd.enabled && !keypad.enabled) {
- /* no device enabled, let's exit */
- pr_err("panel driver disabled.\n");
- return -ENODEV;
- }
-
- err = parport_register_driver(&panel_driver);
- if (err) {
- pr_err("could not register with parport. Aborting.\n");
- return err;
- }
-
- if (pprt)
- pr_info("panel driver registered on parport%d (io=0x%lx).\n",
- parport, pprt->port->base);
- else
- pr_info("panel driver not yet registered\n");
- return 0;
-}
-
-static void __exit panel_cleanup_module(void)
-{
- parport_unregister_driver(&panel_driver);
-}
-
-module_init(panel_init_module);
-module_exit(panel_cleanup_module);
-MODULE_AUTHOR("Willy Tarreau");
-MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-indent-level: 4
- * tab-width: 8
- * End:
- */
diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c
index 87a13374fdc0..adf46072cb37 100644
--- a/drivers/misc/tsl2550.c
+++ b/drivers/misc/tsl2550.c
@@ -443,9 +443,16 @@ static const struct i2c_device_id tsl2550_id[] = {
};
MODULE_DEVICE_TABLE(i2c, tsl2550_id);
+static const struct of_device_id tsl2550_of_match[] = {
+ { .compatible = "taos,tsl2550" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tsl2550_of_match);
+
static struct i2c_driver tsl2550_driver = {
.driver = {
.name = TSL2550_DRV_NAME,
+ .of_match_table = tsl2550_of_match,
.pm = TSL2550_PM_OPS,
},
.probe = tsl2550_probe,