diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-04 22:07:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-04 22:15:35 -0400 |
commit | af82455f7dbd9dc20244d80d033721b30d22c065 (patch) | |
tree | 3b9246456e82ae116b57834a2f0b4a307a016474 | |
parent | 0be75179df5e20306528800fc7c6a504b12b97db (diff) | |
parent | 2a76f89fa58c769241cfc21f2614705591519ae3 (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
...
166 files changed, 8064 insertions, 3259 deletions
diff --git a/Documentation/DocBook/rapidio.tmpl b/Documentation/DocBook/rapidio.tmpl index 50479360d845..ac3cca3399a1 100644 --- a/Documentation/DocBook/rapidio.tmpl +++ b/Documentation/DocBook/rapidio.tmpl | |||
@@ -129,9 +129,6 @@ | |||
129 | <sect1 id="Device_model_support"><title>Device model support</title> | 129 | <sect1 id="Device_model_support"><title>Device model support</title> |
130 | !Idrivers/rapidio/rio-driver.c | 130 | !Idrivers/rapidio/rio-driver.c |
131 | </sect1> | 131 | </sect1> |
132 | <sect1 id="Sysfs_support"><title>Sysfs support</title> | ||
133 | !Idrivers/rapidio/rio-sysfs.c | ||
134 | </sect1> | ||
135 | <sect1 id="PPC32_support"><title>PPC32 support</title> | 132 | <sect1 id="PPC32_support"><title>PPC32 support</title> |
136 | !Iarch/powerpc/sysdev/fsl_rio.c | 133 | !Iarch/powerpc/sysdev/fsl_rio.c |
137 | </sect1> | 134 | </sect1> |
diff --git a/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.txt b/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.txt new file mode 100644 index 000000000000..2aa24b889923 --- /dev/null +++ b/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.txt | |||
@@ -0,0 +1,45 @@ | |||
1 | DT bindings for the Hitachi HD44780 Character LCD Controller | ||
2 | |||
3 | The Hitachi HD44780 Character LCD Controller is commonly used on character LCDs | ||
4 | that can display one or more lines of text. It exposes an M6800 bus interface, | ||
5 | which can be used in either 4-bit or 8-bit mode. | ||
6 | |||
7 | Required properties: | ||
8 | - compatible: Must contain "hit,hd44780", | ||
9 | - data-gpios: Must contain an array of either 4 or 8 GPIO specifiers, | ||
10 | referring to the GPIO pins connected to the data signal lines DB0-DB7 | ||
11 | (8-bit mode) or DB4-DB7 (4-bit mode) of the LCD Controller's bus interface, | ||
12 | - enable-gpios: Must contain a GPIO specifier, referring to the GPIO pin | ||
13 | connected to the "E" (Enable) signal line of the LCD Controller's bus | ||
14 | interface, | ||
15 | - rs-gpios: Must contain a GPIO specifier, referring to the GPIO pin | ||
16 | connected to the "RS" (Register Select) signal line of the LCD Controller's | ||
17 | bus interface, | ||
18 | - display-height-chars: Height of the display, in character cells, | ||
19 | - display-width-chars: Width of the display, in character cells. | ||
20 | |||
21 | Optional properties: | ||
22 | - rw-gpios: Must contain a GPIO specifier, referring to the GPIO pin | ||
23 | connected to the "RW" (Read/Write) signal line of the LCD Controller's bus | ||
24 | interface, | ||
25 | - backlight-gpios: Must contain a GPIO specifier, referring to the GPIO pin | ||
26 | used for enabling the LCD's backlight, | ||
27 | - internal-buffer-width: Internal buffer width (default is 40 for displays | ||
28 | with 1 or 2 lines, and display-width-chars for displays with more than 2 | ||
29 | lines). | ||
30 | |||
31 | Example: | ||
32 | |||
33 | auxdisplay { | ||
34 | compatible = "hit,hd44780"; | ||
35 | |||
36 | data-gpios = <&hc595 0 GPIO_ACTIVE_HIGH>, | ||
37 | <&hc595 1 GPIO_ACTIVE_HIGH>, | ||
38 | <&hc595 2 GPIO_ACTIVE_HIGH>, | ||
39 | <&hc595 3 GPIO_ACTIVE_HIGH>; | ||
40 | enable-gpios = <&hc595 4 GPIO_ACTIVE_HIGH>; | ||
41 | rs-gpios = <&hc595 5 GPIO_ACTIVE_HIGH>; | ||
42 | |||
43 | display-height-chars = <2>; | ||
44 | display-width-chars = <16>; | ||
45 | }; | ||
diff --git a/Documentation/devicetree/bindings/firmware/coreboot.txt b/Documentation/devicetree/bindings/firmware/coreboot.txt new file mode 100644 index 000000000000..4c955703cea8 --- /dev/null +++ b/Documentation/devicetree/bindings/firmware/coreboot.txt | |||
@@ -0,0 +1,33 @@ | |||
1 | COREBOOT firmware information | ||
2 | |||
3 | The device tree node to communicate the location of coreboot's memory-resident | ||
4 | bookkeeping structures to the kernel. Since coreboot itself cannot boot a | ||
5 | device-tree-based kernel (yet), this node needs to be inserted by a | ||
6 | second-stage bootloader (a coreboot "payload"). | ||
7 | |||
8 | Required properties: | ||
9 | - compatible: Should be "coreboot" | ||
10 | - reg: Address and length of the following two memory regions, in order: | ||
11 | 1.) The coreboot table. This is a list of variable-sized descriptors | ||
12 | that contain various compile- and run-time generated firmware | ||
13 | parameters. It is identified by the magic string "LBIO" in its first | ||
14 | four bytes. | ||
15 | See coreboot's src/commonlib/include/commonlib/coreboot_tables.h for | ||
16 | details. | ||
17 | 2.) The CBMEM area. This is a downward-growing memory region used by | ||
18 | coreboot to dynamically allocate data structures that remain resident. | ||
19 | It may or may not include the coreboot table as one of its members. It | ||
20 | is identified by a root node descriptor with the magic number | ||
21 | 0xc0389481 that resides in the topmost 8 bytes of the area. | ||
22 | See coreboot's src/include/imd.h for details. | ||
23 | |||
24 | Example: | ||
25 | firmware { | ||
26 | ranges; | ||
27 | |||
28 | coreboot { | ||
29 | compatible = "coreboot"; | ||
30 | reg = <0xfdfea000 0x264>, | ||
31 | <0xfdfea000 0x16000>; | ||
32 | } | ||
33 | }; | ||
diff --git a/Documentation/devicetree/bindings/fpga/altera-pr-ip.txt b/Documentation/devicetree/bindings/fpga/altera-pr-ip.txt new file mode 100644 index 000000000000..52a294cf2730 --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/altera-pr-ip.txt | |||
@@ -0,0 +1,12 @@ | |||
1 | Altera Arria10 Partial Reconfiguration IP | ||
2 | |||
3 | Required properties: | ||
4 | - compatible : should contain "altr,a10-pr-ip" | ||
5 | - reg : base address and size for memory mapped io. | ||
6 | |||
7 | Example: | ||
8 | |||
9 | fpga_mgr: fpga-mgr@ff20c000 { | ||
10 | compatible = "altr,a10-pr-ip"; | ||
11 | reg = <0xff20c000 0x10>; | ||
12 | }; | ||
diff --git a/Documentation/devicetree/bindings/fpga/fpga-region.txt b/Documentation/devicetree/bindings/fpga/fpga-region.txt index 3b32ba15a717..81bf3adba24b 100644 --- a/Documentation/devicetree/bindings/fpga/fpga-region.txt +++ b/Documentation/devicetree/bindings/fpga/fpga-region.txt | |||
@@ -186,6 +186,7 @@ Optional properties: | |||
186 | otherwise full reconfiguration is done. | 186 | otherwise full reconfiguration is done. |
187 | - external-fpga-config : boolean, set if the FPGA has already been configured | 187 | - external-fpga-config : boolean, set if the FPGA has already been configured |
188 | prior to OS boot up. | 188 | prior to OS boot up. |
189 | - encrypted-fpga-config : boolean, set if the bitstream is encrypted | ||
189 | - region-unfreeze-timeout-us : The maximum time in microseconds to wait for | 190 | - region-unfreeze-timeout-us : The maximum time in microseconds to wait for |
190 | bridges to successfully become enabled after the region has been | 191 | bridges to successfully become enabled after the region has been |
191 | programmed. | 192 | programmed. |
diff --git a/Documentation/devicetree/bindings/fpga/lattice-ice40-fpga-mgr.txt b/Documentation/devicetree/bindings/fpga/lattice-ice40-fpga-mgr.txt new file mode 100644 index 000000000000..4dc412437b08 --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/lattice-ice40-fpga-mgr.txt | |||
@@ -0,0 +1,21 @@ | |||
1 | Lattice iCE40 FPGA Manager | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: Should contain "lattice,ice40-fpga-mgr" | ||
5 | - reg: SPI chip select | ||
6 | - spi-max-frequency: Maximum SPI frequency (>=1000000, <=25000000) | ||
7 | - cdone-gpios: GPIO input connected to CDONE pin | ||
8 | - reset-gpios: Active-low GPIO output connected to CRESET_B pin. Note | ||
9 | that unless the GPIO is held low during startup, the | ||
10 | FPGA will enter Master SPI mode and drive SCK with a | ||
11 | clock signal potentially jamming other devices on the | ||
12 | bus until the firmware is loaded. | ||
13 | |||
14 | Example: | ||
15 | fpga: fpga@0 { | ||
16 | compatible = "lattice,ice40-fpga-mgr"; | ||
17 | reg = <0>; | ||
18 | spi-max-frequency = <1000000>; | ||
19 | cdone-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>; | ||
20 | reset-gpios = <&gpio 22 GPIO_ACTIVE_LOW>; | ||
21 | }; | ||
diff --git a/Documentation/devicetree/bindings/fpga/xilinx-slave-serial.txt b/Documentation/devicetree/bindings/fpga/xilinx-slave-serial.txt new file mode 100644 index 000000000000..9766f7472f51 --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/xilinx-slave-serial.txt | |||
@@ -0,0 +1,44 @@ | |||
1 | Xilinx Slave Serial SPI FPGA Manager | ||
2 | |||
3 | Xilinx Spartan-6 FPGAs support a method of loading the bitstream over | ||
4 | what is referred to as "slave serial" interface. | ||
5 | The slave serial link is not technically SPI, and might require extra | ||
6 | circuits in order to play nicely with other SPI slaves on the same bus. | ||
7 | |||
8 | See https://www.xilinx.com/support/documentation/user_guides/ug380.pdf | ||
9 | |||
10 | Required properties: | ||
11 | - compatible: should contain "xlnx,fpga-slave-serial" | ||
12 | - reg: spi chip select of the FPGA | ||
13 | - prog_b-gpios: config pin (referred to as PROGRAM_B in the manual) | ||
14 | - done-gpios: config status pin (referred to as DONE in the manual) | ||
15 | |||
16 | Example for full FPGA configuration: | ||
17 | |||
18 | fpga-region0 { | ||
19 | compatible = "fpga-region"; | ||
20 | fpga-mgr = <&fpga_mgr_spi>; | ||
21 | #address-cells = <0x1>; | ||
22 | #size-cells = <0x1>; | ||
23 | }; | ||
24 | |||
25 | spi1: spi@10680 { | ||
26 | compatible = "marvell,armada-xp-spi", "marvell,orion-spi"; | ||
27 | pinctrl-0 = <&spi0_pins>; | ||
28 | pinctrl-names = "default"; | ||
29 | #address-cells = <1>; | ||
30 | #size-cells = <0>; | ||
31 | cell-index = <1>; | ||
32 | interrupts = <92>; | ||
33 | clocks = <&coreclk 0>; | ||
34 | status = "okay"; | ||
35 | |||
36 | fpga_mgr_spi: fpga-mgr@0 { | ||
37 | compatible = "xlnx,fpga-slave-serial"; | ||
38 | spi-max-frequency = <60000000>; | ||
39 | spi-cpha; | ||
40 | reg = <0>; | ||
41 | done-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>; | ||
42 | prog_b-gpios = <&gpio0 29 GPIO_ACTIVE_LOW>; | ||
43 | }; | ||
44 | }; | ||
diff --git a/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt index d543ed3f5363..ef06d061913c 100644 --- a/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt +++ b/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt | |||
@@ -1,7 +1,11 @@ | |||
1 | Allwinner sunxi-sid | 1 | Allwinner sunxi-sid |
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid" | 4 | - compatible: Should be one of the following: |
5 | "allwinner,sun4i-a10-sid" | ||
6 | "allwinner,sun7i-a20-sid" | ||
7 | "allwinner,sun8i-h3-sid" | ||
8 | |||
5 | - reg: Should contain registers location and length | 9 | - reg: Should contain registers location and length |
6 | 10 | ||
7 | = Data cells = | 11 | = Data cells = |
diff --git a/Documentation/devicetree/bindings/nvmem/imx-iim.txt b/Documentation/devicetree/bindings/nvmem/imx-iim.txt new file mode 100644 index 000000000000..1978c5bcd96d --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/imx-iim.txt | |||
@@ -0,0 +1,22 @@ | |||
1 | Freescale i.MX IC Identification Module (IIM) device tree bindings | ||
2 | |||
3 | This binding represents the IC Identification Module (IIM) found on | ||
4 | i.MX25, i.MX27, i.MX31, i.MX35, i.MX51 and i.MX53 SoCs. | ||
5 | |||
6 | Required properties: | ||
7 | - compatible: should be one of | ||
8 | "fsl,imx25-iim", "fsl,imx27-iim", | ||
9 | "fsl,imx31-iim", "fsl,imx35-iim", | ||
10 | "fsl,imx51-iim", "fsl,imx53-iim", | ||
11 | - reg: Should contain the register base and length. | ||
12 | - interrupts: Should contain the interrupt for the IIM | ||
13 | - clocks: Should contain a phandle pointing to the gated peripheral clock. | ||
14 | |||
15 | Example: | ||
16 | |||
17 | iim: iim@63f98000 { | ||
18 | compatible = "fsl,imx53-iim", "fsl,imx27-iim"; | ||
19 | reg = <0x63f98000 0x4000>; | ||
20 | interrupts = <69>; | ||
21 | clocks = <&clks IMX5_CLK_IIM_GATE>; | ||
22 | }; | ||
diff --git a/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt b/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt index 966a72ecc6bd..70d791b03ea1 100644 --- a/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt +++ b/Documentation/devicetree/bindings/nvmem/imx-ocotp.txt | |||
@@ -9,14 +9,19 @@ Required properties: | |||
9 | "fsl,imx6sl-ocotp" (i.MX6SL), or | 9 | "fsl,imx6sl-ocotp" (i.MX6SL), or |
10 | "fsl,imx6sx-ocotp" (i.MX6SX), | 10 | "fsl,imx6sx-ocotp" (i.MX6SX), |
11 | "fsl,imx6ul-ocotp" (i.MX6UL), | 11 | "fsl,imx6ul-ocotp" (i.MX6UL), |
12 | "fsl,imx7d-ocotp" (i.MX7D/S), | ||
12 | followed by "syscon". | 13 | followed by "syscon". |
13 | - reg: Should contain the register base and length. | 14 | - reg: Should contain the register base and length. |
14 | - clocks: Should contain a phandle pointing to the gated peripheral clock. | 15 | - clocks: Should contain a phandle pointing to the gated peripheral clock. |
15 | 16 | ||
17 | Optional properties: | ||
18 | - read-only: disable write access | ||
19 | |||
16 | Example: | 20 | Example: |
17 | 21 | ||
18 | ocotp: ocotp@021bc000 { | 22 | ocotp: ocotp@021bc000 { |
19 | compatible = "fsl,imx6q-ocotp", "syscon"; | 23 | compatible = "fsl,imx6q-ocotp", "syscon"; |
20 | reg = <0x021bc000 0x4000>; | 24 | reg = <0x021bc000 0x4000>; |
21 | clocks = <&clks IMX6QDL_CLK_IIM>; | 25 | clocks = <&clks IMX6QDL_CLK_IIM>; |
26 | read-only; | ||
22 | }; | 27 | }; |
diff --git a/Documentation/driver-api/vme.rst b/Documentation/driver-api/vme.rst index 89776fb3c8bd..def139c13410 100644 --- a/Documentation/driver-api/vme.rst +++ b/Documentation/driver-api/vme.rst | |||
@@ -6,36 +6,15 @@ Driver registration | |||
6 | 6 | ||
7 | As with other subsystems within the Linux kernel, VME device drivers register | 7 | As with other subsystems within the Linux kernel, VME device drivers register |
8 | with the VME subsystem, typically called from the devices init routine. This is | 8 | with the VME subsystem, typically called from the devices init routine. This is |
9 | achieved via a call to the following function: | 9 | achieved via a call to :c:func:`vme_register_driver`. |
10 | 10 | ||
11 | .. code-block:: c | 11 | A pointer to a structure of type :c:type:`struct vme_driver <vme_driver>` must |
12 | 12 | be provided to the registration function. Along with the maximum number of | |
13 | int vme_register_driver (struct vme_driver *driver, unsigned int ndevs); | 13 | devices your driver is able to support. |
14 | 14 | ||
15 | If driver registration is successful this function returns zero, if an error | 15 | At the minimum, the '.name', '.match' and '.probe' elements of |
16 | occurred a negative error code will be returned. | 16 | :c:type:`struct vme_driver <vme_driver>` should be correctly set. The '.name' |
17 | 17 | element is a pointer to a string holding the device driver's name. | |
18 | A pointer to a structure of type 'vme_driver' must be provided to the | ||
19 | registration function. Along with ndevs, which is the number of devices your | ||
20 | driver is able to support. The structure is as follows: | ||
21 | |||
22 | .. code-block:: c | ||
23 | |||
24 | struct vme_driver { | ||
25 | struct list_head node; | ||
26 | const char *name; | ||
27 | int (*match)(struct vme_dev *); | ||
28 | int (*probe)(struct vme_dev *); | ||
29 | int (*remove)(struct vme_dev *); | ||
30 | void (*shutdown)(void); | ||
31 | struct device_driver driver; | ||
32 | struct list_head devices; | ||
33 | unsigned int ndev; | ||
34 | }; | ||
35 | |||
36 | At the minimum, the '.name', '.match' and '.probe' elements of this structure | ||
37 | should be correctly set. The '.name' element is a pointer to a string holding | ||
38 | the device driver's name. | ||
39 | 18 | ||
40 | The '.match' function allows control over which VME devices should be registered | 19 | The '.match' function allows control over which VME devices should be registered |
41 | with the driver. The match function should return 1 if a device should be | 20 | with the driver. The match function should return 1 if a device should be |
@@ -54,29 +33,16 @@ the number of devices probed to one: | |||
54 | } | 33 | } |
55 | 34 | ||
56 | The '.probe' element should contain a pointer to the probe routine. The | 35 | The '.probe' element should contain a pointer to the probe routine. The |
57 | probe routine is passed a 'struct vme_dev' pointer as an argument. The | 36 | probe routine is passed a :c:type:`struct vme_dev <vme_dev>` pointer as an |
58 | 'struct vme_dev' structure looks like the following: | 37 | argument. |
59 | |||
60 | .. code-block:: c | ||
61 | |||
62 | struct vme_dev { | ||
63 | int num; | ||
64 | struct vme_bridge *bridge; | ||
65 | struct device dev; | ||
66 | struct list_head drv_list; | ||
67 | struct list_head bridge_list; | ||
68 | }; | ||
69 | 38 | ||
70 | Here, the 'num' field refers to the sequential device ID for this specific | 39 | Here, the 'num' field refers to the sequential device ID for this specific |
71 | driver. The bridge number (or bus number) can be accessed using | 40 | driver. The bridge number (or bus number) can be accessed using |
72 | dev->bridge->num. | 41 | dev->bridge->num. |
73 | 42 | ||
74 | A function is also provided to unregister the driver from the VME core and is | 43 | A function is also provided to unregister the driver from the VME core called |
75 | usually called from the device driver's exit routine: | 44 | :c:func:`vme_unregister_driver` and should usually be called from the device |
76 | 45 | driver's exit routine. | |
77 | .. code-block:: c | ||
78 | |||
79 | void vme_unregister_driver (struct vme_driver *driver); | ||
80 | 46 | ||
81 | 47 | ||
82 | Resource management | 48 | Resource management |
@@ -90,47 +56,29 @@ driver is called. The probe routine is passed a pointer to the devices | |||
90 | device structure. This pointer should be saved, it will be required for | 56 | device structure. This pointer should be saved, it will be required for |
91 | requesting VME resources. | 57 | requesting VME resources. |
92 | 58 | ||
93 | The driver can request ownership of one or more master windows, slave windows | 59 | The driver can request ownership of one or more master windows |
94 | and/or dma channels. Rather than allowing the device driver to request a | 60 | (:c:func:`vme_master_request`), slave windows (:c:func:`vme_slave_request`) |
95 | specific window or DMA channel (which may be used by a different driver) this | 61 | and/or dma channels (:c:func:`vme_dma_request`). Rather than allowing the device |
96 | driver allows a resource to be assigned based on the required attributes of the | 62 | driver to request a specific window or DMA channel (which may be used by a |
97 | driver in question: | 63 | different driver) the API allows a resource to be assigned based on the required |
98 | 64 | attributes of the driver in question. For slave windows these attributes are | |
99 | .. code-block:: c | 65 | split into the VME address spaces that need to be accessed in 'aspace' and VME |
100 | 66 | bus cycle types required in 'cycle'. Master windows add a further set of | |
101 | struct vme_resource * vme_master_request(struct vme_dev *dev, | 67 | attributes in 'width' specifying the required data transfer widths. These |
102 | u32 aspace, u32 cycle, u32 width); | 68 | attributes are defined as bitmasks and as such any combination of the |
103 | 69 | attributes can be requested for a single window, the core will assign a window | |
104 | struct vme_resource * vme_slave_request(struct vme_dev *dev, u32 aspace, | 70 | that meets the requirements, returning a pointer of type vme_resource that |
105 | u32 cycle); | 71 | should be used to identify the allocated resource when it is used. For DMA |
106 | 72 | controllers, the request function requires the potential direction of any | |
107 | struct vme_resource *vme_dma_request(struct vme_dev *dev, u32 route); | 73 | transfers to be provided in the route attributes. This is typically VME-to-MEM |
108 | 74 | and/or MEM-to-VME, though some hardware can support VME-to-VME and MEM-to-MEM | |
109 | For slave windows these attributes are split into the VME address spaces that | 75 | transfers as well as test pattern generation. If an unallocated window fitting |
110 | need to be accessed in 'aspace' and VME bus cycle types required in 'cycle'. | 76 | the requirements can not be found a NULL pointer will be returned. |
111 | Master windows add a further set of attributes in 'width' specifying the | ||
112 | required data transfer widths. These attributes are defined as bitmasks and as | ||
113 | such any combination of the attributes can be requested for a single window, | ||
114 | the core will assign a window that meets the requirements, returning a pointer | ||
115 | of type vme_resource that should be used to identify the allocated resource | ||
116 | when it is used. For DMA controllers, the request function requires the | ||
117 | potential direction of any transfers to be provided in the route attributes. | ||
118 | This is typically VME-to-MEM and/or MEM-to-VME, though some hardware can | ||
119 | support VME-to-VME and MEM-to-MEM transfers as well as test pattern generation. | ||
120 | If an unallocated window fitting the requirements can not be found a NULL | ||
121 | pointer will be returned. | ||
122 | 77 | ||
123 | Functions are also provided to free window allocations once they are no longer | 78 | Functions are also provided to free window allocations once they are no longer |
124 | required. These functions should be passed the pointer to the resource provided | 79 | required. These functions (:c:func:`vme_master_free`, :c:func:`vme_slave_free` |
125 | during resource allocation: | 80 | and :c:func:`vme_dma_free`) should be passed the pointer to the resource |
126 | 81 | provided during resource allocation. | |
127 | .. code-block:: c | ||
128 | |||
129 | void vme_master_free(struct vme_resource *res); | ||
130 | |||
131 | void vme_slave_free(struct vme_resource *res); | ||
132 | |||
133 | void vme_dma_free(struct vme_resource *res); | ||
134 | 82 | ||
135 | 83 | ||
136 | Master windows | 84 | Master windows |
@@ -144,61 +92,22 @@ the underlying chipset. A window must be configured before it can be used. | |||
144 | Master window configuration | 92 | Master window configuration |
145 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 93 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
146 | 94 | ||
147 | Once a master window has been assigned the following functions can be used to | 95 | Once a master window has been assigned :c:func:`vme_master_set` can be used to |
148 | configure it and retrieve the current settings: | 96 | configure it and :c:func:`vme_master_get` to retrieve the current settings. The |
149 | 97 | address spaces, transfer widths and cycle types are the same as described | |
150 | .. code-block:: c | ||
151 | |||
152 | int vme_master_set (struct vme_resource *res, int enabled, | ||
153 | unsigned long long base, unsigned long long size, u32 aspace, | ||
154 | u32 cycle, u32 width); | ||
155 | |||
156 | int vme_master_get (struct vme_resource *res, int *enabled, | ||
157 | unsigned long long *base, unsigned long long *size, u32 *aspace, | ||
158 | u32 *cycle, u32 *width); | ||
159 | |||
160 | The address spaces, transfer widths and cycle types are the same as described | ||
161 | under resource management, however some of the options are mutually exclusive. | 98 | under resource management, however some of the options are mutually exclusive. |
162 | For example, only one address space may be specified. | 99 | For example, only one address space may be specified. |
163 | 100 | ||
164 | These functions return 0 on success or an error code should the call fail. | ||
165 | |||
166 | 101 | ||
167 | Master window access | 102 | Master window access |
168 | ~~~~~~~~~~~~~~~~~~~~ | 103 | ~~~~~~~~~~~~~~~~~~~~ |
169 | 104 | ||
170 | The following functions can be used to read from and write to configured master | 105 | The function :c:func:`vme_master_read` can be used to read from and |
171 | windows. These functions return the number of bytes copied: | 106 | :c:func:`vme_master_write` used to write to configured master windows. |
172 | |||
173 | .. code-block:: c | ||
174 | |||
175 | ssize_t vme_master_read(struct vme_resource *res, void *buf, | ||
176 | size_t count, loff_t offset); | ||
177 | |||
178 | ssize_t vme_master_write(struct vme_resource *res, void *buf, | ||
179 | size_t count, loff_t offset); | ||
180 | |||
181 | In addition to simple reads and writes, a function is provided to do a | ||
182 | read-modify-write transaction. This function returns the original value of the | ||
183 | VME bus location : | ||
184 | |||
185 | .. code-block:: c | ||
186 | |||
187 | unsigned int vme_master_rmw (struct vme_resource *res, | ||
188 | unsigned int mask, unsigned int compare, unsigned int swap, | ||
189 | loff_t offset); | ||
190 | |||
191 | This functions by reading the offset, applying the mask. If the bits selected in | ||
192 | the mask match with the values of the corresponding bits in the compare field, | ||
193 | the value of swap is written the specified offset. | ||
194 | |||
195 | Parts of a VME window can be mapped into user space memory using the following | ||
196 | function: | ||
197 | 107 | ||
198 | .. code-block:: c | 108 | In addition to simple reads and writes, :c:func:`vme_master_rmw` is provided to |
199 | 109 | do a read-modify-write transaction. Parts of a VME window can also be mapped | |
200 | int vme_master_mmap(struct vme_resource *resource, | 110 | into user space memory using :c:func:`vme_master_mmap`. |
201 | struct vm_area_struct *vma) | ||
202 | 111 | ||
203 | 112 | ||
204 | Slave windows | 113 | Slave windows |
@@ -213,41 +122,23 @@ it can be used. | |||
213 | Slave window configuration | 122 | Slave window configuration |
214 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | 123 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
215 | 124 | ||
216 | Once a slave window has been assigned the following functions can be used to | 125 | Once a slave window has been assigned :c:func:`vme_slave_set` can be used to |
217 | configure it and retrieve the current settings: | 126 | configure it and :c:func:`vme_slave_get` to retrieve the current settings. |
218 | |||
219 | .. code-block:: c | ||
220 | |||
221 | int vme_slave_set (struct vme_resource *res, int enabled, | ||
222 | unsigned long long base, unsigned long long size, | ||
223 | dma_addr_t mem, u32 aspace, u32 cycle); | ||
224 | |||
225 | int vme_slave_get (struct vme_resource *res, int *enabled, | ||
226 | unsigned long long *base, unsigned long long *size, | ||
227 | dma_addr_t *mem, u32 *aspace, u32 *cycle); | ||
228 | 127 | ||
229 | The address spaces, transfer widths and cycle types are the same as described | 128 | The address spaces, transfer widths and cycle types are the same as described |
230 | under resource management, however some of the options are mutually exclusive. | 129 | under resource management, however some of the options are mutually exclusive. |
231 | For example, only one address space may be specified. | 130 | For example, only one address space may be specified. |
232 | 131 | ||
233 | These functions return 0 on success or an error code should the call fail. | ||
234 | |||
235 | 132 | ||
236 | Slave window buffer allocation | 133 | Slave window buffer allocation |
237 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 134 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
238 | 135 | ||
239 | Functions are provided to allow the user to allocate and free a contiguous | 136 | Functions are provided to allow the user to allocate |
240 | buffers which will be accessible by the VME bridge. These functions do not have | 137 | (:c:func:`vme_alloc_consistent`) and free (:c:func:`vme_free_consistent`) |
241 | to be used, other methods can be used to allocate a buffer, though care must be | 138 | contiguous buffers which will be accessible by the VME bridge. These functions |
242 | taken to ensure that they are contiguous and accessible by the VME bridge: | 139 | do not have to be used, other methods can be used to allocate a buffer, though |
243 | 140 | care must be taken to ensure that they are contiguous and accessible by the VME | |
244 | .. code-block:: c | 141 | bridge. |
245 | |||
246 | void * vme_alloc_consistent(struct vme_resource *res, size_t size, | ||
247 | dma_addr_t *mem); | ||
248 | |||
249 | void vme_free_consistent(struct vme_resource *res, size_t size, | ||
250 | void *virt, dma_addr_t mem); | ||
251 | 142 | ||
252 | 143 | ||
253 | Slave window access | 144 | Slave window access |
@@ -269,29 +160,18 @@ executed, reused and destroyed. | |||
269 | List Management | 160 | List Management |
270 | ~~~~~~~~~~~~~~~ | 161 | ~~~~~~~~~~~~~~~ |
271 | 162 | ||
272 | The following functions are provided to create and destroy DMA lists. Execution | 163 | The function :c:func:`vme_new_dma_list` is provided to create and |
273 | of a list will not automatically destroy the list, thus enabling a list to be | 164 | :c:func:`vme_dma_list_free` to destroy DMA lists. Execution of a list will not |
274 | reused for repetitive tasks: | 165 | automatically destroy the list, thus enabling a list to be reused for repetitive |
275 | 166 | tasks. | |
276 | .. code-block:: c | ||
277 | |||
278 | struct vme_dma_list *vme_new_dma_list(struct vme_resource *res); | ||
279 | |||
280 | int vme_dma_list_free(struct vme_dma_list *list); | ||
281 | 167 | ||
282 | 168 | ||
283 | List Population | 169 | List Population |
284 | ~~~~~~~~~~~~~~~ | 170 | ~~~~~~~~~~~~~~~ |
285 | 171 | ||
286 | An item can be added to a list using the following function ( the source and | 172 | An item can be added to a list using :c:func:`vme_dma_list_add` (the source and |
287 | destination attributes need to be created before calling this function, this is | 173 | destination attributes need to be created before calling this function, this is |
288 | covered under "Transfer Attributes"): | 174 | covered under "Transfer Attributes"). |
289 | |||
290 | .. code-block:: c | ||
291 | |||
292 | int vme_dma_list_add(struct vme_dma_list *list, | ||
293 | struct vme_dma_attr *src, struct vme_dma_attr *dest, | ||
294 | size_t count); | ||
295 | 175 | ||
296 | .. note:: | 176 | .. note:: |
297 | 177 | ||
@@ -310,41 +190,19 @@ an item to a list. This is due to the diverse attributes required for each type | |||
310 | of source and destination. There are functions to create attributes for PCI, VME | 190 | of source and destination. There are functions to create attributes for PCI, VME |
311 | and pattern sources and destinations (where appropriate): | 191 | and pattern sources and destinations (where appropriate): |
312 | 192 | ||
313 | Pattern source: | 193 | - PCI source or destination: :c:func:`vme_dma_pci_attribute` |
314 | 194 | - VME source or destination: :c:func:`vme_dma_vme_attribute` | |
315 | .. code-block:: c | 195 | - Pattern source: :c:func:`vme_dma_pattern_attribute` |
316 | |||
317 | struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type); | ||
318 | |||
319 | PCI source or destination: | ||
320 | |||
321 | .. code-block:: c | ||
322 | |||
323 | struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t mem); | ||
324 | |||
325 | VME source or destination: | ||
326 | 196 | ||
327 | .. code-block:: c | 197 | The function :c:func:`vme_dma_free_attribute` should be used to free an |
328 | 198 | attribute. | |
329 | struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long base, | ||
330 | u32 aspace, u32 cycle, u32 width); | ||
331 | |||
332 | The following function should be used to free an attribute: | ||
333 | |||
334 | .. code-block:: c | ||
335 | |||
336 | void vme_dma_free_attribute(struct vme_dma_attr *attr); | ||
337 | 199 | ||
338 | 200 | ||
339 | List Execution | 201 | List Execution |
340 | ~~~~~~~~~~~~~~ | 202 | ~~~~~~~~~~~~~~ |
341 | 203 | ||
342 | The following function queues a list for execution. The function will return | 204 | The function :c:func:`vme_dma_list_exec` queues a list for execution and will |
343 | once the list has been executed: | 205 | return once the list has been executed. |
344 | |||
345 | .. code-block:: c | ||
346 | |||
347 | int vme_dma_list_exec(struct vme_dma_list *list); | ||
348 | 206 | ||
349 | 207 | ||
350 | Interrupts | 208 | Interrupts |
@@ -358,20 +216,13 @@ specific VME level and status IDs. | |||
358 | Attaching Interrupt Handlers | 216 | Attaching Interrupt Handlers |
359 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 217 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
360 | 218 | ||
361 | The following functions can be used to attach and free a specific VME level and | 219 | The function :c:func:`vme_irq_request` can be used to attach and |
362 | status ID combination. Any given combination can only be assigned a single | 220 | :c:func:`vme_irq_free` to free a specific VME level and status ID combination. |
363 | callback function. A void pointer parameter is provided, the value of which is | 221 | Any given combination can only be assigned a single callback function. A void |
364 | passed to the callback function, the use of this pointer is user undefined: | 222 | pointer parameter is provided, the value of which is passed to the callback |
365 | 223 | function, the use of this pointer is user undefined. The callback parameters are | |
366 | .. code-block:: c | 224 | as follows. Care must be taken in writing a callback function, callback |
367 | 225 | functions run in interrupt context: | |
368 | int vme_irq_request(struct vme_dev *dev, int level, int statid, | ||
369 | void (*callback)(int, int, void *), void *priv); | ||
370 | |||
371 | void vme_irq_free(struct vme_dev *dev, int level, int statid); | ||
372 | |||
373 | The callback parameters are as follows. Care must be taken in writing a callback | ||
374 | function, callback functions run in interrupt context: | ||
375 | 226 | ||
376 | .. code-block:: c | 227 | .. code-block:: c |
377 | 228 | ||
@@ -381,12 +232,8 @@ function, callback functions run in interrupt context: | |||
381 | Interrupt Generation | 232 | Interrupt Generation |
382 | ~~~~~~~~~~~~~~~~~~~~ | 233 | ~~~~~~~~~~~~~~~~~~~~ |
383 | 234 | ||
384 | The following function can be used to generate a VME interrupt at a given VME | 235 | The function :c:func:`vme_irq_generate` can be used to generate a VME interrupt |
385 | level and VME status ID: | 236 | at a given VME level and VME status ID. |
386 | |||
387 | .. code-block:: c | ||
388 | |||
389 | int vme_irq_generate(struct vme_dev *dev, int level, int statid); | ||
390 | 237 | ||
391 | 238 | ||
392 | Location monitors | 239 | Location monitors |
@@ -399,54 +246,29 @@ monitor. | |||
399 | Location Monitor Management | 246 | Location Monitor Management |
400 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 247 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
401 | 248 | ||
402 | The following functions are provided to request the use of a block of location | 249 | The function :c:func:`vme_lm_request` is provided to request the use of a block |
403 | monitors and to free them after they are no longer required: | 250 | of location monitors and :c:func:`vme_lm_free` to free them after they are no |
404 | 251 | longer required. Each block may provide a number of location monitors, | |
405 | .. code-block:: c | 252 | monitoring adjacent locations. The function :c:func:`vme_lm_count` can be used |
406 | 253 | to determine how many locations are provided. | |
407 | struct vme_resource * vme_lm_request(struct vme_dev *dev); | ||
408 | |||
409 | void vme_lm_free(struct vme_resource * res); | ||
410 | |||
411 | Each block may provide a number of location monitors, monitoring adjacent | ||
412 | locations. The following function can be used to determine how many locations | ||
413 | are provided: | ||
414 | |||
415 | .. code-block:: c | ||
416 | |||
417 | int vme_lm_count(struct vme_resource * res); | ||
418 | 254 | ||
419 | 255 | ||
420 | Location Monitor Configuration | 256 | Location Monitor Configuration |
421 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 257 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
422 | 258 | ||
423 | Once a bank of location monitors has been allocated, the following functions | 259 | Once a bank of location monitors has been allocated, the function |
424 | are provided to configure the location and mode of the location monitor: | 260 | :c:func:`vme_lm_set` is provided to configure the location and mode of the |
425 | 261 | location monitor. The function :c:func:`vme_lm_get` can be used to retrieve | |
426 | .. code-block:: c | 262 | existing settings. |
427 | |||
428 | int vme_lm_set(struct vme_resource *res, unsigned long long base, | ||
429 | u32 aspace, u32 cycle); | ||
430 | |||
431 | int vme_lm_get(struct vme_resource *res, unsigned long long *base, | ||
432 | u32 *aspace, u32 *cycle); | ||
433 | 263 | ||
434 | 264 | ||
435 | Location Monitor Use | 265 | Location Monitor Use |
436 | ~~~~~~~~~~~~~~~~~~~~ | 266 | ~~~~~~~~~~~~~~~~~~~~ |
437 | 267 | ||
438 | The following functions allow a callback to be attached and detached from each | 268 | The function :c:func:`vme_lm_attach` enables a callback to be attached and |
439 | location monitor location. Each location monitor can monitor a number of | 269 | :c:func:`vme_lm_detach` allows on to be detached from each location monitor |
440 | adjacent locations: | 270 | location. Each location monitor can monitor a number of adjacent locations. The |
441 | 271 | callback function is declared as follows. | |
442 | .. code-block:: c | ||
443 | |||
444 | int vme_lm_attach(struct vme_resource *res, int num, | ||
445 | void (*callback)(void *)); | ||
446 | |||
447 | int vme_lm_detach(struct vme_resource *res, int num); | ||
448 | |||
449 | The callback function is declared as follows. | ||
450 | 272 | ||
451 | .. code-block:: c | 273 | .. code-block:: c |
452 | 274 | ||
@@ -456,19 +278,20 @@ The callback function is declared as follows. | |||
456 | Slot Detection | 278 | Slot Detection |
457 | -------------- | 279 | -------------- |
458 | 280 | ||
459 | This function returns the slot ID of the provided bridge. | 281 | The function :c:func:`vme_slot_num` returns the slot ID of the provided bridge. |
460 | |||
461 | .. code-block:: c | ||
462 | |||
463 | int vme_slot_num(struct vme_dev *dev); | ||
464 | 282 | ||
465 | 283 | ||
466 | Bus Detection | 284 | Bus Detection |
467 | ------------- | 285 | ------------- |
468 | 286 | ||
469 | This function returns the bus ID of the provided bridge. | 287 | The function :c:func:`vme_bus_num` returns the bus ID of the provided bridge. |
470 | 288 | ||
471 | .. code-block:: c | ||
472 | 289 | ||
473 | int vme_bus_num(struct vme_dev *dev); | 290 | VME API |
291 | ------- | ||
292 | |||
293 | .. kernel-doc:: include/linux/vme.h | ||
294 | :internal: | ||
474 | 295 | ||
296 | .. kernel-doc:: drivers/vme/vme.c | ||
297 | :export: | ||
diff --git a/Documentation/extcon/porting-android-switch-class b/Documentation/extcon/porting-android-switch-class deleted file mode 100644 index 49c81caef84d..000000000000 --- a/Documentation/extcon/porting-android-switch-class +++ /dev/null | |||
@@ -1,123 +0,0 @@ | |||
1 | |||
2 | Staging/Android Switch Class Porting Guide | ||
3 | (linux/drivers/staging/android/switch) | ||
4 | (c) Copyright 2012 Samsung Electronics | ||
5 | |||
6 | AUTHORS | ||
7 | MyungJoo Ham <myungjoo.ham@samsung.com> | ||
8 | |||
9 | /***************************************************************** | ||
10 | * CHAPTER 1. * | ||
11 | * PORTING SWITCH CLASS DEVICE DRIVERS * | ||
12 | *****************************************************************/ | ||
13 | |||
14 | ****** STEP 1. Basic Functionality | ||
15 | No extcon extended feature, but switch features only. | ||
16 | |||
17 | - struct switch_dev (fed to switch_dev_register/unregister) | ||
18 | @name: no change | ||
19 | @dev: no change | ||
20 | @index: drop (not used in switch device driver side anyway) | ||
21 | @state: no change | ||
22 | If you have used @state with magic numbers, keep it | ||
23 | at this step. | ||
24 | @print_name: no change but type change (switch_dev->extcon_dev) | ||
25 | @print_state: no change but type change (switch_dev->extcon_dev) | ||
26 | |||
27 | - switch_dev_register(sdev, dev) | ||
28 | => extcon_dev_register(edev) | ||
29 | : type change (sdev->edev) | ||
30 | : remove second param('dev'). if edev has parent device, should store | ||
31 | 'dev' to 'edev.dev.parent' before registering extcon device | ||
32 | - switch_dev_unregister(sdev) | ||
33 | => extcon_dev_unregister(edev) | ||
34 | : no change but type change (sdev->edev) | ||
35 | - switch_get_state(sdev) | ||
36 | => extcon_get_state(edev) | ||
37 | : no change but type change (sdev->edev) and (return: int->u32) | ||
38 | - switch_set_state(sdev, state) | ||
39 | => extcon_set_state(edev, state) | ||
40 | : no change but type change (sdev->edev) and (state: int->u32) | ||
41 | |||
42 | With this changes, the ex-switch extcon class device works as it once | ||
43 | worked as switch class device. However, it will now have additional | ||
44 | interfaces (both ABI and in-kernel API) and different ABI locations. | ||
45 | However, if CONFIG_ANDROID is enabled without CONFIG_ANDROID_SWITCH, | ||
46 | /sys/class/switch/* will be symbolically linked to /sys/class/extcon/ | ||
47 | so that they are still compatible with legacy userspace processes. | ||
48 | |||
49 | ****** STEP 2. Multistate (no more magic numbers in state value) | ||
50 | Extcon's extended features for switch device drivers with | ||
51 | complex features usually required magic numbers in state | ||
52 | value of switch_dev. With extcon, such magic numbers that | ||
53 | support multiple cables are no more required or supported. | ||
54 | |||
55 | 1. Define cable names at edev->supported_cable. | ||
56 | 2. (Recommended) remove print_state callback. | ||
57 | 3. Use extcon_get_cable_state_(edev, index) or | ||
58 | extcon_get_cable_state(edev, cable_name) instead of | ||
59 | extcon_get_state(edev) if you intend to get a state of a specific | ||
60 | cable. Same for set_state. This way, you can remove the usage of | ||
61 | magic numbers in state value. | ||
62 | 4. Use extcon_update_state() if you are updating specific bits of | ||
63 | the state value. | ||
64 | |||
65 | Example: a switch device driver w/ magic numbers for two cables. | ||
66 | "0x00": no cables connected. | ||
67 | "0x01": cable 1 connected | ||
68 | "0x02": cable 2 connected | ||
69 | "0x03": cable 1 and 2 connected | ||
70 | 1. edev->supported_cable = {"1", "2", NULL}; | ||
71 | 2. edev->print_state = NULL; | ||
72 | 3. extcon_get_cable_state_(edev, 0) shows cable 1's state. | ||
73 | extcon_get_cable_state(edev, "1") shows cable 1's state. | ||
74 | extcon_set_cable_state_(edev, 1) sets cable 2's state. | ||
75 | extcon_set_cable_state(edev, "2") sets cable 2's state | ||
76 | 4. extcon_update_state(edev, 0x01, 0) sets the least bit's 0. | ||
77 | |||
78 | ****** STEP 3. Notify other device drivers | ||
79 | |||
80 | You can notify others of the cable attach/detach events with | ||
81 | notifier chains. | ||
82 | |||
83 | At the side of other device drivers (the extcon device itself | ||
84 | does not need to get notified of its own events), there are two | ||
85 | methods to register notifier_block for cable events: | ||
86 | (a) for a specific cable or (b) for every cable. | ||
87 | |||
88 | (a) extcon_register_interest(obj, extcon_name, cable_name, nb) | ||
89 | Example: want to get news of "MAX8997_MUIC"'s "USB" cable | ||
90 | |||
91 | obj = kzalloc(sizeof(struct extcon_specific_cable_nb), | ||
92 | GFP_KERNEL); | ||
93 | nb->notifier_call = the_callback_to_handle_usb; | ||
94 | |||
95 | extcon_register_intereset(obj, "MAX8997_MUIC", "USB", nb); | ||
96 | |||
97 | (b) extcon_register_notifier(edev, nb) | ||
98 | Call nb for any changes in edev. | ||
99 | |||
100 | Please note that in order to properly behave with method (a), | ||
101 | the extcon device driver should support multistate feature (STEP 2). | ||
102 | |||
103 | ****** STEP 4. Inter-cable relation (mutually exclusive) | ||
104 | |||
105 | You can provide inter-cable mutually exclusiveness information | ||
106 | for an extcon device. When cables A and B are declared to be mutually | ||
107 | exclusive, the two cables cannot be in ATTACHED state simulteneously. | ||
108 | |||
109 | |||
110 | /***************************************************************** | ||
111 | * CHAPTER 2. * | ||
112 | * PORTING USERSPACE w/ SWITCH CLASS DEVICE SUPPORT * | ||
113 | *****************************************************************/ | ||
114 | |||
115 | ****** ABI Location | ||
116 | |||
117 | If "CONFIG_ANDROID" is enabled, /sys/class/switch/* are created | ||
118 | as symbolic links to /sys/class/extcon/*. | ||
119 | |||
120 | The two files of switch class, name and state, are provided with | ||
121 | extcon, too. When the multistate support (STEP 2 of CHAPTER 1.) is | ||
122 | not enabled or print_state callback is supplied, the output of | ||
123 | state ABI is same with switch class. | ||
diff --git a/Documentation/w1/slaves/00-INDEX b/Documentation/w1/slaves/00-INDEX index 6e18c70c3474..8d76718e1ea2 100644 --- a/Documentation/w1/slaves/00-INDEX +++ b/Documentation/w1/slaves/00-INDEX | |||
@@ -2,7 +2,11 @@ | |||
2 | - This file | 2 | - This file |
3 | w1_therm | 3 | w1_therm |
4 | - The Maxim/Dallas Semiconductor ds18*20 temperature sensor. | 4 | - The Maxim/Dallas Semiconductor ds18*20 temperature sensor. |
5 | w1_ds2413 | ||
6 | - The Maxim/Dallas Semiconductor ds2413 dual channel addressable switch. | ||
5 | w1_ds2423 | 7 | w1_ds2423 |
6 | - The Maxim/Dallas Semiconductor ds2423 counter device. | 8 | - The Maxim/Dallas Semiconductor ds2423 counter device. |
9 | w1_ds2438 | ||
10 | - The Maxim/Dallas Semiconductor ds2438 smart battery monitor. | ||
7 | w1_ds28e04 | 11 | w1_ds28e04 |
8 | - The Maxim/Dallas Semiconductor ds28e04 eeprom. | 12 | - The Maxim/Dallas Semiconductor ds28e04 eeprom. |
diff --git a/Documentation/w1/slaves/w1_ds2413 b/Documentation/w1/slaves/w1_ds2413 new file mode 100644 index 000000000000..936263a8ccb4 --- /dev/null +++ b/Documentation/w1/slaves/w1_ds2413 | |||
@@ -0,0 +1,50 @@ | |||
1 | Kernel driver w1_ds2413 | ||
2 | ======================= | ||
3 | |||
4 | Supported chips: | ||
5 | * Maxim DS2413 1-Wire Dual Channel Addressable Switch | ||
6 | |||
7 | supported family codes: | ||
8 | W1_FAMILY_DS2413 0x3A | ||
9 | |||
10 | Author: Mariusz Bialonczyk <manio@skyboo.net> | ||
11 | |||
12 | Description | ||
13 | ----------- | ||
14 | |||
15 | The DS2413 chip has two open-drain outputs (PIO A and PIO B). | ||
16 | Support is provided through the sysfs files "output" and "state". | ||
17 | |||
18 | Reading state | ||
19 | ------------- | ||
20 | The "state" file provides one-byte value which is in the same format as for | ||
21 | the chip PIO_ACCESS_READ command (refer the datasheet for details): | ||
22 | |||
23 | Bit 0: PIOA Pin State | ||
24 | Bit 1: PIOA Output Latch State | ||
25 | Bit 2: PIOB Pin State | ||
26 | Bit 3: PIOB Output Latch State | ||
27 | Bit 4-7: Complement of Bit 3 to Bit 0 (verified by the kernel module) | ||
28 | |||
29 | This file is readonly. | ||
30 | |||
31 | Writing output | ||
32 | -------------- | ||
33 | You can set the PIO pins using the "output" file. | ||
34 | It is writable, you can write one-byte value to this sysfs file. | ||
35 | Similarly the byte format is the same as for the PIO_ACCESS_WRITE command: | ||
36 | |||
37 | Bit 0: PIOA | ||
38 | Bit 1: PIOB | ||
39 | Bit 2-7: No matter (driver will set it to "1"s) | ||
40 | |||
41 | |||
42 | The chip has some kind of basic protection against transmission errors. | ||
43 | When reading the state, there is a four complement bits. | ||
44 | The driver is checking this complement, and when it is wrong then it is | ||
45 | returning I/O error. | ||
46 | |||
47 | When writing output, the master must repeat the PIO Output Data byte in | ||
48 | its inverted form and it is waiting for a confirmation. | ||
49 | If the write is unsuccessful for three times, the write also returns | ||
50 | I/O error. | ||
diff --git a/Documentation/w1/slaves/w1_ds2438 b/Documentation/w1/slaves/w1_ds2438 new file mode 100644 index 000000000000..b99f3674c5b4 --- /dev/null +++ b/Documentation/w1/slaves/w1_ds2438 | |||
@@ -0,0 +1,63 @@ | |||
1 | Kernel driver w1_ds2438 | ||
2 | ======================= | ||
3 | |||
4 | Supported chips: | ||
5 | * Maxim DS2438 Smart Battery Monitor | ||
6 | |||
7 | supported family codes: | ||
8 | W1_FAMILY_DS2438 0x26 | ||
9 | |||
10 | Author: Mariusz Bialonczyk <manio@skyboo.net> | ||
11 | |||
12 | Description | ||
13 | ----------- | ||
14 | |||
15 | The DS2438 chip provides several functions that are desirable to carry in | ||
16 | a battery pack. It also has a 40 bytes of nonvolatile EEPROM. | ||
17 | Because the ability of temperature, current and voltage measurement, the chip | ||
18 | is also often used in weather stations and applications such as: rain gauge, | ||
19 | wind speed/direction measuring, humidity sensing, etc. | ||
20 | |||
21 | Current support is provided through the following sysfs files (all files | ||
22 | except "iad" are readonly): | ||
23 | |||
24 | "iad" | ||
25 | ----- | ||
26 | This file controls the 'Current A/D Control Bit' (IAD) in the | ||
27 | Status/Configuration Register. | ||
28 | Writing a zero value will clear the IAD bit and disables the current | ||
29 | measurements. | ||
30 | Writing value "1" is setting the IAD bit (enables the measurements). | ||
31 | The IAD bit is enabled by default in the DS2438. | ||
32 | |||
33 | When writing to sysfs file bits 2-7 are ignored, so it's safe to write ASCII. | ||
34 | An I/O error is returned when there is a problem setting the new value. | ||
35 | |||
36 | "page0" | ||
37 | ------- | ||
38 | This file provides full 8 bytes of the chip Page 0 (00h). | ||
39 | This page contains the most frequently accessed information of the DS2438. | ||
40 | Internally when this file is read, the additional CRC byte is also obtained | ||
41 | from the slave device. If it is correct, the 8 bytes page data are passed | ||
42 | to userspace, otherwise an I/O error is returned. | ||
43 | |||
44 | "temperature" | ||
45 | ------------- | ||
46 | Opening and reading this file initiates the CONVERT_T (temperature conversion) | ||
47 | command of the chip, afterwards the temperature is read from the device | ||
48 | registers and provided as an ASCII decimal value. | ||
49 | |||
50 | Important: The returned value has to be divided by 256 to get a real | ||
51 | temperature in degrees Celsius. | ||
52 | |||
53 | "vad", "vdd" | ||
54 | ------------ | ||
55 | Opening and reading this file initiates the CONVERT_V (voltage conversion) | ||
56 | command of the chip. | ||
57 | |||
58 | Depending on a sysfs filename a different input for the A/D will be selected: | ||
59 | vad: general purpose A/D input (VAD) | ||
60 | vdd: battery input (VDD) | ||
61 | |||
62 | After the voltage conversion the value is returned as decimal ASCII. | ||
63 | Note: The value is in mV, so to get a volts the value has to be divided by 10. | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 748354f51966..5ee3125f8341 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -5161,7 +5161,6 @@ F: include/uapi/linux/firewire*.h | |||
5161 | F: tools/firewire/ | 5161 | F: tools/firewire/ |
5162 | 5162 | ||
5163 | FIRMWARE LOADER (request_firmware) | 5163 | FIRMWARE LOADER (request_firmware) |
5164 | M: Ming Lei <ming.lei@canonical.com> | ||
5165 | M: Luis R. Rodriguez <mcgrof@kernel.org> | 5164 | M: Luis R. Rodriguez <mcgrof@kernel.org> |
5166 | L: linux-kernel@vger.kernel.org | 5165 | L: linux-kernel@vger.kernel.org |
5167 | S: Maintained | 5166 | S: Maintained |
@@ -5191,13 +5190,15 @@ F: include/linux/ipmi-fru.h | |||
5191 | K: fmc_d.*register | 5190 | K: fmc_d.*register |
5192 | 5191 | ||
5193 | FPGA MANAGER FRAMEWORK | 5192 | FPGA MANAGER FRAMEWORK |
5194 | M: Alan Tull <atull@opensource.altera.com> | 5193 | M: Alan Tull <atull@kernel.org> |
5195 | R: Moritz Fischer <moritz.fischer@ettus.com> | 5194 | R: Moritz Fischer <moritz.fischer@ettus.com> |
5196 | L: linux-fpga@vger.kernel.org | 5195 | L: linux-fpga@vger.kernel.org |
5197 | S: Maintained | 5196 | S: Maintained |
5198 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/atull/linux-fpga.git | 5197 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/atull/linux-fpga.git |
5198 | F: Documentation/fpga/ | ||
5199 | F: Documentation/devicetree/bindings/fpga/ | ||
5199 | F: drivers/fpga/ | 5200 | F: drivers/fpga/ |
5200 | F: include/linux/fpga/fpga-mgr.h | 5201 | F: include/linux/fpga/ |
5201 | W: http://www.rocketboards.org | 5202 | W: http://www.rocketboards.org |
5202 | 5203 | ||
5203 | FPU EMULATOR | 5204 | FPU EMULATOR |
@@ -9131,7 +9132,6 @@ F: drivers/nvme/target/fcloop.c | |||
9131 | 9132 | ||
9132 | NVMEM FRAMEWORK | 9133 | NVMEM FRAMEWORK |
9133 | M: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> | 9134 | M: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> |
9134 | M: Maxime Ripard <maxime.ripard@free-electrons.com> | ||
9135 | S: Maintained | 9135 | S: Maintained |
9136 | F: drivers/nvmem/ | 9136 | F: drivers/nvmem/ |
9137 | F: Documentation/devicetree/bindings/nvmem/ | 9137 | F: Documentation/devicetree/bindings/nvmem/ |
diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c index 8a5b6f059498..55b186ef863a 100644 --- a/arch/arm/mach-ep93xx/ts72xx.c +++ b/arch/arm/mach-ep93xx/ts72xx.c | |||
@@ -210,6 +210,28 @@ static struct ep93xx_eth_data __initdata ts72xx_eth_data = { | |||
210 | .phy_id = 1, | 210 | .phy_id = 1, |
211 | }; | 211 | }; |
212 | 212 | ||
213 | #if IS_ENABLED(CONFIG_FPGA_MGR_TS73XX) | ||
214 | |||
215 | /* Relative to EP93XX_CS1_PHYS_BASE */ | ||
216 | #define TS73XX_FPGA_LOADER_BASE 0x03c00000 | ||
217 | |||
218 | static struct resource ts73xx_fpga_resources[] = { | ||
219 | { | ||
220 | .start = EP93XX_CS1_PHYS_BASE + TS73XX_FPGA_LOADER_BASE, | ||
221 | .end = EP93XX_CS1_PHYS_BASE + TS73XX_FPGA_LOADER_BASE + 1, | ||
222 | .flags = IORESOURCE_MEM, | ||
223 | }, | ||
224 | }; | ||
225 | |||
226 | static struct platform_device ts73xx_fpga_device = { | ||
227 | .name = "ts73xx-fpga-mgr", | ||
228 | .id = -1, | ||
229 | .resource = ts73xx_fpga_resources, | ||
230 | .num_resources = ARRAY_SIZE(ts73xx_fpga_resources), | ||
231 | }; | ||
232 | |||
233 | #endif | ||
234 | |||
213 | static void __init ts72xx_init_machine(void) | 235 | static void __init ts72xx_init_machine(void) |
214 | { | 236 | { |
215 | ep93xx_init_devices(); | 237 | ep93xx_init_devices(); |
@@ -218,6 +240,10 @@ static void __init ts72xx_init_machine(void) | |||
218 | platform_device_register(&ts72xx_wdt_device); | 240 | platform_device_register(&ts72xx_wdt_device); |
219 | 241 | ||
220 | ep93xx_register_eth(&ts72xx_eth_data, 1); | 242 | ep93xx_register_eth(&ts72xx_eth_data, 1); |
243 | #if IS_ENABLED(CONFIG_FPGA_MGR_TS73XX) | ||
244 | if (board_is_ts7300()) | ||
245 | platform_device_register(&ts73xx_fpga_device); | ||
246 | #endif | ||
221 | } | 247 | } |
222 | 248 | ||
223 | MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC") | 249 | MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC") |
diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c index 2b01421f7d0f..5b882cc0c0e9 100644 --- a/arch/x86/hyperv/hv_init.c +++ b/arch/x86/hyperv/hv_init.c | |||
@@ -25,7 +25,7 @@ | |||
25 | #include <linux/vmalloc.h> | 25 | #include <linux/vmalloc.h> |
26 | #include <linux/mm.h> | 26 | #include <linux/mm.h> |
27 | #include <linux/clockchips.h> | 27 | #include <linux/clockchips.h> |
28 | 28 | #include <linux/hyperv.h> | |
29 | 29 | ||
30 | #ifdef CONFIG_HYPERV_TSCPAGE | 30 | #ifdef CONFIG_HYPERV_TSCPAGE |
31 | 31 | ||
diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 3a20ccf787b8..432df4b1baec 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h | |||
@@ -124,7 +124,7 @@ | |||
124 | * Recommend using hypercall for address space switches rather | 124 | * Recommend using hypercall for address space switches rather |
125 | * than MOV to CR3 instruction | 125 | * than MOV to CR3 instruction |
126 | */ | 126 | */ |
127 | #define HV_X64_MWAIT_RECOMMENDED (1 << 0) | 127 | #define HV_X64_AS_SWITCH_RECOMMENDED (1 << 0) |
128 | /* Recommend using hypercall for local TLB flushes rather | 128 | /* Recommend using hypercall for local TLB flushes rather |
129 | * than INVLPG or MOV to CR3 instructions */ | 129 | * than INVLPG or MOV to CR3 instructions */ |
130 | #define HV_X64_LOCAL_TLB_FLUSH_RECOMMENDED (1 << 1) | 130 | #define HV_X64_LOCAL_TLB_FLUSH_RECOMMENDED (1 << 1) |
@@ -148,6 +148,11 @@ | |||
148 | #define HV_X64_RELAXED_TIMING_RECOMMENDED (1 << 5) | 148 | #define HV_X64_RELAXED_TIMING_RECOMMENDED (1 << 5) |
149 | 149 | ||
150 | /* | 150 | /* |
151 | * Virtual APIC support | ||
152 | */ | ||
153 | #define HV_X64_DEPRECATING_AEOI_RECOMMENDED (1 << 9) | ||
154 | |||
155 | /* | ||
151 | * Crash notification flag. | 156 | * Crash notification flag. |
152 | */ | 157 | */ |
153 | #define HV_CRASH_CTL_CRASH_NOTIFY (1ULL << 63) | 158 | #define HV_CRASH_CTL_CRASH_NOTIFY (1ULL << 63) |
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index b5375b9497b3..04cb8d34ccb8 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c | |||
@@ -49,6 +49,9 @@ void hyperv_vector_handler(struct pt_regs *regs) | |||
49 | if (vmbus_handler) | 49 | if (vmbus_handler) |
50 | vmbus_handler(); | 50 | vmbus_handler(); |
51 | 51 | ||
52 | if (ms_hyperv.hints & HV_X64_DEPRECATING_AEOI_RECOMMENDED) | ||
53 | ack_APIC_irq(); | ||
54 | |||
52 | exiting_irq(); | 55 | exiting_irq(); |
53 | set_irq_regs(old_regs); | 56 | set_irq_regs(old_regs); |
54 | } | 57 | } |
diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index a82fc022d34b..832e885349b1 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig | |||
@@ -22,7 +22,7 @@ config ANDROID_BINDER_IPC | |||
22 | config ANDROID_BINDER_DEVICES | 22 | config ANDROID_BINDER_DEVICES |
23 | string "Android Binder devices" | 23 | string "Android Binder devices" |
24 | depends on ANDROID_BINDER_IPC | 24 | depends on ANDROID_BINDER_IPC |
25 | default "binder" | 25 | default "binder,hwbinder" |
26 | ---help--- | 26 | ---help--- |
27 | Default value for the binder.devices parameter. | 27 | Default value for the binder.devices parameter. |
28 | 28 | ||
diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index 8a8e403644d6..9ae6681c90ad 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig | |||
@@ -13,8 +13,22 @@ menuconfig AUXDISPLAY | |||
13 | 13 | ||
14 | If you say N, all options in this submenu will be skipped and disabled. | 14 | If you say N, all options in this submenu will be skipped and disabled. |
15 | 15 | ||
16 | config CHARLCD | ||
17 | tristate "Character LCD core support" if COMPILE_TEST | ||
18 | |||
16 | if AUXDISPLAY | 19 | if AUXDISPLAY |
17 | 20 | ||
21 | config HD44780 | ||
22 | tristate "HD44780 Character LCD support" | ||
23 | depends on GPIOLIB || COMPILE_TEST | ||
24 | select CHARLCD | ||
25 | ---help--- | ||
26 | Enable support for Character LCDs using a HD44780 controller. | ||
27 | The LCD is accessible through the /dev/lcd char device (10, 156). | ||
28 | This code can either be compiled as a module, or linked into the | ||
29 | kernel and started at boot. | ||
30 | If you don't understand what all this is about, say N. | ||
31 | |||
18 | config KS0108 | 32 | config KS0108 |
19 | tristate "KS0108 LCD Controller" | 33 | tristate "KS0108 LCD Controller" |
20 | depends on PARPORT_PC | 34 | depends on PARPORT_PC |
@@ -142,3 +156,293 @@ config HT16K33 | |||
142 | LED controller driver with keyscan. | 156 | LED controller driver with keyscan. |
143 | 157 | ||
144 | endif # AUXDISPLAY | 158 | endif # AUXDISPLAY |
159 | |||
160 | config ARM_CHARLCD | ||
161 | bool "ARM Ltd. Character LCD Driver" | ||
162 | depends on PLAT_VERSATILE | ||
163 | help | ||
164 | This is a driver for the character LCD found on the ARM Ltd. | ||
165 | Versatile and RealView Platform Baseboards. It doesn't do | ||
166 | very much more than display the text "ARM Linux" on the first | ||
167 | line and the Linux version on the second line, but that's | ||
168 | still useful. | ||
169 | |||
170 | config PANEL | ||
171 | tristate "Parallel port LCD/Keypad Panel support" | ||
172 | depends on PARPORT | ||
173 | select CHARLCD | ||
174 | ---help--- | ||
175 | Say Y here if you have an HD44780 or KS-0074 LCD connected to your | ||
176 | parallel port. This driver also features 4 and 6-key keypads. The LCD | ||
177 | is accessible through the /dev/lcd char device (10, 156), and the | ||
178 | keypad through /dev/keypad (10, 185). This code can either be | ||
179 | compiled as a module, or linked into the kernel and started at boot. | ||
180 | If you don't understand what all this is about, say N. | ||
181 | |||
182 | if PANEL | ||
183 | |||
184 | config PANEL_PARPORT | ||
185 | int "Default parallel port number (0=LPT1)" | ||
186 | range 0 255 | ||
187 | default "0" | ||
188 | ---help--- | ||
189 | This is the index of the parallel port the panel is connected to. One | ||
190 | driver instance only supports one parallel port, so if your keypad | ||
191 | and LCD are connected to two separate ports, you have to start two | ||
192 | modules with different arguments. Numbering starts with '0' for LPT1, | ||
193 | and so on. | ||
194 | |||
195 | config PANEL_PROFILE | ||
196 | int "Default panel profile (0-5, 0=custom)" | ||
197 | range 0 5 | ||
198 | default "5" | ||
199 | ---help--- | ||
200 | To ease configuration, the driver supports different configuration | ||
201 | profiles for past and recent wirings. These profiles can also be | ||
202 | used to define an approximative configuration, completed by a few | ||
203 | other options. Here are the profiles : | ||
204 | |||
205 | 0 = custom (see further) | ||
206 | 1 = 2x16 parallel LCD, old keypad | ||
207 | 2 = 2x16 serial LCD (KS-0074), new keypad | ||
208 | 3 = 2x16 parallel LCD (Hantronix), no keypad | ||
209 | 4 = 2x16 parallel LCD (Nexcom NSA1045) with Nexcom's keypad | ||
210 | 5 = 2x40 parallel LCD (old one), with old keypad | ||
211 | |||
212 | Custom configurations allow you to define how your display is | ||
213 | wired to the parallel port, and how it works. This is only intended | ||
214 | for experts. | ||
215 | |||
216 | config PANEL_KEYPAD | ||
217 | depends on PANEL_PROFILE="0" | ||
218 | int "Keypad type (0=none, 1=old 6 keys, 2=new 6 keys, 3=Nexcom 4 keys)" | ||
219 | range 0 3 | ||
220 | default 0 | ||
221 | ---help--- | ||
222 | This enables and configures a keypad connected to the parallel port. | ||
223 | The keys will be read from character device 10,185. Valid values are : | ||
224 | |||
225 | 0 : do not enable this driver | ||
226 | 1 : old 6 keys keypad | ||
227 | 2 : new 6 keys keypad, as used on the server at www.ant-computing.com | ||
228 | 3 : Nexcom NSA1045's 4 keys keypad | ||
229 | |||
230 | New profiles can be described in the driver source. The driver also | ||
231 | supports simultaneous keys pressed when the keypad supports them. | ||
232 | |||
233 | config PANEL_LCD | ||
234 | depends on PANEL_PROFILE="0" | ||
235 | int "LCD type (0=none, 1=custom, 2=old //, 3=ks0074, 4=hantronix, 5=Nexcom)" | ||
236 | range 0 5 | ||
237 | default 0 | ||
238 | ---help--- | ||
239 | This enables and configures an LCD connected to the parallel port. | ||
240 | The driver includes an interpreter for escape codes starting with | ||
241 | '\e[L' which are specific to the LCD, and a few ANSI codes. The | ||
242 | driver will be registered as character device 10,156, usually | ||
243 | under the name '/dev/lcd'. There are a total of 6 supported types : | ||
244 | |||
245 | 0 : do not enable the driver | ||
246 | 1 : custom configuration and wiring (see further) | ||
247 | 2 : 2x16 & 2x40 parallel LCD (old wiring) | ||
248 | 3 : 2x16 serial LCD (KS-0074 based) | ||
249 | 4 : 2x16 parallel LCD (Hantronix wiring) | ||
250 | 5 : 2x16 parallel LCD (Nexcom wiring) | ||
251 | |||
252 | When type '1' is specified, other options will appear to configure | ||
253 | more precise aspects (wiring, dimensions, protocol, ...). Please note | ||
254 | that those values changed from the 2.4 driver for better consistency. | ||
255 | |||
256 | config PANEL_LCD_HEIGHT | ||
257 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" | ||
258 | int "Number of lines on the LCD (1-2)" | ||
259 | range 1 2 | ||
260 | default 2 | ||
261 | ---help--- | ||
262 | This is the number of visible character lines on the LCD in custom profile. | ||
263 | It can either be 1 or 2. | ||
264 | |||
265 | config PANEL_LCD_WIDTH | ||
266 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" | ||
267 | int "Number of characters per line on the LCD (1-40)" | ||
268 | range 1 40 | ||
269 | default 40 | ||
270 | ---help--- | ||
271 | This is the number of characters per line on the LCD in custom profile. | ||
272 | Common values are 16,20,24,40. | ||
273 | |||
274 | config PANEL_LCD_BWIDTH | ||
275 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" | ||
276 | int "Internal LCD line width (1-40, 40 by default)" | ||
277 | range 1 40 | ||
278 | default 40 | ||
279 | ---help--- | ||
280 | Most LCDs use a standard controller which supports hardware lines of 40 | ||
281 | characters, although sometimes only 16, 20 or 24 of them are really wired | ||
282 | to the terminal. This results in some non-visible but addressable characters, | ||
283 | and is the case for most parallel LCDs. Other LCDs, and some serial ones, | ||
284 | however, use the same line width internally as what is visible. The KS0074 | ||
285 | for example, uses 16 characters per line for 16 visible characters per line. | ||
286 | |||
287 | This option lets you configure the value used by your LCD in 'custom' profile. | ||
288 | If you don't know, put '40' here. | ||
289 | |||
290 | config PANEL_LCD_HWIDTH | ||
291 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" | ||
292 | int "Hardware LCD line width (1-64, 64 by default)" | ||
293 | range 1 64 | ||
294 | default 64 | ||
295 | ---help--- | ||
296 | Most LCDs use a single address bit to differentiate line 0 and line 1. Since | ||
297 | some of them need to be able to address 40 chars with the lower bits, they | ||
298 | often use the immediately superior power of 2, which is 64, to address the | ||
299 | next line. | ||
300 | |||
301 | If you don't know what your LCD uses, in doubt let 16 here for a 2x16, and | ||
302 | 64 here for a 2x40. | ||
303 | |||
304 | config PANEL_LCD_CHARSET | ||
305 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" | ||
306 | int "LCD character set (0=normal, 1=KS0074)" | ||
307 | range 0 1 | ||
308 | default 0 | ||
309 | ---help--- | ||
310 | Some controllers such as the KS0074 use a somewhat strange character set | ||
311 | where many symbols are at unusual places. The driver knows how to map | ||
312 | 'standard' ASCII characters to the character sets used by these controllers. | ||
313 | Valid values are : | ||
314 | |||
315 | 0 : normal (untranslated) character set | ||
316 | 1 : KS0074 character set | ||
317 | |||
318 | If you don't know, use the normal one (0). | ||
319 | |||
320 | config PANEL_LCD_PROTO | ||
321 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" | ||
322 | int "LCD communication mode (0=parallel 8 bits, 1=serial)" | ||
323 | range 0 1 | ||
324 | default 0 | ||
325 | ---help--- | ||
326 | This driver now supports any serial or parallel LCD wired to a parallel | ||
327 | port. But before assigning signals, the driver needs to know if it will | ||
328 | be driving a serial LCD or a parallel one. Serial LCDs only use 2 wires | ||
329 | (SDA/SCL), while parallel ones use 2 or 3 wires for the control signals | ||
330 | (E, RS, sometimes RW), and 4 or 8 for the data. Use 0 here for a 8 bits | ||
331 | parallel LCD, and 1 for a serial LCD. | ||
332 | |||
333 | config PANEL_LCD_PIN_E | ||
334 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" | ||
335 | int "Parallel port pin number & polarity connected to the LCD E signal (-17...17) " | ||
336 | range -17 17 | ||
337 | default 14 | ||
338 | ---help--- | ||
339 | This describes the number of the parallel port pin to which the LCD 'E' | ||
340 | signal has been connected. It can be : | ||
341 | |||
342 | 0 : no connection (eg: connected to ground) | ||
343 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
344 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
345 | |||
346 | Default for the 'E' pin in custom profile is '14' (AUTOFEED). | ||
347 | |||
348 | config PANEL_LCD_PIN_RS | ||
349 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" | ||
350 | int "Parallel port pin number & polarity connected to the LCD RS signal (-17...17) " | ||
351 | range -17 17 | ||
352 | default 17 | ||
353 | ---help--- | ||
354 | This describes the number of the parallel port pin to which the LCD 'RS' | ||
355 | signal has been connected. It can be : | ||
356 | |||
357 | 0 : no connection (eg: connected to ground) | ||
358 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
359 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
360 | |||
361 | Default for the 'RS' pin in custom profile is '17' (SELECT IN). | ||
362 | |||
363 | config PANEL_LCD_PIN_RW | ||
364 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" | ||
365 | int "Parallel port pin number & polarity connected to the LCD RW signal (-17...17) " | ||
366 | range -17 17 | ||
367 | default 16 | ||
368 | ---help--- | ||
369 | This describes the number of the parallel port pin to which the LCD 'RW' | ||
370 | signal has been connected. It can be : | ||
371 | |||
372 | 0 : no connection (eg: connected to ground) | ||
373 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
374 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
375 | |||
376 | Default for the 'RW' pin in custom profile is '16' (INIT). | ||
377 | |||
378 | config PANEL_LCD_PIN_SCL | ||
379 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0" | ||
380 | int "Parallel port pin number & polarity connected to the LCD SCL signal (-17...17) " | ||
381 | range -17 17 | ||
382 | default 1 | ||
383 | ---help--- | ||
384 | This describes the number of the parallel port pin to which the serial | ||
385 | LCD 'SCL' signal has been connected. It can be : | ||
386 | |||
387 | 0 : no connection (eg: connected to ground) | ||
388 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
389 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
390 | |||
391 | Default for the 'SCL' pin in custom profile is '1' (STROBE). | ||
392 | |||
393 | config PANEL_LCD_PIN_SDA | ||
394 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0" | ||
395 | int "Parallel port pin number & polarity connected to the LCD SDA signal (-17...17) " | ||
396 | range -17 17 | ||
397 | default 2 | ||
398 | ---help--- | ||
399 | This describes the number of the parallel port pin to which the serial | ||
400 | LCD 'SDA' signal has been connected. It can be : | ||
401 | |||
402 | 0 : no connection (eg: connected to ground) | ||
403 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
404 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
405 | |||
406 | Default for the 'SDA' pin in custom profile is '2' (D0). | ||
407 | |||
408 | config PANEL_LCD_PIN_BL | ||
409 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" | ||
410 | int "Parallel port pin number & polarity connected to the LCD backlight signal (-17...17) " | ||
411 | range -17 17 | ||
412 | default 0 | ||
413 | ---help--- | ||
414 | This describes the number of the parallel port pin to which the LCD 'BL' signal | ||
415 | has been connected. It can be : | ||
416 | |||
417 | 0 : no connection (eg: connected to ground) | ||
418 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
419 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
420 | |||
421 | Default for the 'BL' pin in custom profile is '0' (uncontrolled). | ||
422 | |||
423 | config PANEL_CHANGE_MESSAGE | ||
424 | bool "Change LCD initialization message ?" | ||
425 | default "n" | ||
426 | ---help--- | ||
427 | This allows you to replace the boot message indicating the kernel version | ||
428 | and the driver version with a custom message. This is useful on appliances | ||
429 | where a simple 'Starting system' message can be enough to stop a customer | ||
430 | from worrying. | ||
431 | |||
432 | If you say 'Y' here, you'll be able to choose a message yourself. Otherwise, | ||
433 | say 'N' and keep the default message with the version. | ||
434 | |||
435 | config PANEL_BOOT_MESSAGE | ||
436 | depends on PANEL_CHANGE_MESSAGE="y" | ||
437 | string "New initialization message" | ||
438 | default "" | ||
439 | ---help--- | ||
440 | This allows you to replace the boot message indicating the kernel version | ||
441 | and the driver version with a custom message. This is useful on appliances | ||
442 | where a simple 'Starting system' message can be enough to stop a customer | ||
443 | from worrying. | ||
444 | |||
445 | An empty message will only clear the display at driver init time. Any other | ||
446 | printf()-formatted message is valid with newline and escape codes. | ||
447 | |||
448 | endif # PANEL | ||
diff --git a/drivers/auxdisplay/Makefile b/drivers/auxdisplay/Makefile index cb3dd847713b..2b8af3dc5e42 100644 --- a/drivers/auxdisplay/Makefile +++ b/drivers/auxdisplay/Makefile | |||
@@ -2,7 +2,11 @@ | |||
2 | # Makefile for the kernel auxiliary displays device drivers. | 2 | # Makefile for the kernel auxiliary displays device drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_CHARLCD) += charlcd.o | ||
6 | obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o | ||
5 | obj-$(CONFIG_KS0108) += ks0108.o | 7 | obj-$(CONFIG_KS0108) += ks0108.o |
6 | obj-$(CONFIG_CFAG12864B) += cfag12864b.o cfag12864bfb.o | 8 | obj-$(CONFIG_CFAG12864B) += cfag12864b.o cfag12864bfb.o |
7 | obj-$(CONFIG_IMG_ASCII_LCD) += img-ascii-lcd.o | 9 | obj-$(CONFIG_IMG_ASCII_LCD) += img-ascii-lcd.o |
10 | obj-$(CONFIG_HD44780) += hd44780.o | ||
8 | obj-$(CONFIG_HT16K33) += ht16k33.o | 11 | obj-$(CONFIG_HT16K33) += ht16k33.o |
12 | obj-$(CONFIG_PANEL) += panel.o | ||
diff --git a/drivers/misc/arm-charlcd.c b/drivers/auxdisplay/arm-charlcd.c index b3176ee92b90..b3176ee92b90 100644 --- a/drivers/misc/arm-charlcd.c +++ b/drivers/auxdisplay/arm-charlcd.c | |||
diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c new file mode 100644 index 000000000000..cfeb049a01ef --- /dev/null +++ b/drivers/auxdisplay/charlcd.c | |||
@@ -0,0 +1,818 @@ | |||
1 | /* | ||
2 | * Character LCD driver for Linux | ||
3 | * | ||
4 | * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu> | ||
5 | * Copyright (C) 2016-2017 Glider bvba | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/atomic.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/fs.h> | ||
16 | #include <linux/miscdevice.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/notifier.h> | ||
19 | #include <linux/reboot.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/uaccess.h> | ||
22 | #include <linux/workqueue.h> | ||
23 | |||
24 | #include <generated/utsrelease.h> | ||
25 | |||
26 | #include <misc/charlcd.h> | ||
27 | |||
28 | #define LCD_MINOR 156 | ||
29 | |||
30 | #define DEFAULT_LCD_BWIDTH 40 | ||
31 | #define DEFAULT_LCD_HWIDTH 64 | ||
32 | |||
33 | /* Keep the backlight on this many seconds for each flash */ | ||
34 | #define LCD_BL_TEMPO_PERIOD 4 | ||
35 | |||
36 | #define LCD_FLAG_B 0x0004 /* Blink on */ | ||
37 | #define LCD_FLAG_C 0x0008 /* Cursor on */ | ||
38 | #define LCD_FLAG_D 0x0010 /* Display on */ | ||
39 | #define LCD_FLAG_F 0x0020 /* Large font mode */ | ||
40 | #define LCD_FLAG_N 0x0040 /* 2-rows mode */ | ||
41 | #define LCD_FLAG_L 0x0080 /* Backlight enabled */ | ||
42 | |||
43 | /* LCD commands */ | ||
44 | #define LCD_CMD_DISPLAY_CLEAR 0x01 /* Clear entire display */ | ||
45 | |||
46 | #define LCD_CMD_ENTRY_MODE 0x04 /* Set entry mode */ | ||
47 | #define LCD_CMD_CURSOR_INC 0x02 /* Increment cursor */ | ||
48 | |||
49 | #define LCD_CMD_DISPLAY_CTRL 0x08 /* Display control */ | ||
50 | #define LCD_CMD_DISPLAY_ON 0x04 /* Set display on */ | ||
51 | #define LCD_CMD_CURSOR_ON 0x02 /* Set cursor on */ | ||
52 | #define LCD_CMD_BLINK_ON 0x01 /* Set blink on */ | ||
53 | |||
54 | #define LCD_CMD_SHIFT 0x10 /* Shift cursor/display */ | ||
55 | #define LCD_CMD_DISPLAY_SHIFT 0x08 /* Shift display instead of cursor */ | ||
56 | #define LCD_CMD_SHIFT_RIGHT 0x04 /* Shift display/cursor to the right */ | ||
57 | |||
58 | #define LCD_CMD_FUNCTION_SET 0x20 /* Set function */ | ||
59 | #define LCD_CMD_DATA_LEN_8BITS 0x10 /* Set data length to 8 bits */ | ||
60 | #define LCD_CMD_TWO_LINES 0x08 /* Set to two display lines */ | ||
61 | #define LCD_CMD_FONT_5X10_DOTS 0x04 /* Set char font to 5x10 dots */ | ||
62 | |||
63 | #define LCD_CMD_SET_CGRAM_ADDR 0x40 /* Set char generator RAM address */ | ||
64 | |||
65 | #define LCD_CMD_SET_DDRAM_ADDR 0x80 /* Set display data RAM address */ | ||
66 | |||
67 | #define LCD_ESCAPE_LEN 24 /* Max chars for LCD escape command */ | ||
68 | #define LCD_ESCAPE_CHAR 27 /* Use char 27 for escape command */ | ||
69 | |||
70 | struct charlcd_priv { | ||
71 | struct charlcd lcd; | ||
72 | |||
73 | struct delayed_work bl_work; | ||
74 | struct mutex bl_tempo_lock; /* Protects access to bl_tempo */ | ||
75 | bool bl_tempo; | ||
76 | |||
77 | bool must_clear; | ||
78 | |||
79 | /* contains the LCD config state */ | ||
80 | unsigned long int flags; | ||
81 | |||
82 | /* Contains the LCD X and Y offset */ | ||
83 | struct { | ||
84 | unsigned long int x; | ||
85 | unsigned long int y; | ||
86 | } addr; | ||
87 | |||
88 | /* Current escape sequence and it's length or -1 if outside */ | ||
89 | struct { | ||
90 | char buf[LCD_ESCAPE_LEN + 1]; | ||
91 | int len; | ||
92 | } esc_seq; | ||
93 | |||
94 | unsigned long long drvdata[0]; | ||
95 | }; | ||
96 | |||
97 | #define to_priv(p) container_of(p, struct charlcd_priv, lcd) | ||
98 | |||
99 | /* Device single-open policy control */ | ||
100 | static atomic_t charlcd_available = ATOMIC_INIT(1); | ||
101 | |||
102 | /* sleeps that many milliseconds with a reschedule */ | ||
103 | static void long_sleep(int ms) | ||
104 | { | ||
105 | if (in_interrupt()) | ||
106 | mdelay(ms); | ||
107 | else | ||
108 | schedule_timeout_interruptible(msecs_to_jiffies(ms)); | ||
109 | } | ||
110 | |||
111 | /* turn the backlight on or off */ | ||
112 | static void charlcd_backlight(struct charlcd *lcd, int on) | ||
113 | { | ||
114 | struct charlcd_priv *priv = to_priv(lcd); | ||
115 | |||
116 | if (!lcd->ops->backlight) | ||
117 | return; | ||
118 | |||
119 | mutex_lock(&priv->bl_tempo_lock); | ||
120 | if (!priv->bl_tempo) | ||
121 | lcd->ops->backlight(lcd, on); | ||
122 | mutex_unlock(&priv->bl_tempo_lock); | ||
123 | } | ||
124 | |||
125 | static void charlcd_bl_off(struct work_struct *work) | ||
126 | { | ||
127 | struct delayed_work *dwork = to_delayed_work(work); | ||
128 | struct charlcd_priv *priv = | ||
129 | container_of(dwork, struct charlcd_priv, bl_work); | ||
130 | |||
131 | mutex_lock(&priv->bl_tempo_lock); | ||
132 | if (priv->bl_tempo) { | ||
133 | priv->bl_tempo = false; | ||
134 | if (!(priv->flags & LCD_FLAG_L)) | ||
135 | priv->lcd.ops->backlight(&priv->lcd, 0); | ||
136 | } | ||
137 | mutex_unlock(&priv->bl_tempo_lock); | ||
138 | } | ||
139 | |||
140 | /* turn the backlight on for a little while */ | ||
141 | void charlcd_poke(struct charlcd *lcd) | ||
142 | { | ||
143 | struct charlcd_priv *priv = to_priv(lcd); | ||
144 | |||
145 | if (!lcd->ops->backlight) | ||
146 | return; | ||
147 | |||
148 | cancel_delayed_work_sync(&priv->bl_work); | ||
149 | |||
150 | mutex_lock(&priv->bl_tempo_lock); | ||
151 | if (!priv->bl_tempo && !(priv->flags & LCD_FLAG_L)) | ||
152 | lcd->ops->backlight(lcd, 1); | ||
153 | priv->bl_tempo = true; | ||
154 | schedule_delayed_work(&priv->bl_work, LCD_BL_TEMPO_PERIOD * HZ); | ||
155 | mutex_unlock(&priv->bl_tempo_lock); | ||
156 | } | ||
157 | EXPORT_SYMBOL_GPL(charlcd_poke); | ||
158 | |||
159 | static void charlcd_gotoxy(struct charlcd *lcd) | ||
160 | { | ||
161 | struct charlcd_priv *priv = to_priv(lcd); | ||
162 | unsigned int addr; | ||
163 | |||
164 | /* | ||
165 | * we force the cursor to stay at the end of the | ||
166 | * line if it wants to go farther | ||
167 | */ | ||
168 | addr = priv->addr.x < lcd->bwidth ? priv->addr.x & (lcd->hwidth - 1) | ||
169 | : lcd->bwidth - 1; | ||
170 | if (priv->addr.y & 1) | ||
171 | addr += lcd->hwidth; | ||
172 | if (priv->addr.y & 2) | ||
173 | addr += lcd->bwidth; | ||
174 | lcd->ops->write_cmd(lcd, LCD_CMD_SET_DDRAM_ADDR | addr); | ||
175 | } | ||
176 | |||
177 | static void charlcd_home(struct charlcd *lcd) | ||
178 | { | ||
179 | struct charlcd_priv *priv = to_priv(lcd); | ||
180 | |||
181 | priv->addr.x = 0; | ||
182 | priv->addr.y = 0; | ||
183 | charlcd_gotoxy(lcd); | ||
184 | } | ||
185 | |||
186 | static void charlcd_print(struct charlcd *lcd, char c) | ||
187 | { | ||
188 | struct charlcd_priv *priv = to_priv(lcd); | ||
189 | |||
190 | if (priv->addr.x < lcd->bwidth) { | ||
191 | if (lcd->char_conv) | ||
192 | c = lcd->char_conv[(unsigned char)c]; | ||
193 | lcd->ops->write_data(lcd, c); | ||
194 | priv->addr.x++; | ||
195 | } | ||
196 | /* prevents the cursor from wrapping onto the next line */ | ||
197 | if (priv->addr.x == lcd->bwidth) | ||
198 | charlcd_gotoxy(lcd); | ||
199 | } | ||
200 | |||
201 | static void charlcd_clear_fast(struct charlcd *lcd) | ||
202 | { | ||
203 | int pos; | ||
204 | |||
205 | charlcd_home(lcd); | ||
206 | |||
207 | if (lcd->ops->clear_fast) | ||
208 | lcd->ops->clear_fast(lcd); | ||
209 | else | ||
210 | for (pos = 0; pos < min(2, lcd->height) * lcd->hwidth; pos++) | ||
211 | lcd->ops->write_data(lcd, ' '); | ||
212 | |||
213 | charlcd_home(lcd); | ||
214 | } | ||
215 | |||
216 | /* clears the display and resets X/Y */ | ||
217 | static void charlcd_clear_display(struct charlcd *lcd) | ||
218 | { | ||
219 | struct charlcd_priv *priv = to_priv(lcd); | ||
220 | |||
221 | lcd->ops->write_cmd(lcd, LCD_CMD_DISPLAY_CLEAR); | ||
222 | priv->addr.x = 0; | ||
223 | priv->addr.y = 0; | ||
224 | /* we must wait a few milliseconds (15) */ | ||
225 | long_sleep(15); | ||
226 | } | ||
227 | |||
228 | static int charlcd_init_display(struct charlcd *lcd) | ||
229 | { | ||
230 | void (*write_cmd_raw)(struct charlcd *lcd, int cmd); | ||
231 | struct charlcd_priv *priv = to_priv(lcd); | ||
232 | u8 init; | ||
233 | |||
234 | if (lcd->ifwidth != 4 && lcd->ifwidth != 8) | ||
235 | return -EINVAL; | ||
236 | |||
237 | priv->flags = ((lcd->height > 1) ? LCD_FLAG_N : 0) | LCD_FLAG_D | | ||
238 | LCD_FLAG_C | LCD_FLAG_B; | ||
239 | |||
240 | long_sleep(20); /* wait 20 ms after power-up for the paranoid */ | ||
241 | |||
242 | /* | ||
243 | * 8-bit mode, 1 line, small fonts; let's do it 3 times, to make sure | ||
244 | * the LCD is in 8-bit mode afterwards | ||
245 | */ | ||
246 | init = LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS; | ||
247 | if (lcd->ifwidth == 4) { | ||
248 | init >>= 4; | ||
249 | write_cmd_raw = lcd->ops->write_cmd_raw4; | ||
250 | } else { | ||
251 | write_cmd_raw = lcd->ops->write_cmd; | ||
252 | } | ||
253 | write_cmd_raw(lcd, init); | ||
254 | long_sleep(10); | ||
255 | write_cmd_raw(lcd, init); | ||
256 | long_sleep(10); | ||
257 | write_cmd_raw(lcd, init); | ||
258 | long_sleep(10); | ||
259 | |||
260 | if (lcd->ifwidth == 4) { | ||
261 | /* Switch to 4-bit mode, 1 line, small fonts */ | ||
262 | lcd->ops->write_cmd_raw4(lcd, LCD_CMD_FUNCTION_SET >> 4); | ||
263 | long_sleep(10); | ||
264 | } | ||
265 | |||
266 | /* set font height and lines number */ | ||
267 | lcd->ops->write_cmd(lcd, | ||
268 | LCD_CMD_FUNCTION_SET | | ||
269 | ((lcd->ifwidth == 8) ? LCD_CMD_DATA_LEN_8BITS : 0) | | ||
270 | ((priv->flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0) | | ||
271 | ((priv->flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0)); | ||
272 | long_sleep(10); | ||
273 | |||
274 | /* display off, cursor off, blink off */ | ||
275 | lcd->ops->write_cmd(lcd, LCD_CMD_DISPLAY_CTRL); | ||
276 | long_sleep(10); | ||
277 | |||
278 | lcd->ops->write_cmd(lcd, | ||
279 | LCD_CMD_DISPLAY_CTRL | /* set display mode */ | ||
280 | ((priv->flags & LCD_FLAG_D) ? LCD_CMD_DISPLAY_ON : 0) | | ||
281 | ((priv->flags & LCD_FLAG_C) ? LCD_CMD_CURSOR_ON : 0) | | ||
282 | ((priv->flags & LCD_FLAG_B) ? LCD_CMD_BLINK_ON : 0)); | ||
283 | |||
284 | charlcd_backlight(lcd, (priv->flags & LCD_FLAG_L) ? 1 : 0); | ||
285 | |||
286 | long_sleep(10); | ||
287 | |||
288 | /* entry mode set : increment, cursor shifting */ | ||
289 | lcd->ops->write_cmd(lcd, LCD_CMD_ENTRY_MODE | LCD_CMD_CURSOR_INC); | ||
290 | |||
291 | charlcd_clear_display(lcd); | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * These are the file operation function for user access to /dev/lcd | ||
297 | * This function can also be called from inside the kernel, by | ||
298 | * setting file and ppos to NULL. | ||
299 | * | ||
300 | */ | ||
301 | |||
302 | static inline int handle_lcd_special_code(struct charlcd *lcd) | ||
303 | { | ||
304 | struct charlcd_priv *priv = to_priv(lcd); | ||
305 | |||
306 | /* LCD special codes */ | ||
307 | |||
308 | int processed = 0; | ||
309 | |||
310 | char *esc = priv->esc_seq.buf + 2; | ||
311 | int oldflags = priv->flags; | ||
312 | |||
313 | /* check for display mode flags */ | ||
314 | switch (*esc) { | ||
315 | case 'D': /* Display ON */ | ||
316 | priv->flags |= LCD_FLAG_D; | ||
317 | processed = 1; | ||
318 | break; | ||
319 | case 'd': /* Display OFF */ | ||
320 | priv->flags &= ~LCD_FLAG_D; | ||
321 | processed = 1; | ||
322 | break; | ||
323 | case 'C': /* Cursor ON */ | ||
324 | priv->flags |= LCD_FLAG_C; | ||
325 | processed = 1; | ||
326 | break; | ||
327 | case 'c': /* Cursor OFF */ | ||
328 | priv->flags &= ~LCD_FLAG_C; | ||
329 | processed = 1; | ||
330 | break; | ||
331 | case 'B': /* Blink ON */ | ||
332 | priv->flags |= LCD_FLAG_B; | ||
333 | processed = 1; | ||
334 | break; | ||
335 | case 'b': /* Blink OFF */ | ||
336 | priv->flags &= ~LCD_FLAG_B; | ||
337 | processed = 1; | ||
338 | break; | ||
339 | case '+': /* Back light ON */ | ||
340 | priv->flags |= LCD_FLAG_L; | ||
341 | processed = 1; | ||
342 | break; | ||
343 | case '-': /* Back light OFF */ | ||
344 | priv->flags &= ~LCD_FLAG_L; | ||
345 | processed = 1; | ||
346 | break; | ||
347 | case '*': /* Flash back light */ | ||
348 | charlcd_poke(lcd); | ||
349 | processed = 1; | ||
350 | break; | ||
351 | case 'f': /* Small Font */ | ||
352 | priv->flags &= ~LCD_FLAG_F; | ||
353 | processed = 1; | ||
354 | break; | ||
355 | case 'F': /* Large Font */ | ||
356 | priv->flags |= LCD_FLAG_F; | ||
357 | processed = 1; | ||
358 | break; | ||
359 | case 'n': /* One Line */ | ||
360 | priv->flags &= ~LCD_FLAG_N; | ||
361 | processed = 1; | ||
362 | break; | ||
363 | case 'N': /* Two Lines */ | ||
364 | priv->flags |= LCD_FLAG_N; | ||
365 | break; | ||
366 | case 'l': /* Shift Cursor Left */ | ||
367 | if (priv->addr.x > 0) { | ||
368 | /* back one char if not at end of line */ | ||
369 | if (priv->addr.x < lcd->bwidth) | ||
370 | lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT); | ||
371 | priv->addr.x--; | ||
372 | } | ||
373 | processed = 1; | ||
374 | break; | ||
375 | case 'r': /* shift cursor right */ | ||
376 | if (priv->addr.x < lcd->width) { | ||
377 | /* allow the cursor to pass the end of the line */ | ||
378 | if (priv->addr.x < (lcd->bwidth - 1)) | ||
379 | lcd->ops->write_cmd(lcd, | ||
380 | LCD_CMD_SHIFT | LCD_CMD_SHIFT_RIGHT); | ||
381 | priv->addr.x++; | ||
382 | } | ||
383 | processed = 1; | ||
384 | break; | ||
385 | case 'L': /* shift display left */ | ||
386 | lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT); | ||
387 | processed = 1; | ||
388 | break; | ||
389 | case 'R': /* shift display right */ | ||
390 | lcd->ops->write_cmd(lcd, | ||
391 | LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT | | ||
392 | LCD_CMD_SHIFT_RIGHT); | ||
393 | processed = 1; | ||
394 | break; | ||
395 | case 'k': { /* kill end of line */ | ||
396 | int x; | ||
397 | |||
398 | for (x = priv->addr.x; x < lcd->bwidth; x++) | ||
399 | lcd->ops->write_data(lcd, ' '); | ||
400 | |||
401 | /* restore cursor position */ | ||
402 | charlcd_gotoxy(lcd); | ||
403 | processed = 1; | ||
404 | break; | ||
405 | } | ||
406 | case 'I': /* reinitialize display */ | ||
407 | charlcd_init_display(lcd); | ||
408 | processed = 1; | ||
409 | break; | ||
410 | case 'G': { | ||
411 | /* Generator : LGcxxxxx...xx; must have <c> between '0' | ||
412 | * and '7', representing the numerical ASCII code of the | ||
413 | * redefined character, and <xx...xx> a sequence of 16 | ||
414 | * hex digits representing 8 bytes for each character. | ||
415 | * Most LCDs will only use 5 lower bits of the 7 first | ||
416 | * bytes. | ||
417 | */ | ||
418 | |||
419 | unsigned char cgbytes[8]; | ||
420 | unsigned char cgaddr; | ||
421 | int cgoffset; | ||
422 | int shift; | ||
423 | char value; | ||
424 | int addr; | ||
425 | |||
426 | if (!strchr(esc, ';')) | ||
427 | break; | ||
428 | |||
429 | esc++; | ||
430 | |||
431 | cgaddr = *(esc++) - '0'; | ||
432 | if (cgaddr > 7) { | ||
433 | processed = 1; | ||
434 | break; | ||
435 | } | ||
436 | |||
437 | cgoffset = 0; | ||
438 | shift = 0; | ||
439 | value = 0; | ||
440 | while (*esc && cgoffset < 8) { | ||
441 | shift ^= 4; | ||
442 | if (*esc >= '0' && *esc <= '9') { | ||
443 | value |= (*esc - '0') << shift; | ||
444 | } else if (*esc >= 'A' && *esc <= 'Z') { | ||
445 | value |= (*esc - 'A' + 10) << shift; | ||
446 | } else if (*esc >= 'a' && *esc <= 'z') { | ||
447 | value |= (*esc - 'a' + 10) << shift; | ||
448 | } else { | ||
449 | esc++; | ||
450 | continue; | ||
451 | } | ||
452 | |||
453 | if (shift == 0) { | ||
454 | cgbytes[cgoffset++] = value; | ||
455 | value = 0; | ||
456 | } | ||
457 | |||
458 | esc++; | ||
459 | } | ||
460 | |||
461 | lcd->ops->write_cmd(lcd, LCD_CMD_SET_CGRAM_ADDR | (cgaddr * 8)); | ||
462 | for (addr = 0; addr < cgoffset; addr++) | ||
463 | lcd->ops->write_data(lcd, cgbytes[addr]); | ||
464 | |||
465 | /* ensures that we stop writing to CGRAM */ | ||
466 | charlcd_gotoxy(lcd); | ||
467 | processed = 1; | ||
468 | break; | ||
469 | } | ||
470 | case 'x': /* gotoxy : LxXXX[yYYY]; */ | ||
471 | case 'y': /* gotoxy : LyYYY[xXXX]; */ | ||
472 | if (!strchr(esc, ';')) | ||
473 | break; | ||
474 | |||
475 | while (*esc) { | ||
476 | if (*esc == 'x') { | ||
477 | esc++; | ||
478 | if (kstrtoul(esc, 10, &priv->addr.x) < 0) | ||
479 | break; | ||
480 | } else if (*esc == 'y') { | ||
481 | esc++; | ||
482 | if (kstrtoul(esc, 10, &priv->addr.y) < 0) | ||
483 | break; | ||
484 | } else { | ||
485 | break; | ||
486 | } | ||
487 | } | ||
488 | |||
489 | charlcd_gotoxy(lcd); | ||
490 | processed = 1; | ||
491 | break; | ||
492 | } | ||
493 | |||
494 | /* TODO: This indent party here got ugly, clean it! */ | ||
495 | /* Check whether one flag was changed */ | ||
496 | if (oldflags == priv->flags) | ||
497 | return processed; | ||
498 | |||
499 | /* check whether one of B,C,D flags were changed */ | ||
500 | if ((oldflags ^ priv->flags) & | ||
501 | (LCD_FLAG_B | LCD_FLAG_C | LCD_FLAG_D)) | ||
502 | /* set display mode */ | ||
503 | lcd->ops->write_cmd(lcd, | ||
504 | LCD_CMD_DISPLAY_CTRL | | ||
505 | ((priv->flags & LCD_FLAG_D) ? LCD_CMD_DISPLAY_ON : 0) | | ||
506 | ((priv->flags & LCD_FLAG_C) ? LCD_CMD_CURSOR_ON : 0) | | ||
507 | ((priv->flags & LCD_FLAG_B) ? LCD_CMD_BLINK_ON : 0)); | ||
508 | /* check whether one of F,N flags was changed */ | ||
509 | else if ((oldflags ^ priv->flags) & (LCD_FLAG_F | LCD_FLAG_N)) | ||
510 | lcd->ops->write_cmd(lcd, | ||
511 | LCD_CMD_FUNCTION_SET | | ||
512 | ((lcd->ifwidth == 8) ? LCD_CMD_DATA_LEN_8BITS : 0) | | ||
513 | ((priv->flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0) | | ||
514 | ((priv->flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0)); | ||
515 | /* check whether L flag was changed */ | ||
516 | else if ((oldflags ^ priv->flags) & LCD_FLAG_L) | ||
517 | charlcd_backlight(lcd, !!(priv->flags & LCD_FLAG_L)); | ||
518 | |||
519 | return processed; | ||
520 | } | ||
521 | |||
522 | static void charlcd_write_char(struct charlcd *lcd, char c) | ||
523 | { | ||
524 | struct charlcd_priv *priv = to_priv(lcd); | ||
525 | |||
526 | /* first, we'll test if we're in escape mode */ | ||
527 | if ((c != '\n') && priv->esc_seq.len >= 0) { | ||
528 | /* yes, let's add this char to the buffer */ | ||
529 | priv->esc_seq.buf[priv->esc_seq.len++] = c; | ||
530 | priv->esc_seq.buf[priv->esc_seq.len] = 0; | ||
531 | } else { | ||
532 | /* aborts any previous escape sequence */ | ||
533 | priv->esc_seq.len = -1; | ||
534 | |||
535 | switch (c) { | ||
536 | case LCD_ESCAPE_CHAR: | ||
537 | /* start of an escape sequence */ | ||
538 | priv->esc_seq.len = 0; | ||
539 | priv->esc_seq.buf[priv->esc_seq.len] = 0; | ||
540 | break; | ||
541 | case '\b': | ||
542 | /* go back one char and clear it */ | ||
543 | if (priv->addr.x > 0) { | ||
544 | /* | ||
545 | * check if we're not at the | ||
546 | * end of the line | ||
547 | */ | ||
548 | if (priv->addr.x < lcd->bwidth) | ||
549 | /* back one char */ | ||
550 | lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT); | ||
551 | priv->addr.x--; | ||
552 | } | ||
553 | /* replace with a space */ | ||
554 | lcd->ops->write_data(lcd, ' '); | ||
555 | /* back one char again */ | ||
556 | lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT); | ||
557 | break; | ||
558 | case '\014': | ||
559 | /* quickly clear the display */ | ||
560 | charlcd_clear_fast(lcd); | ||
561 | break; | ||
562 | case '\n': | ||
563 | /* | ||
564 | * flush the remainder of the current line and | ||
565 | * go to the beginning of the next line | ||
566 | */ | ||
567 | for (; priv->addr.x < lcd->bwidth; priv->addr.x++) | ||
568 | lcd->ops->write_data(lcd, ' '); | ||
569 | priv->addr.x = 0; | ||
570 | priv->addr.y = (priv->addr.y + 1) % lcd->height; | ||
571 | charlcd_gotoxy(lcd); | ||
572 | break; | ||
573 | case '\r': | ||
574 | /* go to the beginning of the same line */ | ||
575 | priv->addr.x = 0; | ||
576 | charlcd_gotoxy(lcd); | ||
577 | break; | ||
578 | case '\t': | ||
579 | /* print a space instead of the tab */ | ||
580 | charlcd_print(lcd, ' '); | ||
581 | break; | ||
582 | default: | ||
583 | /* simply print this char */ | ||
584 | charlcd_print(lcd, c); | ||
585 | break; | ||
586 | } | ||
587 | } | ||
588 | |||
589 | /* | ||
590 | * now we'll see if we're in an escape mode and if the current | ||
591 | * escape sequence can be understood. | ||
592 | */ | ||
593 | if (priv->esc_seq.len >= 2) { | ||
594 | int processed = 0; | ||
595 | |||
596 | if (!strcmp(priv->esc_seq.buf, "[2J")) { | ||
597 | /* clear the display */ | ||
598 | charlcd_clear_fast(lcd); | ||
599 | processed = 1; | ||
600 | } else if (!strcmp(priv->esc_seq.buf, "[H")) { | ||
601 | /* cursor to home */ | ||
602 | charlcd_home(lcd); | ||
603 | processed = 1; | ||
604 | } | ||
605 | /* codes starting with ^[[L */ | ||
606 | else if ((priv->esc_seq.len >= 3) && | ||
607 | (priv->esc_seq.buf[0] == '[') && | ||
608 | (priv->esc_seq.buf[1] == 'L')) { | ||
609 | processed = handle_lcd_special_code(lcd); | ||
610 | } | ||
611 | |||
612 | /* LCD special escape codes */ | ||
613 | /* | ||
614 | * flush the escape sequence if it's been processed | ||
615 | * or if it is getting too long. | ||
616 | */ | ||
617 | if (processed || (priv->esc_seq.len >= LCD_ESCAPE_LEN)) | ||
618 | priv->esc_seq.len = -1; | ||
619 | } /* escape codes */ | ||
620 | } | ||
621 | |||
622 | static struct charlcd *the_charlcd; | ||
623 | |||
624 | static ssize_t charlcd_write(struct file *file, const char __user *buf, | ||
625 | size_t count, loff_t *ppos) | ||
626 | { | ||
627 | const char __user *tmp = buf; | ||
628 | char c; | ||
629 | |||
630 | for (; count-- > 0; (*ppos)++, tmp++) { | ||
631 | if (!in_interrupt() && (((count + 1) & 0x1f) == 0)) | ||
632 | /* | ||
633 | * let's be a little nice with other processes | ||
634 | * that need some CPU | ||
635 | */ | ||
636 | schedule(); | ||
637 | |||
638 | if (get_user(c, tmp)) | ||
639 | return -EFAULT; | ||
640 | |||
641 | charlcd_write_char(the_charlcd, c); | ||
642 | } | ||
643 | |||
644 | return tmp - buf; | ||
645 | } | ||
646 | |||
647 | static int charlcd_open(struct inode *inode, struct file *file) | ||
648 | { | ||
649 | struct charlcd_priv *priv = to_priv(the_charlcd); | ||
650 | |||
651 | if (!atomic_dec_and_test(&charlcd_available)) | ||
652 | return -EBUSY; /* open only once at a time */ | ||
653 | |||
654 | if (file->f_mode & FMODE_READ) /* device is write-only */ | ||
655 | return -EPERM; | ||
656 | |||
657 | if (priv->must_clear) { | ||
658 | charlcd_clear_display(&priv->lcd); | ||
659 | priv->must_clear = false; | ||
660 | } | ||
661 | return nonseekable_open(inode, file); | ||
662 | } | ||
663 | |||
664 | static int charlcd_release(struct inode *inode, struct file *file) | ||
665 | { | ||
666 | atomic_inc(&charlcd_available); | ||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | static const struct file_operations charlcd_fops = { | ||
671 | .write = charlcd_write, | ||
672 | .open = charlcd_open, | ||
673 | .release = charlcd_release, | ||
674 | .llseek = no_llseek, | ||
675 | }; | ||
676 | |||
677 | static struct miscdevice charlcd_dev = { | ||
678 | .minor = LCD_MINOR, | ||
679 | .name = "lcd", | ||
680 | .fops = &charlcd_fops, | ||
681 | }; | ||
682 | |||
683 | static void charlcd_puts(struct charlcd *lcd, const char *s) | ||
684 | { | ||
685 | const char *tmp = s; | ||
686 | int count = strlen(s); | ||
687 | |||
688 | for (; count-- > 0; tmp++) { | ||
689 | if (!in_interrupt() && (((count + 1) & 0x1f) == 0)) | ||
690 | /* | ||
691 | * let's be a little nice with other processes | ||
692 | * that need some CPU | ||
693 | */ | ||
694 | schedule(); | ||
695 | |||
696 | charlcd_write_char(lcd, *tmp); | ||
697 | } | ||
698 | } | ||
699 | |||
700 | /* initialize the LCD driver */ | ||
701 | static int charlcd_init(struct charlcd *lcd) | ||
702 | { | ||
703 | struct charlcd_priv *priv = to_priv(lcd); | ||
704 | int ret; | ||
705 | |||
706 | if (lcd->ops->backlight) { | ||
707 | mutex_init(&priv->bl_tempo_lock); | ||
708 | INIT_DELAYED_WORK(&priv->bl_work, charlcd_bl_off); | ||
709 | } | ||
710 | |||
711 | /* | ||
712 | * before this line, we must NOT send anything to the display. | ||
713 | * Since charlcd_init_display() needs to write data, we have to | ||
714 | * enable mark the LCD initialized just before. | ||
715 | */ | ||
716 | ret = charlcd_init_display(lcd); | ||
717 | if (ret) | ||
718 | return ret; | ||
719 | |||
720 | /* display a short message */ | ||
721 | #ifdef CONFIG_PANEL_CHANGE_MESSAGE | ||
722 | #ifdef CONFIG_PANEL_BOOT_MESSAGE | ||
723 | charlcd_puts(lcd, "\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE); | ||
724 | #endif | ||
725 | #else | ||
726 | charlcd_puts(lcd, "\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE "\n"); | ||
727 | #endif | ||
728 | /* clear the display on the next device opening */ | ||
729 | priv->must_clear = true; | ||
730 | charlcd_home(lcd); | ||
731 | return 0; | ||
732 | } | ||
733 | |||
734 | struct charlcd *charlcd_alloc(unsigned int drvdata_size) | ||
735 | { | ||
736 | struct charlcd_priv *priv; | ||
737 | struct charlcd *lcd; | ||
738 | |||
739 | priv = kzalloc(sizeof(*priv) + drvdata_size, GFP_KERNEL); | ||
740 | if (!priv) | ||
741 | return NULL; | ||
742 | |||
743 | priv->esc_seq.len = -1; | ||
744 | |||
745 | lcd = &priv->lcd; | ||
746 | lcd->ifwidth = 8; | ||
747 | lcd->bwidth = DEFAULT_LCD_BWIDTH; | ||
748 | lcd->hwidth = DEFAULT_LCD_HWIDTH; | ||
749 | lcd->drvdata = priv->drvdata; | ||
750 | |||
751 | return lcd; | ||
752 | } | ||
753 | EXPORT_SYMBOL_GPL(charlcd_alloc); | ||
754 | |||
755 | static int panel_notify_sys(struct notifier_block *this, unsigned long code, | ||
756 | void *unused) | ||
757 | { | ||
758 | struct charlcd *lcd = the_charlcd; | ||
759 | |||
760 | switch (code) { | ||
761 | case SYS_DOWN: | ||
762 | charlcd_puts(lcd, | ||
763 | "\x0cReloading\nSystem...\x1b[Lc\x1b[Lb\x1b[L+"); | ||
764 | break; | ||
765 | case SYS_HALT: | ||
766 | charlcd_puts(lcd, "\x0cSystem Halted.\x1b[Lc\x1b[Lb\x1b[L+"); | ||
767 | break; | ||
768 | case SYS_POWER_OFF: | ||
769 | charlcd_puts(lcd, "\x0cPower off.\x1b[Lc\x1b[Lb\x1b[L+"); | ||
770 | break; | ||
771 | default: | ||
772 | break; | ||
773 | } | ||
774 | return NOTIFY_DONE; | ||
775 | } | ||
776 | |||
777 | static struct notifier_block panel_notifier = { | ||
778 | panel_notify_sys, | ||
779 | NULL, | ||
780 | 0 | ||
781 | }; | ||
782 | |||
783 | int charlcd_register(struct charlcd *lcd) | ||
784 | { | ||
785 | int ret; | ||
786 | |||
787 | ret = charlcd_init(lcd); | ||
788 | if (ret) | ||
789 | return ret; | ||
790 | |||
791 | ret = misc_register(&charlcd_dev); | ||
792 | if (ret) | ||
793 | return ret; | ||
794 | |||
795 | the_charlcd = lcd; | ||
796 | register_reboot_notifier(&panel_notifier); | ||
797 | return 0; | ||
798 | } | ||
799 | EXPORT_SYMBOL_GPL(charlcd_register); | ||
800 | |||
801 | int charlcd_unregister(struct charlcd *lcd) | ||
802 | { | ||
803 | struct charlcd_priv *priv = to_priv(lcd); | ||
804 | |||
805 | unregister_reboot_notifier(&panel_notifier); | ||
806 | charlcd_puts(lcd, "\x0cLCD driver unloaded.\x1b[Lc\x1b[Lb\x1b[L-"); | ||
807 | misc_deregister(&charlcd_dev); | ||
808 | the_charlcd = NULL; | ||
809 | if (lcd->ops->backlight) { | ||
810 | cancel_delayed_work_sync(&priv->bl_work); | ||
811 | priv->lcd.ops->backlight(&priv->lcd, 0); | ||
812 | } | ||
813 | |||
814 | return 0; | ||
815 | } | ||
816 | EXPORT_SYMBOL_GPL(charlcd_unregister); | ||
817 | |||
818 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c new file mode 100644 index 000000000000..036eec404289 --- /dev/null +++ b/drivers/auxdisplay/hd44780.c | |||
@@ -0,0 +1,326 @@ | |||
1 | /* | ||
2 | * HD44780 Character LCD driver for Linux | ||
3 | * | ||
4 | * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu> | ||
5 | * Copyright (C) 2016-2017 Glider bvba | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/delay.h> | ||
14 | #include <linux/gpio/consumer.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/property.h> | ||
18 | #include <linux/slab.h> | ||
19 | |||
20 | #include <misc/charlcd.h> | ||
21 | |||
22 | |||
23 | enum hd44780_pin { | ||
24 | /* Order does matter due to writing to GPIO array subsets! */ | ||
25 | PIN_DATA0, /* Optional */ | ||
26 | PIN_DATA1, /* Optional */ | ||
27 | PIN_DATA2, /* Optional */ | ||
28 | PIN_DATA3, /* Optional */ | ||
29 | PIN_DATA4, | ||
30 | PIN_DATA5, | ||
31 | PIN_DATA6, | ||
32 | PIN_DATA7, | ||
33 | PIN_CTRL_RS, | ||
34 | PIN_CTRL_RW, /* Optional */ | ||
35 | PIN_CTRL_E, | ||
36 | PIN_CTRL_BL, /* Optional */ | ||
37 | PIN_NUM | ||
38 | }; | ||
39 | |||
40 | struct hd44780 { | ||
41 | struct gpio_desc *pins[PIN_NUM]; | ||
42 | }; | ||
43 | |||
44 | static void hd44780_backlight(struct charlcd *lcd, int on) | ||
45 | { | ||
46 | struct hd44780 *hd = lcd->drvdata; | ||
47 | |||
48 | if (hd->pins[PIN_CTRL_BL]) | ||
49 | gpiod_set_value_cansleep(hd->pins[PIN_CTRL_BL], on); | ||
50 | } | ||
51 | |||
52 | static void hd44780_strobe_gpio(struct hd44780 *hd) | ||
53 | { | ||
54 | /* Maintain the data during 20 us before the strobe */ | ||
55 | udelay(20); | ||
56 | |||
57 | gpiod_set_value_cansleep(hd->pins[PIN_CTRL_E], 1); | ||
58 | |||
59 | /* Maintain the strobe during 40 us */ | ||
60 | udelay(40); | ||
61 | |||
62 | gpiod_set_value_cansleep(hd->pins[PIN_CTRL_E], 0); | ||
63 | } | ||
64 | |||
65 | /* write to an LCD panel register in 8 bit GPIO mode */ | ||
66 | static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs) | ||
67 | { | ||
68 | int values[10]; /* for DATA[0-7], RS, RW */ | ||
69 | unsigned int i, n; | ||
70 | |||
71 | for (i = 0; i < 8; i++) | ||
72 | values[PIN_DATA0 + i] = !!(val & BIT(i)); | ||
73 | values[PIN_CTRL_RS] = rs; | ||
74 | n = 9; | ||
75 | if (hd->pins[PIN_CTRL_RW]) { | ||
76 | values[PIN_CTRL_RW] = 0; | ||
77 | n++; | ||
78 | } | ||
79 | |||
80 | /* Present the data to the port */ | ||
81 | gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], values); | ||
82 | |||
83 | hd44780_strobe_gpio(hd); | ||
84 | } | ||
85 | |||
86 | /* write to an LCD panel register in 4 bit GPIO mode */ | ||
87 | static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs) | ||
88 | { | ||
89 | int values[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */ | ||
90 | unsigned int i, n; | ||
91 | |||
92 | /* High nibble + RS, RW */ | ||
93 | for (i = 4; i < 8; i++) | ||
94 | values[PIN_DATA0 + i] = !!(val & BIT(i)); | ||
95 | values[PIN_CTRL_RS] = rs; | ||
96 | n = 5; | ||
97 | if (hd->pins[PIN_CTRL_RW]) { | ||
98 | values[PIN_CTRL_RW] = 0; | ||
99 | n++; | ||
100 | } | ||
101 | |||
102 | /* Present the data to the port */ | ||
103 | gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], | ||
104 | &values[PIN_DATA4]); | ||
105 | |||
106 | hd44780_strobe_gpio(hd); | ||
107 | |||
108 | /* Low nibble */ | ||
109 | for (i = 0; i < 4; i++) | ||
110 | values[PIN_DATA4 + i] = !!(val & BIT(i)); | ||
111 | |||
112 | /* Present the data to the port */ | ||
113 | gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], | ||
114 | &values[PIN_DATA4]); | ||
115 | |||
116 | hd44780_strobe_gpio(hd); | ||
117 | } | ||
118 | |||
119 | /* Send a command to the LCD panel in 8 bit GPIO mode */ | ||
120 | static void hd44780_write_cmd_gpio8(struct charlcd *lcd, int cmd) | ||
121 | { | ||
122 | struct hd44780 *hd = lcd->drvdata; | ||
123 | |||
124 | hd44780_write_gpio8(hd, cmd, 0); | ||
125 | |||
126 | /* The shortest command takes at least 120 us */ | ||
127 | udelay(120); | ||
128 | } | ||
129 | |||
130 | /* Send data to the LCD panel in 8 bit GPIO mode */ | ||
131 | static void hd44780_write_data_gpio8(struct charlcd *lcd, int data) | ||
132 | { | ||
133 | struct hd44780 *hd = lcd->drvdata; | ||
134 | |||
135 | hd44780_write_gpio8(hd, data, 1); | ||
136 | |||
137 | /* The shortest data takes at least 45 us */ | ||
138 | udelay(45); | ||
139 | } | ||
140 | |||
141 | static const struct charlcd_ops hd44780_ops_gpio8 = { | ||
142 | .write_cmd = hd44780_write_cmd_gpio8, | ||
143 | .write_data = hd44780_write_data_gpio8, | ||
144 | .backlight = hd44780_backlight, | ||
145 | }; | ||
146 | |||
147 | /* Send a command to the LCD panel in 4 bit GPIO mode */ | ||
148 | static void hd44780_write_cmd_gpio4(struct charlcd *lcd, int cmd) | ||
149 | { | ||
150 | struct hd44780 *hd = lcd->drvdata; | ||
151 | |||
152 | hd44780_write_gpio4(hd, cmd, 0); | ||
153 | |||
154 | /* The shortest command takes at least 120 us */ | ||
155 | udelay(120); | ||
156 | } | ||
157 | |||
158 | /* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */ | ||
159 | static void hd44780_write_cmd_raw_gpio4(struct charlcd *lcd, int cmd) | ||
160 | { | ||
161 | int values[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */ | ||
162 | struct hd44780 *hd = lcd->drvdata; | ||
163 | unsigned int i, n; | ||
164 | |||
165 | /* Command nibble + RS, RW */ | ||
166 | for (i = 0; i < 4; i++) | ||
167 | values[PIN_DATA4 + i] = !!(cmd & BIT(i)); | ||
168 | values[PIN_CTRL_RS] = 0; | ||
169 | n = 5; | ||
170 | if (hd->pins[PIN_CTRL_RW]) { | ||
171 | values[PIN_CTRL_RW] = 0; | ||
172 | n++; | ||
173 | } | ||
174 | |||
175 | /* Present the data to the port */ | ||
176 | gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], | ||
177 | &values[PIN_DATA4]); | ||
178 | |||
179 | hd44780_strobe_gpio(hd); | ||
180 | } | ||
181 | |||
182 | /* Send data to the LCD panel in 4 bit GPIO mode */ | ||
183 | static void hd44780_write_data_gpio4(struct charlcd *lcd, int data) | ||
184 | { | ||
185 | struct hd44780 *hd = lcd->drvdata; | ||
186 | |||
187 | hd44780_write_gpio4(hd, data, 1); | ||
188 | |||
189 | /* The shortest data takes at least 45 us */ | ||
190 | udelay(45); | ||
191 | } | ||
192 | |||
193 | static const struct charlcd_ops hd44780_ops_gpio4 = { | ||
194 | .write_cmd = hd44780_write_cmd_gpio4, | ||
195 | .write_cmd_raw4 = hd44780_write_cmd_raw_gpio4, | ||
196 | .write_data = hd44780_write_data_gpio4, | ||
197 | .backlight = hd44780_backlight, | ||
198 | }; | ||
199 | |||
200 | static int hd44780_probe(struct platform_device *pdev) | ||
201 | { | ||
202 | struct device *dev = &pdev->dev; | ||
203 | unsigned int i, base; | ||
204 | struct charlcd *lcd; | ||
205 | struct hd44780 *hd; | ||
206 | int ifwidth, ret; | ||
207 | |||
208 | /* Required pins */ | ||
209 | ifwidth = gpiod_count(dev, "data"); | ||
210 | if (ifwidth < 0) | ||
211 | return ifwidth; | ||
212 | |||
213 | switch (ifwidth) { | ||
214 | case 4: | ||
215 | base = PIN_DATA4; | ||
216 | break; | ||
217 | case 8: | ||
218 | base = PIN_DATA0; | ||
219 | break; | ||
220 | default: | ||
221 | return -EINVAL; | ||
222 | } | ||
223 | |||
224 | lcd = charlcd_alloc(sizeof(struct hd44780)); | ||
225 | if (!lcd) | ||
226 | return -ENOMEM; | ||
227 | |||
228 | hd = lcd->drvdata; | ||
229 | |||
230 | for (i = 0; i < ifwidth; i++) { | ||
231 | hd->pins[base + i] = devm_gpiod_get_index(dev, "data", i, | ||
232 | GPIOD_OUT_LOW); | ||
233 | if (IS_ERR(hd->pins[base + i])) { | ||
234 | ret = PTR_ERR(hd->pins[base + i]); | ||
235 | goto fail; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | hd->pins[PIN_CTRL_E] = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); | ||
240 | if (IS_ERR(hd->pins[PIN_CTRL_E])) { | ||
241 | ret = PTR_ERR(hd->pins[PIN_CTRL_E]); | ||
242 | goto fail; | ||
243 | } | ||
244 | |||
245 | hd->pins[PIN_CTRL_RS] = devm_gpiod_get(dev, "rs", GPIOD_OUT_HIGH); | ||
246 | if (IS_ERR(hd->pins[PIN_CTRL_RS])) { | ||
247 | ret = PTR_ERR(hd->pins[PIN_CTRL_RS]); | ||
248 | goto fail; | ||
249 | } | ||
250 | |||
251 | /* Optional pins */ | ||
252 | hd->pins[PIN_CTRL_RW] = devm_gpiod_get_optional(dev, "rw", | ||
253 | GPIOD_OUT_LOW); | ||
254 | if (IS_ERR(hd->pins[PIN_CTRL_RW])) { | ||
255 | ret = PTR_ERR(hd->pins[PIN_CTRL_RW]); | ||
256 | goto fail; | ||
257 | } | ||
258 | |||
259 | hd->pins[PIN_CTRL_BL] = devm_gpiod_get_optional(dev, "backlight", | ||
260 | GPIOD_OUT_LOW); | ||
261 | if (IS_ERR(hd->pins[PIN_CTRL_BL])) { | ||
262 | ret = PTR_ERR(hd->pins[PIN_CTRL_BL]); | ||
263 | goto fail; | ||
264 | } | ||
265 | |||
266 | /* Required properties */ | ||
267 | ret = device_property_read_u32(dev, "display-height-chars", | ||
268 | &lcd->height); | ||
269 | if (ret) | ||
270 | goto fail; | ||
271 | ret = device_property_read_u32(dev, "display-width-chars", &lcd->width); | ||
272 | if (ret) | ||
273 | goto fail; | ||
274 | |||
275 | /* | ||
276 | * On displays with more than two rows, the internal buffer width is | ||
277 | * usually equal to the display width | ||
278 | */ | ||
279 | if (lcd->height > 2) | ||
280 | lcd->bwidth = lcd->width; | ||
281 | |||
282 | /* Optional properties */ | ||
283 | device_property_read_u32(dev, "internal-buffer-width", &lcd->bwidth); | ||
284 | |||
285 | lcd->ifwidth = ifwidth; | ||
286 | lcd->ops = ifwidth == 8 ? &hd44780_ops_gpio8 : &hd44780_ops_gpio4; | ||
287 | |||
288 | ret = charlcd_register(lcd); | ||
289 | if (ret) | ||
290 | goto fail; | ||
291 | |||
292 | platform_set_drvdata(pdev, lcd); | ||
293 | return 0; | ||
294 | |||
295 | fail: | ||
296 | kfree(lcd); | ||
297 | return ret; | ||
298 | } | ||
299 | |||
300 | static int hd44780_remove(struct platform_device *pdev) | ||
301 | { | ||
302 | struct charlcd *lcd = platform_get_drvdata(pdev); | ||
303 | |||
304 | charlcd_unregister(lcd); | ||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static const struct of_device_id hd44780_of_match[] = { | ||
309 | { .compatible = "hit,hd44780" }, | ||
310 | { /* sentinel */ } | ||
311 | }; | ||
312 | MODULE_DEVICE_TABLE(of, hd44780_of_match); | ||
313 | |||
314 | static struct platform_driver hd44780_driver = { | ||
315 | .probe = hd44780_probe, | ||
316 | .remove = hd44780_remove, | ||
317 | .driver = { | ||
318 | .name = "hd44780", | ||
319 | .of_match_table = hd44780_of_match, | ||
320 | }, | ||
321 | }; | ||
322 | |||
323 | module_platform_driver(hd44780_driver); | ||
324 | MODULE_DESCRIPTION("HD44780 Character LCD driver"); | ||
325 | MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>"); | ||
326 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/auxdisplay/ht16k33.c b/drivers/auxdisplay/ht16k33.c index f66b45b235b0..fbfa5b4cc567 100644 --- a/drivers/auxdisplay/ht16k33.c +++ b/drivers/auxdisplay/ht16k33.c | |||
@@ -254,18 +254,22 @@ static bool ht16k33_keypad_scan(struct ht16k33_keypad *keypad) | |||
254 | { | 254 | { |
255 | const unsigned short *keycodes = keypad->dev->keycode; | 255 | const unsigned short *keycodes = keypad->dev->keycode; |
256 | u16 new_state[HT16K33_MATRIX_KEYPAD_MAX_COLS]; | 256 | u16 new_state[HT16K33_MATRIX_KEYPAD_MAX_COLS]; |
257 | u8 data[HT16K33_MATRIX_KEYPAD_MAX_COLS * 2]; | 257 | __le16 data[HT16K33_MATRIX_KEYPAD_MAX_COLS]; |
258 | unsigned long bits_changed; | 258 | unsigned long bits_changed; |
259 | int row, col, code; | 259 | int row, col, code; |
260 | int rc; | ||
260 | bool pressed = false; | 261 | bool pressed = false; |
261 | 262 | ||
262 | if (i2c_smbus_read_i2c_block_data(keypad->client, 0x40, 6, data) != 6) { | 263 | rc = i2c_smbus_read_i2c_block_data(keypad->client, 0x40, |
263 | dev_err(&keypad->client->dev, "Failed to read key data\n"); | 264 | sizeof(data), (u8 *)data); |
265 | if (rc != sizeof(data)) { | ||
266 | dev_err(&keypad->client->dev, | ||
267 | "Failed to read key data, rc=%d\n", rc); | ||
264 | return false; | 268 | return false; |
265 | } | 269 | } |
266 | 270 | ||
267 | for (col = 0; col < keypad->cols; col++) { | 271 | for (col = 0; col < keypad->cols; col++) { |
268 | new_state[col] = (data[col * 2 + 1] << 8) | data[col * 2]; | 272 | new_state[col] = le16_to_cpu(data[col]); |
269 | if (new_state[col]) | 273 | if (new_state[col]) |
270 | pressed = true; | 274 | pressed = true; |
271 | bits_changed = keypad->last_key_state[col] ^ new_state[col]; | 275 | bits_changed = keypad->last_key_state[col] ^ new_state[col]; |
@@ -278,7 +282,7 @@ static bool ht16k33_keypad_scan(struct ht16k33_keypad *keypad) | |||
278 | } | 282 | } |
279 | } | 283 | } |
280 | input_sync(keypad->dev); | 284 | input_sync(keypad->dev); |
281 | memcpy(keypad->last_key_state, new_state, sizeof(new_state)); | 285 | memcpy(keypad->last_key_state, new_state, sizeof(u16) * keypad->cols); |
282 | 286 | ||
283 | return pressed; | 287 | return pressed; |
284 | } | 288 | } |
@@ -353,6 +357,12 @@ static int ht16k33_keypad_probe(struct i2c_client *client, | |||
353 | err = matrix_keypad_parse_of_params(&client->dev, &rows, &cols); | 357 | err = matrix_keypad_parse_of_params(&client->dev, &rows, &cols); |
354 | if (err) | 358 | if (err) |
355 | return err; | 359 | return err; |
360 | if (rows > HT16K33_MATRIX_KEYPAD_MAX_ROWS || | ||
361 | cols > HT16K33_MATRIX_KEYPAD_MAX_COLS) { | ||
362 | dev_err(&client->dev, "%u rows or %u cols out of range in DT\n", | ||
363 | rows, cols); | ||
364 | return -ERANGE; | ||
365 | } | ||
356 | 366 | ||
357 | keypad->rows = rows; | 367 | keypad->rows = rows; |
358 | keypad->cols = cols; | 368 | keypad->cols = cols; |
diff --git a/drivers/auxdisplay/img-ascii-lcd.c b/drivers/auxdisplay/img-ascii-lcd.c index 83f1439e57fd..25306fa27251 100644 --- a/drivers/auxdisplay/img-ascii-lcd.c +++ b/drivers/auxdisplay/img-ascii-lcd.c | |||
@@ -220,6 +220,7 @@ static const struct of_device_id img_ascii_lcd_matches[] = { | |||
220 | { .compatible = "mti,sead3-lcd", .data = &sead3_config }, | 220 | { .compatible = "mti,sead3-lcd", .data = &sead3_config }, |
221 | { /* sentinel */ } | 221 | { /* sentinel */ } |
222 | }; | 222 | }; |
223 | MODULE_DEVICE_TABLE(of, img_ascii_lcd_matches); | ||
223 | 224 | ||
224 | /** | 225 | /** |
225 | * img_ascii_lcd_scroll() - scroll the display by a character | 226 | * img_ascii_lcd_scroll() - scroll the display by a character |
diff --git a/drivers/misc/panel.c b/drivers/auxdisplay/panel.c index ef2ece0f26af..e0c014c2356f 100644 --- a/drivers/misc/panel.c +++ b/drivers/auxdisplay/panel.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Front panel driver for Linux | 2 | * Front panel driver for Linux |
3 | * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu> | 3 | * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu> |
4 | * Copyright (C) 2016-2017 Glider bvba | ||
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
@@ -54,15 +55,12 @@ | |||
54 | #include <linux/ctype.h> | 55 | #include <linux/ctype.h> |
55 | #include <linux/parport.h> | 56 | #include <linux/parport.h> |
56 | #include <linux/list.h> | 57 | #include <linux/list.h> |
57 | #include <linux/notifier.h> | ||
58 | #include <linux/reboot.h> | ||
59 | #include <linux/workqueue.h> | ||
60 | #include <generated/utsrelease.h> | ||
61 | 58 | ||
62 | #include <linux/io.h> | 59 | #include <linux/io.h> |
63 | #include <linux/uaccess.h> | 60 | #include <linux/uaccess.h> |
64 | 61 | ||
65 | #define LCD_MINOR 156 | 62 | #include <misc/charlcd.h> |
63 | |||
66 | #define KEYPAD_MINOR 185 | 64 | #define KEYPAD_MINOR 185 |
67 | 65 | ||
68 | #define LCD_MAXBYTES 256 /* max burst write */ | 66 | #define LCD_MAXBYTES 256 /* max burst write */ |
@@ -76,9 +74,6 @@ | |||
76 | /* a key repeats this times INPUT_POLL_TIME */ | 74 | /* a key repeats this times INPUT_POLL_TIME */ |
77 | #define KEYPAD_REP_DELAY (2) | 75 | #define KEYPAD_REP_DELAY (2) |
78 | 76 | ||
79 | /* keep the light on this many seconds for each flash */ | ||
80 | #define FLASH_LIGHT_TEMPO (4) | ||
81 | |||
82 | /* converts an r_str() input to an active high, bits string : 000BAOSE */ | 77 | /* converts an r_str() input to an active high, bits string : 000BAOSE */ |
83 | #define PNL_PINPUT(a) ((((unsigned char)(a)) ^ 0x7F) >> 3) | 78 | #define PNL_PINPUT(a) ((((unsigned char)(a)) ^ 0x7F) >> 3) |
84 | 79 | ||
@@ -120,40 +115,6 @@ | |||
120 | #define PIN_SELECP 17 | 115 | #define PIN_SELECP 17 |
121 | #define PIN_NOT_SET 127 | 116 | #define PIN_NOT_SET 127 |
122 | 117 | ||
123 | #define LCD_FLAG_B 0x0004 /* blink on */ | ||
124 | #define LCD_FLAG_C 0x0008 /* cursor on */ | ||
125 | #define LCD_FLAG_D 0x0010 /* display on */ | ||
126 | #define LCD_FLAG_F 0x0020 /* large font mode */ | ||
127 | #define LCD_FLAG_N 0x0040 /* 2-rows mode */ | ||
128 | #define LCD_FLAG_L 0x0080 /* backlight enabled */ | ||
129 | |||
130 | /* LCD commands */ | ||
131 | #define LCD_CMD_DISPLAY_CLEAR 0x01 /* Clear entire display */ | ||
132 | |||
133 | #define LCD_CMD_ENTRY_MODE 0x04 /* Set entry mode */ | ||
134 | #define LCD_CMD_CURSOR_INC 0x02 /* Increment cursor */ | ||
135 | |||
136 | #define LCD_CMD_DISPLAY_CTRL 0x08 /* Display control */ | ||
137 | #define LCD_CMD_DISPLAY_ON 0x04 /* Set display on */ | ||
138 | #define LCD_CMD_CURSOR_ON 0x02 /* Set cursor on */ | ||
139 | #define LCD_CMD_BLINK_ON 0x01 /* Set blink on */ | ||
140 | |||
141 | #define LCD_CMD_SHIFT 0x10 /* Shift cursor/display */ | ||
142 | #define LCD_CMD_DISPLAY_SHIFT 0x08 /* Shift display instead of cursor */ | ||
143 | #define LCD_CMD_SHIFT_RIGHT 0x04 /* Shift display/cursor to the right */ | ||
144 | |||
145 | #define LCD_CMD_FUNCTION_SET 0x20 /* Set function */ | ||
146 | #define LCD_CMD_DATA_LEN_8BITS 0x10 /* Set data length to 8 bits */ | ||
147 | #define LCD_CMD_TWO_LINES 0x08 /* Set to two display lines */ | ||
148 | #define LCD_CMD_FONT_5X10_DOTS 0x04 /* Set char font to 5x10 dots */ | ||
149 | |||
150 | #define LCD_CMD_SET_CGRAM_ADDR 0x40 /* Set char generator RAM address */ | ||
151 | |||
152 | #define LCD_CMD_SET_DDRAM_ADDR 0x80 /* Set display data RAM address */ | ||
153 | |||
154 | #define LCD_ESCAPE_LEN 24 /* max chars for LCD escape command */ | ||
155 | #define LCD_ESCAPE_CHAR 27 /* use char 27 for escape command */ | ||
156 | |||
157 | #define NOT_SET -1 | 118 | #define NOT_SET -1 |
158 | 119 | ||
159 | /* macros to simplify use of the parallel port */ | 120 | /* macros to simplify use of the parallel port */ |
@@ -245,19 +206,10 @@ static wait_queue_head_t keypad_read_wait; | |||
245 | static struct { | 206 | static struct { |
246 | bool enabled; | 207 | bool enabled; |
247 | bool initialized; | 208 | bool initialized; |
248 | bool must_clear; | ||
249 | 209 | ||
250 | int height; | ||
251 | int width; | ||
252 | int bwidth; | ||
253 | int hwidth; | ||
254 | int charset; | 210 | int charset; |
255 | int proto; | 211 | int proto; |
256 | 212 | ||
257 | struct delayed_work bl_work; | ||
258 | struct mutex bl_tempo_lock; /* Protects access to bl_tempo */ | ||
259 | bool bl_tempo; | ||
260 | |||
261 | /* TODO: use union here? */ | 213 | /* TODO: use union here? */ |
262 | struct { | 214 | struct { |
263 | int e; | 215 | int e; |
@@ -268,20 +220,7 @@ static struct { | |||
268 | int bl; | 220 | int bl; |
269 | } pins; | 221 | } pins; |
270 | 222 | ||
271 | /* contains the LCD config state */ | 223 | struct charlcd *charlcd; |
272 | unsigned long int flags; | ||
273 | |||
274 | /* Contains the LCD X and Y offset */ | ||
275 | struct { | ||
276 | unsigned long int x; | ||
277 | unsigned long int y; | ||
278 | } addr; | ||
279 | |||
280 | /* Current escape sequence and it's length or -1 if outside */ | ||
281 | struct { | ||
282 | char buf[LCD_ESCAPE_LEN + 1]; | ||
283 | int len; | ||
284 | } esc_seq; | ||
285 | } lcd; | 224 | } lcd; |
286 | 225 | ||
287 | /* Needed only for init */ | 226 | /* Needed only for init */ |
@@ -464,17 +403,12 @@ static unsigned char lcd_bits[LCD_PORTS][LCD_BITS][BIT_STATES]; | |||
464 | /* global variables */ | 403 | /* global variables */ |
465 | 404 | ||
466 | /* Device single-open policy control */ | 405 | /* Device single-open policy control */ |
467 | static atomic_t lcd_available = ATOMIC_INIT(1); | ||
468 | static atomic_t keypad_available = ATOMIC_INIT(1); | 406 | static atomic_t keypad_available = ATOMIC_INIT(1); |
469 | 407 | ||
470 | static struct pardevice *pprt; | 408 | static struct pardevice *pprt; |
471 | 409 | ||
472 | static int keypad_initialized; | 410 | static int keypad_initialized; |
473 | 411 | ||
474 | static void (*lcd_write_cmd)(int); | ||
475 | static void (*lcd_write_data)(int); | ||
476 | static void (*lcd_clear_fast)(void); | ||
477 | |||
478 | static DEFINE_SPINLOCK(pprt_lock); | 412 | static DEFINE_SPINLOCK(pprt_lock); |
479 | static struct timer_list scan_timer; | 413 | static struct timer_list scan_timer; |
480 | 414 | ||
@@ -574,8 +508,6 @@ static int keypad_enabled = NOT_SET; | |||
574 | module_param(keypad_enabled, int, 0000); | 508 | module_param(keypad_enabled, int, 0000); |
575 | MODULE_PARM_DESC(keypad_enabled, "Deprecated option, use keypad_type instead"); | 509 | MODULE_PARM_DESC(keypad_enabled, "Deprecated option, use keypad_type instead"); |
576 | 510 | ||
577 | static const unsigned char *lcd_char_conv; | ||
578 | |||
579 | /* for some LCD drivers (ks0074) we need a charset conversion table. */ | 511 | /* for some LCD drivers (ks0074) we need a charset conversion table. */ |
580 | static const unsigned char lcd_char_conv_ks0074[256] = { | 512 | static const unsigned char lcd_char_conv_ks0074[256] = { |
581 | /* 0|8 1|9 2|A 3|B 4|C 5|D 6|E 7|F */ | 513 | /* 0|8 1|9 2|A 3|B 4|C 5|D 6|E 7|F */ |
@@ -752,15 +684,6 @@ static void pin_to_bits(int pin, unsigned char *d_val, unsigned char *c_val) | |||
752 | } | 684 | } |
753 | } | 685 | } |
754 | 686 | ||
755 | /* sleeps that many milliseconds with a reschedule */ | ||
756 | static void long_sleep(int ms) | ||
757 | { | ||
758 | if (in_interrupt()) | ||
759 | mdelay(ms); | ||
760 | else | ||
761 | schedule_timeout_interruptible(msecs_to_jiffies(ms)); | ||
762 | } | ||
763 | |||
764 | /* | 687 | /* |
765 | * send a serial byte to the LCD panel. The caller is responsible for locking | 688 | * send a serial byte to the LCD panel. The caller is responsible for locking |
766 | * if needed. | 689 | * if needed. |
@@ -792,8 +715,11 @@ static void lcd_send_serial(int byte) | |||
792 | } | 715 | } |
793 | 716 | ||
794 | /* turn the backlight on or off */ | 717 | /* turn the backlight on or off */ |
795 | static void __lcd_backlight(int on) | 718 | static void lcd_backlight(struct charlcd *charlcd, int on) |
796 | { | 719 | { |
720 | if (lcd.pins.bl == PIN_NONE) | ||
721 | return; | ||
722 | |||
797 | /* The backlight is activated by setting the AUTOFEED line to +5V */ | 723 | /* The backlight is activated by setting the AUTOFEED line to +5V */ |
798 | spin_lock_irq(&pprt_lock); | 724 | spin_lock_irq(&pprt_lock); |
799 | if (on) | 725 | if (on) |
@@ -804,46 +730,8 @@ static void __lcd_backlight(int on) | |||
804 | spin_unlock_irq(&pprt_lock); | 730 | spin_unlock_irq(&pprt_lock); |
805 | } | 731 | } |
806 | 732 | ||
807 | static void lcd_backlight(int on) | ||
808 | { | ||
809 | if (lcd.pins.bl == PIN_NONE) | ||
810 | return; | ||
811 | |||
812 | mutex_lock(&lcd.bl_tempo_lock); | ||
813 | if (!lcd.bl_tempo) | ||
814 | __lcd_backlight(on); | ||
815 | mutex_unlock(&lcd.bl_tempo_lock); | ||
816 | } | ||
817 | |||
818 | static void lcd_bl_off(struct work_struct *work) | ||
819 | { | ||
820 | mutex_lock(&lcd.bl_tempo_lock); | ||
821 | if (lcd.bl_tempo) { | ||
822 | lcd.bl_tempo = false; | ||
823 | if (!(lcd.flags & LCD_FLAG_L)) | ||
824 | __lcd_backlight(0); | ||
825 | } | ||
826 | mutex_unlock(&lcd.bl_tempo_lock); | ||
827 | } | ||
828 | |||
829 | /* turn the backlight on for a little while */ | ||
830 | static void lcd_poke(void) | ||
831 | { | ||
832 | if (lcd.pins.bl == PIN_NONE) | ||
833 | return; | ||
834 | |||
835 | cancel_delayed_work_sync(&lcd.bl_work); | ||
836 | |||
837 | mutex_lock(&lcd.bl_tempo_lock); | ||
838 | if (!lcd.bl_tempo && !(lcd.flags & LCD_FLAG_L)) | ||
839 | __lcd_backlight(1); | ||
840 | lcd.bl_tempo = true; | ||
841 | schedule_delayed_work(&lcd.bl_work, FLASH_LIGHT_TEMPO * HZ); | ||
842 | mutex_unlock(&lcd.bl_tempo_lock); | ||
843 | } | ||
844 | |||
845 | /* send a command to the LCD panel in serial mode */ | 733 | /* send a command to the LCD panel in serial mode */ |
846 | static void lcd_write_cmd_s(int cmd) | 734 | static void lcd_write_cmd_s(struct charlcd *charlcd, int cmd) |
847 | { | 735 | { |
848 | spin_lock_irq(&pprt_lock); | 736 | spin_lock_irq(&pprt_lock); |
849 | lcd_send_serial(0x1F); /* R/W=W, RS=0 */ | 737 | lcd_send_serial(0x1F); /* R/W=W, RS=0 */ |
@@ -854,7 +742,7 @@ static void lcd_write_cmd_s(int cmd) | |||
854 | } | 742 | } |
855 | 743 | ||
856 | /* send data to the LCD panel in serial mode */ | 744 | /* send data to the LCD panel in serial mode */ |
857 | static void lcd_write_data_s(int data) | 745 | static void lcd_write_data_s(struct charlcd *charlcd, int data) |
858 | { | 746 | { |
859 | spin_lock_irq(&pprt_lock); | 747 | spin_lock_irq(&pprt_lock); |
860 | lcd_send_serial(0x5F); /* R/W=W, RS=1 */ | 748 | lcd_send_serial(0x5F); /* R/W=W, RS=1 */ |
@@ -865,7 +753,7 @@ static void lcd_write_data_s(int data) | |||
865 | } | 753 | } |
866 | 754 | ||
867 | /* send a command to the LCD panel in 8 bits parallel mode */ | 755 | /* send a command to the LCD panel in 8 bits parallel mode */ |
868 | static void lcd_write_cmd_p8(int cmd) | 756 | static void lcd_write_cmd_p8(struct charlcd *charlcd, int cmd) |
869 | { | 757 | { |
870 | spin_lock_irq(&pprt_lock); | 758 | spin_lock_irq(&pprt_lock); |
871 | /* present the data to the data port */ | 759 | /* present the data to the data port */ |
@@ -887,7 +775,7 @@ static void lcd_write_cmd_p8(int cmd) | |||
887 | } | 775 | } |
888 | 776 | ||
889 | /* send data to the LCD panel in 8 bits parallel mode */ | 777 | /* send data to the LCD panel in 8 bits parallel mode */ |
890 | static void lcd_write_data_p8(int data) | 778 | static void lcd_write_data_p8(struct charlcd *charlcd, int data) |
891 | { | 779 | { |
892 | spin_lock_irq(&pprt_lock); | 780 | spin_lock_irq(&pprt_lock); |
893 | /* present the data to the data port */ | 781 | /* present the data to the data port */ |
@@ -909,7 +797,7 @@ static void lcd_write_data_p8(int data) | |||
909 | } | 797 | } |
910 | 798 | ||
911 | /* send a command to the TI LCD panel */ | 799 | /* send a command to the TI LCD panel */ |
912 | static void lcd_write_cmd_tilcd(int cmd) | 800 | static void lcd_write_cmd_tilcd(struct charlcd *charlcd, int cmd) |
913 | { | 801 | { |
914 | spin_lock_irq(&pprt_lock); | 802 | spin_lock_irq(&pprt_lock); |
915 | /* present the data to the control port */ | 803 | /* present the data to the control port */ |
@@ -919,7 +807,7 @@ static void lcd_write_cmd_tilcd(int cmd) | |||
919 | } | 807 | } |
920 | 808 | ||
921 | /* send data to the TI LCD panel */ | 809 | /* send data to the TI LCD panel */ |
922 | static void lcd_write_data_tilcd(int data) | 810 | static void lcd_write_data_tilcd(struct charlcd *charlcd, int data) |
923 | { | 811 | { |
924 | spin_lock_irq(&pprt_lock); | 812 | spin_lock_irq(&pprt_lock); |
925 | /* present the data to the data port */ | 813 | /* present the data to the data port */ |
@@ -928,47 +816,13 @@ static void lcd_write_data_tilcd(int data) | |||
928 | spin_unlock_irq(&pprt_lock); | 816 | spin_unlock_irq(&pprt_lock); |
929 | } | 817 | } |
930 | 818 | ||
931 | static void lcd_gotoxy(void) | ||
932 | { | ||
933 | lcd_write_cmd(LCD_CMD_SET_DDRAM_ADDR | ||
934 | | (lcd.addr.y ? lcd.hwidth : 0) | ||
935 | /* | ||
936 | * we force the cursor to stay at the end of the | ||
937 | * line if it wants to go farther | ||
938 | */ | ||
939 | | ((lcd.addr.x < lcd.bwidth) ? lcd.addr.x & | ||
940 | (lcd.hwidth - 1) : lcd.bwidth - 1)); | ||
941 | } | ||
942 | |||
943 | static void lcd_home(void) | ||
944 | { | ||
945 | lcd.addr.x = 0; | ||
946 | lcd.addr.y = 0; | ||
947 | lcd_gotoxy(); | ||
948 | } | ||
949 | |||
950 | static void lcd_print(char c) | ||
951 | { | ||
952 | if (lcd.addr.x < lcd.bwidth) { | ||
953 | if (lcd_char_conv) | ||
954 | c = lcd_char_conv[(unsigned char)c]; | ||
955 | lcd_write_data(c); | ||
956 | lcd.addr.x++; | ||
957 | } | ||
958 | /* prevents the cursor from wrapping onto the next line */ | ||
959 | if (lcd.addr.x == lcd.bwidth) | ||
960 | lcd_gotoxy(); | ||
961 | } | ||
962 | |||
963 | /* fills the display with spaces and resets X/Y */ | 819 | /* fills the display with spaces and resets X/Y */ |
964 | static void lcd_clear_fast_s(void) | 820 | static void lcd_clear_fast_s(struct charlcd *charlcd) |
965 | { | 821 | { |
966 | int pos; | 822 | int pos; |
967 | 823 | ||
968 | lcd_home(); | ||
969 | |||
970 | spin_lock_irq(&pprt_lock); | 824 | spin_lock_irq(&pprt_lock); |
971 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { | 825 | for (pos = 0; pos < charlcd->height * charlcd->hwidth; pos++) { |
972 | lcd_send_serial(0x5F); /* R/W=W, RS=1 */ | 826 | lcd_send_serial(0x5F); /* R/W=W, RS=1 */ |
973 | lcd_send_serial(' ' & 0x0F); | 827 | lcd_send_serial(' ' & 0x0F); |
974 | lcd_send_serial((' ' >> 4) & 0x0F); | 828 | lcd_send_serial((' ' >> 4) & 0x0F); |
@@ -976,19 +830,15 @@ static void lcd_clear_fast_s(void) | |||
976 | udelay(40); | 830 | udelay(40); |
977 | } | 831 | } |
978 | spin_unlock_irq(&pprt_lock); | 832 | spin_unlock_irq(&pprt_lock); |
979 | |||
980 | lcd_home(); | ||
981 | } | 833 | } |
982 | 834 | ||
983 | /* fills the display with spaces and resets X/Y */ | 835 | /* fills the display with spaces and resets X/Y */ |
984 | static void lcd_clear_fast_p8(void) | 836 | static void lcd_clear_fast_p8(struct charlcd *charlcd) |
985 | { | 837 | { |
986 | int pos; | 838 | int pos; |
987 | 839 | ||
988 | lcd_home(); | ||
989 | |||
990 | spin_lock_irq(&pprt_lock); | 840 | spin_lock_irq(&pprt_lock); |
991 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { | 841 | for (pos = 0; pos < charlcd->height * charlcd->hwidth; pos++) { |
992 | /* present the data to the data port */ | 842 | /* present the data to the data port */ |
993 | w_dtr(pprt, ' '); | 843 | w_dtr(pprt, ' '); |
994 | 844 | ||
@@ -1010,488 +860,62 @@ static void lcd_clear_fast_p8(void) | |||
1010 | udelay(45); | 860 | udelay(45); |
1011 | } | 861 | } |
1012 | spin_unlock_irq(&pprt_lock); | 862 | spin_unlock_irq(&pprt_lock); |
1013 | |||
1014 | lcd_home(); | ||
1015 | } | 863 | } |
1016 | 864 | ||
1017 | /* fills the display with spaces and resets X/Y */ | 865 | /* fills the display with spaces and resets X/Y */ |
1018 | static void lcd_clear_fast_tilcd(void) | 866 | static void lcd_clear_fast_tilcd(struct charlcd *charlcd) |
1019 | { | 867 | { |
1020 | int pos; | 868 | int pos; |
1021 | 869 | ||
1022 | lcd_home(); | ||
1023 | |||
1024 | spin_lock_irq(&pprt_lock); | 870 | spin_lock_irq(&pprt_lock); |
1025 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { | 871 | for (pos = 0; pos < charlcd->height * charlcd->hwidth; pos++) { |
1026 | /* present the data to the data port */ | 872 | /* present the data to the data port */ |
1027 | w_dtr(pprt, ' '); | 873 | w_dtr(pprt, ' '); |
1028 | udelay(60); | 874 | udelay(60); |
1029 | } | 875 | } |
1030 | 876 | ||
1031 | spin_unlock_irq(&pprt_lock); | 877 | spin_unlock_irq(&pprt_lock); |
1032 | |||
1033 | lcd_home(); | ||
1034 | } | ||
1035 | |||
1036 | /* clears the display and resets X/Y */ | ||
1037 | static void lcd_clear_display(void) | ||
1038 | { | ||
1039 | lcd_write_cmd(LCD_CMD_DISPLAY_CLEAR); | ||
1040 | lcd.addr.x = 0; | ||
1041 | lcd.addr.y = 0; | ||
1042 | /* we must wait a few milliseconds (15) */ | ||
1043 | long_sleep(15); | ||
1044 | } | 878 | } |
1045 | 879 | ||
1046 | static void lcd_init_display(void) | 880 | static struct charlcd_ops charlcd_serial_ops = { |
1047 | { | 881 | .write_cmd = lcd_write_cmd_s, |
1048 | lcd.flags = ((lcd.height > 1) ? LCD_FLAG_N : 0) | 882 | .write_data = lcd_write_data_s, |
1049 | | LCD_FLAG_D | LCD_FLAG_C | LCD_FLAG_B; | 883 | .clear_fast = lcd_clear_fast_s, |
1050 | 884 | .backlight = lcd_backlight, | |
1051 | long_sleep(20); /* wait 20 ms after power-up for the paranoid */ | 885 | }; |
1052 | |||
1053 | /* 8bits, 1 line, small fonts; let's do it 3 times */ | ||
1054 | lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS); | ||
1055 | long_sleep(10); | ||
1056 | lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS); | ||
1057 | long_sleep(10); | ||
1058 | lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS); | ||
1059 | long_sleep(10); | ||
1060 | |||
1061 | /* set font height and lines number */ | ||
1062 | lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS | ||
1063 | | ((lcd.flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0) | ||
1064 | | ((lcd.flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0) | ||
1065 | ); | ||
1066 | long_sleep(10); | ||
1067 | |||
1068 | /* display off, cursor off, blink off */ | ||
1069 | lcd_write_cmd(LCD_CMD_DISPLAY_CTRL); | ||
1070 | long_sleep(10); | ||
1071 | |||
1072 | lcd_write_cmd(LCD_CMD_DISPLAY_CTRL /* set display mode */ | ||
1073 | | ((lcd.flags & LCD_FLAG_D) ? LCD_CMD_DISPLAY_ON : 0) | ||
1074 | | ((lcd.flags & LCD_FLAG_C) ? LCD_CMD_CURSOR_ON : 0) | ||
1075 | | ((lcd.flags & LCD_FLAG_B) ? LCD_CMD_BLINK_ON : 0) | ||
1076 | ); | ||
1077 | |||
1078 | lcd_backlight((lcd.flags & LCD_FLAG_L) ? 1 : 0); | ||
1079 | |||
1080 | long_sleep(10); | ||
1081 | |||
1082 | /* entry mode set : increment, cursor shifting */ | ||
1083 | lcd_write_cmd(LCD_CMD_ENTRY_MODE | LCD_CMD_CURSOR_INC); | ||
1084 | 886 | ||
1085 | lcd_clear_display(); | 887 | static struct charlcd_ops charlcd_parallel_ops = { |
1086 | } | 888 | .write_cmd = lcd_write_cmd_p8, |
889 | .write_data = lcd_write_data_p8, | ||
890 | .clear_fast = lcd_clear_fast_p8, | ||
891 | .backlight = lcd_backlight, | ||
892 | }; | ||
1087 | 893 | ||
1088 | /* | 894 | static struct charlcd_ops charlcd_tilcd_ops = { |
1089 | * These are the file operation function for user access to /dev/lcd | 895 | .write_cmd = lcd_write_cmd_tilcd, |
1090 | * This function can also be called from inside the kernel, by | 896 | .write_data = lcd_write_data_tilcd, |
1091 | * setting file and ppos to NULL. | 897 | .clear_fast = lcd_clear_fast_tilcd, |
1092 | * | 898 | .backlight = lcd_backlight, |
1093 | */ | 899 | }; |
1094 | 900 | ||
1095 | static inline int handle_lcd_special_code(void) | 901 | /* initialize the LCD driver */ |
902 | static void lcd_init(void) | ||
1096 | { | 903 | { |
1097 | /* LCD special codes */ | 904 | struct charlcd *charlcd; |
1098 | |||
1099 | int processed = 0; | ||
1100 | 905 | ||
1101 | char *esc = lcd.esc_seq.buf + 2; | 906 | charlcd = charlcd_alloc(0); |
1102 | int oldflags = lcd.flags; | 907 | if (!charlcd) |
1103 | 908 | return; | |
1104 | /* check for display mode flags */ | ||
1105 | switch (*esc) { | ||
1106 | case 'D': /* Display ON */ | ||
1107 | lcd.flags |= LCD_FLAG_D; | ||
1108 | processed = 1; | ||
1109 | break; | ||
1110 | case 'd': /* Display OFF */ | ||
1111 | lcd.flags &= ~LCD_FLAG_D; | ||
1112 | processed = 1; | ||
1113 | break; | ||
1114 | case 'C': /* Cursor ON */ | ||
1115 | lcd.flags |= LCD_FLAG_C; | ||
1116 | processed = 1; | ||
1117 | break; | ||
1118 | case 'c': /* Cursor OFF */ | ||
1119 | lcd.flags &= ~LCD_FLAG_C; | ||
1120 | processed = 1; | ||
1121 | break; | ||
1122 | case 'B': /* Blink ON */ | ||
1123 | lcd.flags |= LCD_FLAG_B; | ||
1124 | processed = 1; | ||
1125 | break; | ||
1126 | case 'b': /* Blink OFF */ | ||
1127 | lcd.flags &= ~LCD_FLAG_B; | ||
1128 | processed = 1; | ||
1129 | break; | ||
1130 | case '+': /* Back light ON */ | ||
1131 | lcd.flags |= LCD_FLAG_L; | ||
1132 | processed = 1; | ||
1133 | break; | ||
1134 | case '-': /* Back light OFF */ | ||
1135 | lcd.flags &= ~LCD_FLAG_L; | ||
1136 | processed = 1; | ||
1137 | break; | ||
1138 | case '*': | ||
1139 | /* flash back light */ | ||
1140 | lcd_poke(); | ||
1141 | processed = 1; | ||
1142 | break; | ||
1143 | case 'f': /* Small Font */ | ||
1144 | lcd.flags &= ~LCD_FLAG_F; | ||
1145 | processed = 1; | ||
1146 | break; | ||
1147 | case 'F': /* Large Font */ | ||
1148 | lcd.flags |= LCD_FLAG_F; | ||
1149 | processed = 1; | ||
1150 | break; | ||
1151 | case 'n': /* One Line */ | ||
1152 | lcd.flags &= ~LCD_FLAG_N; | ||
1153 | processed = 1; | ||
1154 | break; | ||
1155 | case 'N': /* Two Lines */ | ||
1156 | lcd.flags |= LCD_FLAG_N; | ||
1157 | break; | ||
1158 | case 'l': /* Shift Cursor Left */ | ||
1159 | if (lcd.addr.x > 0) { | ||
1160 | /* back one char if not at end of line */ | ||
1161 | if (lcd.addr.x < lcd.bwidth) | ||
1162 | lcd_write_cmd(LCD_CMD_SHIFT); | ||
1163 | lcd.addr.x--; | ||
1164 | } | ||
1165 | processed = 1; | ||
1166 | break; | ||
1167 | case 'r': /* shift cursor right */ | ||
1168 | if (lcd.addr.x < lcd.width) { | ||
1169 | /* allow the cursor to pass the end of the line */ | ||
1170 | if (lcd.addr.x < (lcd.bwidth - 1)) | ||
1171 | lcd_write_cmd(LCD_CMD_SHIFT | | ||
1172 | LCD_CMD_SHIFT_RIGHT); | ||
1173 | lcd.addr.x++; | ||
1174 | } | ||
1175 | processed = 1; | ||
1176 | break; | ||
1177 | case 'L': /* shift display left */ | ||
1178 | lcd_write_cmd(LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT); | ||
1179 | processed = 1; | ||
1180 | break; | ||
1181 | case 'R': /* shift display right */ | ||
1182 | lcd_write_cmd(LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT | | ||
1183 | LCD_CMD_SHIFT_RIGHT); | ||
1184 | processed = 1; | ||
1185 | break; | ||
1186 | case 'k': { /* kill end of line */ | ||
1187 | int x; | ||
1188 | |||
1189 | for (x = lcd.addr.x; x < lcd.bwidth; x++) | ||
1190 | lcd_write_data(' '); | ||
1191 | |||
1192 | /* restore cursor position */ | ||
1193 | lcd_gotoxy(); | ||
1194 | processed = 1; | ||
1195 | break; | ||
1196 | } | ||
1197 | case 'I': /* reinitialize display */ | ||
1198 | lcd_init_display(); | ||
1199 | processed = 1; | ||
1200 | break; | ||
1201 | case 'G': { | ||
1202 | /* Generator : LGcxxxxx...xx; must have <c> between '0' | ||
1203 | * and '7', representing the numerical ASCII code of the | ||
1204 | * redefined character, and <xx...xx> a sequence of 16 | ||
1205 | * hex digits representing 8 bytes for each character. | ||
1206 | * Most LCDs will only use 5 lower bits of the 7 first | ||
1207 | * bytes. | ||
1208 | */ | ||
1209 | |||
1210 | unsigned char cgbytes[8]; | ||
1211 | unsigned char cgaddr; | ||
1212 | int cgoffset; | ||
1213 | int shift; | ||
1214 | char value; | ||
1215 | int addr; | ||
1216 | |||
1217 | if (!strchr(esc, ';')) | ||
1218 | break; | ||
1219 | |||
1220 | esc++; | ||
1221 | |||
1222 | cgaddr = *(esc++) - '0'; | ||
1223 | if (cgaddr > 7) { | ||
1224 | processed = 1; | ||
1225 | break; | ||
1226 | } | ||
1227 | |||
1228 | cgoffset = 0; | ||
1229 | shift = 0; | ||
1230 | value = 0; | ||
1231 | while (*esc && cgoffset < 8) { | ||
1232 | shift ^= 4; | ||
1233 | if (*esc >= '0' && *esc <= '9') { | ||
1234 | value |= (*esc - '0') << shift; | ||
1235 | } else if (*esc >= 'A' && *esc <= 'Z') { | ||
1236 | value |= (*esc - 'A' + 10) << shift; | ||
1237 | } else if (*esc >= 'a' && *esc <= 'z') { | ||
1238 | value |= (*esc - 'a' + 10) << shift; | ||
1239 | } else { | ||
1240 | esc++; | ||
1241 | continue; | ||
1242 | } | ||
1243 | |||
1244 | if (shift == 0) { | ||
1245 | cgbytes[cgoffset++] = value; | ||
1246 | value = 0; | ||
1247 | } | ||
1248 | |||
1249 | esc++; | ||
1250 | } | ||
1251 | |||
1252 | lcd_write_cmd(LCD_CMD_SET_CGRAM_ADDR | (cgaddr * 8)); | ||
1253 | for (addr = 0; addr < cgoffset; addr++) | ||
1254 | lcd_write_data(cgbytes[addr]); | ||
1255 | |||
1256 | /* ensures that we stop writing to CGRAM */ | ||
1257 | lcd_gotoxy(); | ||
1258 | processed = 1; | ||
1259 | break; | ||
1260 | } | ||
1261 | case 'x': /* gotoxy : LxXXX[yYYY]; */ | ||
1262 | case 'y': /* gotoxy : LyYYY[xXXX]; */ | ||
1263 | if (!strchr(esc, ';')) | ||
1264 | break; | ||
1265 | |||
1266 | while (*esc) { | ||
1267 | if (*esc == 'x') { | ||
1268 | esc++; | ||
1269 | if (kstrtoul(esc, 10, &lcd.addr.x) < 0) | ||
1270 | break; | ||
1271 | } else if (*esc == 'y') { | ||
1272 | esc++; | ||
1273 | if (kstrtoul(esc, 10, &lcd.addr.y) < 0) | ||
1274 | break; | ||
1275 | } else { | ||
1276 | break; | ||
1277 | } | ||
1278 | } | ||
1279 | |||
1280 | lcd_gotoxy(); | ||
1281 | processed = 1; | ||
1282 | break; | ||
1283 | } | ||
1284 | |||
1285 | /* TODO: This indent party here got ugly, clean it! */ | ||
1286 | /* Check whether one flag was changed */ | ||
1287 | if (oldflags != lcd.flags) { | ||
1288 | /* check whether one of B,C,D flags were changed */ | ||
1289 | if ((oldflags ^ lcd.flags) & | ||
1290 | (LCD_FLAG_B | LCD_FLAG_C | LCD_FLAG_D)) | ||
1291 | /* set display mode */ | ||
1292 | lcd_write_cmd(LCD_CMD_DISPLAY_CTRL | ||
1293 | | ((lcd.flags & LCD_FLAG_D) | ||
1294 | ? LCD_CMD_DISPLAY_ON : 0) | ||
1295 | | ((lcd.flags & LCD_FLAG_C) | ||
1296 | ? LCD_CMD_CURSOR_ON : 0) | ||
1297 | | ((lcd.flags & LCD_FLAG_B) | ||
1298 | ? LCD_CMD_BLINK_ON : 0)); | ||
1299 | /* check whether one of F,N flags was changed */ | ||
1300 | else if ((oldflags ^ lcd.flags) & (LCD_FLAG_F | LCD_FLAG_N)) | ||
1301 | lcd_write_cmd(LCD_CMD_FUNCTION_SET | ||
1302 | | LCD_CMD_DATA_LEN_8BITS | ||
1303 | | ((lcd.flags & LCD_FLAG_F) | ||
1304 | ? LCD_CMD_FONT_5X10_DOTS | ||
1305 | : 0) | ||
1306 | | ((lcd.flags & LCD_FLAG_N) | ||
1307 | ? LCD_CMD_TWO_LINES | ||
1308 | : 0)); | ||
1309 | /* check whether L flag was changed */ | ||
1310 | else if ((oldflags ^ lcd.flags) & (LCD_FLAG_L)) | ||
1311 | lcd_backlight(!!(lcd.flags & LCD_FLAG_L)); | ||
1312 | } | ||
1313 | |||
1314 | return processed; | ||
1315 | } | ||
1316 | |||
1317 | static void lcd_write_char(char c) | ||
1318 | { | ||
1319 | /* first, we'll test if we're in escape mode */ | ||
1320 | if ((c != '\n') && lcd.esc_seq.len >= 0) { | ||
1321 | /* yes, let's add this char to the buffer */ | ||
1322 | lcd.esc_seq.buf[lcd.esc_seq.len++] = c; | ||
1323 | lcd.esc_seq.buf[lcd.esc_seq.len] = 0; | ||
1324 | } else { | ||
1325 | /* aborts any previous escape sequence */ | ||
1326 | lcd.esc_seq.len = -1; | ||
1327 | |||
1328 | switch (c) { | ||
1329 | case LCD_ESCAPE_CHAR: | ||
1330 | /* start of an escape sequence */ | ||
1331 | lcd.esc_seq.len = 0; | ||
1332 | lcd.esc_seq.buf[lcd.esc_seq.len] = 0; | ||
1333 | break; | ||
1334 | case '\b': | ||
1335 | /* go back one char and clear it */ | ||
1336 | if (lcd.addr.x > 0) { | ||
1337 | /* | ||
1338 | * check if we're not at the | ||
1339 | * end of the line | ||
1340 | */ | ||
1341 | if (lcd.addr.x < lcd.bwidth) | ||
1342 | /* back one char */ | ||
1343 | lcd_write_cmd(LCD_CMD_SHIFT); | ||
1344 | lcd.addr.x--; | ||
1345 | } | ||
1346 | /* replace with a space */ | ||
1347 | lcd_write_data(' '); | ||
1348 | /* back one char again */ | ||
1349 | lcd_write_cmd(LCD_CMD_SHIFT); | ||
1350 | break; | ||
1351 | case '\014': | ||
1352 | /* quickly clear the display */ | ||
1353 | lcd_clear_fast(); | ||
1354 | break; | ||
1355 | case '\n': | ||
1356 | /* | ||
1357 | * flush the remainder of the current line and | ||
1358 | * go to the beginning of the next line | ||
1359 | */ | ||
1360 | for (; lcd.addr.x < lcd.bwidth; lcd.addr.x++) | ||
1361 | lcd_write_data(' '); | ||
1362 | lcd.addr.x = 0; | ||
1363 | lcd.addr.y = (lcd.addr.y + 1) % lcd.height; | ||
1364 | lcd_gotoxy(); | ||
1365 | break; | ||
1366 | case '\r': | ||
1367 | /* go to the beginning of the same line */ | ||
1368 | lcd.addr.x = 0; | ||
1369 | lcd_gotoxy(); | ||
1370 | break; | ||
1371 | case '\t': | ||
1372 | /* print a space instead of the tab */ | ||
1373 | lcd_print(' '); | ||
1374 | break; | ||
1375 | default: | ||
1376 | /* simply print this char */ | ||
1377 | lcd_print(c); | ||
1378 | break; | ||
1379 | } | ||
1380 | } | ||
1381 | 909 | ||
1382 | /* | 910 | /* |
1383 | * now we'll see if we're in an escape mode and if the current | 911 | * Init lcd struct with load-time values to preserve exact |
1384 | * escape sequence can be understood. | 912 | * current functionality (at least for now). |
1385 | */ | 913 | */ |
1386 | if (lcd.esc_seq.len >= 2) { | 914 | charlcd->height = lcd_height; |
1387 | int processed = 0; | 915 | charlcd->width = lcd_width; |
1388 | 916 | charlcd->bwidth = lcd_bwidth; | |
1389 | if (!strcmp(lcd.esc_seq.buf, "[2J")) { | 917 | charlcd->hwidth = lcd_hwidth; |
1390 | /* clear the display */ | ||
1391 | lcd_clear_fast(); | ||
1392 | processed = 1; | ||
1393 | } else if (!strcmp(lcd.esc_seq.buf, "[H")) { | ||
1394 | /* cursor to home */ | ||
1395 | lcd_home(); | ||
1396 | processed = 1; | ||
1397 | } | ||
1398 | /* codes starting with ^[[L */ | ||
1399 | else if ((lcd.esc_seq.len >= 3) && | ||
1400 | (lcd.esc_seq.buf[0] == '[') && | ||
1401 | (lcd.esc_seq.buf[1] == 'L')) { | ||
1402 | processed = handle_lcd_special_code(); | ||
1403 | } | ||
1404 | |||
1405 | /* LCD special escape codes */ | ||
1406 | /* | ||
1407 | * flush the escape sequence if it's been processed | ||
1408 | * or if it is getting too long. | ||
1409 | */ | ||
1410 | if (processed || (lcd.esc_seq.len >= LCD_ESCAPE_LEN)) | ||
1411 | lcd.esc_seq.len = -1; | ||
1412 | } /* escape codes */ | ||
1413 | } | ||
1414 | 918 | ||
1415 | static ssize_t lcd_write(struct file *file, | ||
1416 | const char __user *buf, size_t count, loff_t *ppos) | ||
1417 | { | ||
1418 | const char __user *tmp = buf; | ||
1419 | char c; | ||
1420 | |||
1421 | for (; count-- > 0; (*ppos)++, tmp++) { | ||
1422 | if (!in_interrupt() && (((count + 1) & 0x1f) == 0)) | ||
1423 | /* | ||
1424 | * let's be a little nice with other processes | ||
1425 | * that need some CPU | ||
1426 | */ | ||
1427 | schedule(); | ||
1428 | |||
1429 | if (get_user(c, tmp)) | ||
1430 | return -EFAULT; | ||
1431 | |||
1432 | lcd_write_char(c); | ||
1433 | } | ||
1434 | |||
1435 | return tmp - buf; | ||
1436 | } | ||
1437 | |||
1438 | static int lcd_open(struct inode *inode, struct file *file) | ||
1439 | { | ||
1440 | if (!atomic_dec_and_test(&lcd_available)) | ||
1441 | return -EBUSY; /* open only once at a time */ | ||
1442 | |||
1443 | if (file->f_mode & FMODE_READ) /* device is write-only */ | ||
1444 | return -EPERM; | ||
1445 | |||
1446 | if (lcd.must_clear) { | ||
1447 | lcd_clear_display(); | ||
1448 | lcd.must_clear = false; | ||
1449 | } | ||
1450 | return nonseekable_open(inode, file); | ||
1451 | } | ||
1452 | |||
1453 | static int lcd_release(struct inode *inode, struct file *file) | ||
1454 | { | ||
1455 | atomic_inc(&lcd_available); | ||
1456 | return 0; | ||
1457 | } | ||
1458 | |||
1459 | static const struct file_operations lcd_fops = { | ||
1460 | .write = lcd_write, | ||
1461 | .open = lcd_open, | ||
1462 | .release = lcd_release, | ||
1463 | .llseek = no_llseek, | ||
1464 | }; | ||
1465 | |||
1466 | static struct miscdevice lcd_dev = { | ||
1467 | .minor = LCD_MINOR, | ||
1468 | .name = "lcd", | ||
1469 | .fops = &lcd_fops, | ||
1470 | }; | ||
1471 | |||
1472 | /* public function usable from the kernel for any purpose */ | ||
1473 | static void panel_lcd_print(const char *s) | ||
1474 | { | ||
1475 | const char *tmp = s; | ||
1476 | int count = strlen(s); | ||
1477 | |||
1478 | if (lcd.enabled && lcd.initialized) { | ||
1479 | for (; count-- > 0; tmp++) { | ||
1480 | if (!in_interrupt() && (((count + 1) & 0x1f) == 0)) | ||
1481 | /* | ||
1482 | * let's be a little nice with other processes | ||
1483 | * that need some CPU | ||
1484 | */ | ||
1485 | schedule(); | ||
1486 | |||
1487 | lcd_write_char(*tmp); | ||
1488 | } | ||
1489 | } | ||
1490 | } | ||
1491 | |||
1492 | /* initialize the LCD driver */ | ||
1493 | static void lcd_init(void) | ||
1494 | { | ||
1495 | switch (selected_lcd_type) { | 919 | switch (selected_lcd_type) { |
1496 | case LCD_TYPE_OLD: | 920 | case LCD_TYPE_OLD: |
1497 | /* parallel mode, 8 bits */ | 921 | /* parallel mode, 8 bits */ |
@@ -1500,10 +924,10 @@ static void lcd_init(void) | |||
1500 | lcd.pins.e = PIN_STROBE; | 924 | lcd.pins.e = PIN_STROBE; |
1501 | lcd.pins.rs = PIN_AUTOLF; | 925 | lcd.pins.rs = PIN_AUTOLF; |
1502 | 926 | ||
1503 | lcd.width = 40; | 927 | charlcd->width = 40; |
1504 | lcd.bwidth = 40; | 928 | charlcd->bwidth = 40; |
1505 | lcd.hwidth = 64; | 929 | charlcd->hwidth = 64; |
1506 | lcd.height = 2; | 930 | charlcd->height = 2; |
1507 | break; | 931 | break; |
1508 | case LCD_TYPE_KS0074: | 932 | case LCD_TYPE_KS0074: |
1509 | /* serial mode, ks0074 */ | 933 | /* serial mode, ks0074 */ |
@@ -1513,10 +937,10 @@ static void lcd_init(void) | |||
1513 | lcd.pins.cl = PIN_STROBE; | 937 | lcd.pins.cl = PIN_STROBE; |
1514 | lcd.pins.da = PIN_D0; | 938 | lcd.pins.da = PIN_D0; |
1515 | 939 | ||
1516 | lcd.width = 16; | 940 | charlcd->width = 16; |
1517 | lcd.bwidth = 40; | 941 | charlcd->bwidth = 40; |
1518 | lcd.hwidth = 16; | 942 | charlcd->hwidth = 16; |
1519 | lcd.height = 2; | 943 | charlcd->height = 2; |
1520 | break; | 944 | break; |
1521 | case LCD_TYPE_NEXCOM: | 945 | case LCD_TYPE_NEXCOM: |
1522 | /* parallel mode, 8 bits, generic */ | 946 | /* parallel mode, 8 bits, generic */ |
@@ -1526,10 +950,10 @@ static void lcd_init(void) | |||
1526 | lcd.pins.rs = PIN_SELECP; | 950 | lcd.pins.rs = PIN_SELECP; |
1527 | lcd.pins.rw = PIN_INITP; | 951 | lcd.pins.rw = PIN_INITP; |
1528 | 952 | ||
1529 | lcd.width = 16; | 953 | charlcd->width = 16; |
1530 | lcd.bwidth = 40; | 954 | charlcd->bwidth = 40; |
1531 | lcd.hwidth = 64; | 955 | charlcd->hwidth = 64; |
1532 | lcd.height = 2; | 956 | charlcd->height = 2; |
1533 | break; | 957 | break; |
1534 | case LCD_TYPE_CUSTOM: | 958 | case LCD_TYPE_CUSTOM: |
1535 | /* customer-defined */ | 959 | /* customer-defined */ |
@@ -1545,22 +969,22 @@ static void lcd_init(void) | |||
1545 | lcd.pins.e = PIN_STROBE; | 969 | lcd.pins.e = PIN_STROBE; |
1546 | lcd.pins.rs = PIN_SELECP; | 970 | lcd.pins.rs = PIN_SELECP; |
1547 | 971 | ||
1548 | lcd.width = 16; | 972 | charlcd->width = 16; |
1549 | lcd.bwidth = 40; | 973 | charlcd->bwidth = 40; |
1550 | lcd.hwidth = 64; | 974 | charlcd->hwidth = 64; |
1551 | lcd.height = 2; | 975 | charlcd->height = 2; |
1552 | break; | 976 | break; |
1553 | } | 977 | } |
1554 | 978 | ||
1555 | /* Overwrite with module params set on loading */ | 979 | /* Overwrite with module params set on loading */ |
1556 | if (lcd_height != NOT_SET) | 980 | if (lcd_height != NOT_SET) |
1557 | lcd.height = lcd_height; | 981 | charlcd->height = lcd_height; |
1558 | if (lcd_width != NOT_SET) | 982 | if (lcd_width != NOT_SET) |
1559 | lcd.width = lcd_width; | 983 | charlcd->width = lcd_width; |
1560 | if (lcd_bwidth != NOT_SET) | 984 | if (lcd_bwidth != NOT_SET) |
1561 | lcd.bwidth = lcd_bwidth; | 985 | charlcd->bwidth = lcd_bwidth; |
1562 | if (lcd_hwidth != NOT_SET) | 986 | if (lcd_hwidth != NOT_SET) |
1563 | lcd.hwidth = lcd_hwidth; | 987 | charlcd->hwidth = lcd_hwidth; |
1564 | if (lcd_charset != NOT_SET) | 988 | if (lcd_charset != NOT_SET) |
1565 | lcd.charset = lcd_charset; | 989 | lcd.charset = lcd_charset; |
1566 | if (lcd_proto != NOT_SET) | 990 | if (lcd_proto != NOT_SET) |
@@ -1579,19 +1003,17 @@ static void lcd_init(void) | |||
1579 | lcd.pins.bl = lcd_bl_pin; | 1003 | lcd.pins.bl = lcd_bl_pin; |
1580 | 1004 | ||
1581 | /* this is used to catch wrong and default values */ | 1005 | /* this is used to catch wrong and default values */ |
1582 | if (lcd.width <= 0) | 1006 | if (charlcd->width <= 0) |
1583 | lcd.width = DEFAULT_LCD_WIDTH; | 1007 | charlcd->width = DEFAULT_LCD_WIDTH; |
1584 | if (lcd.bwidth <= 0) | 1008 | if (charlcd->bwidth <= 0) |
1585 | lcd.bwidth = DEFAULT_LCD_BWIDTH; | 1009 | charlcd->bwidth = DEFAULT_LCD_BWIDTH; |
1586 | if (lcd.hwidth <= 0) | 1010 | if (charlcd->hwidth <= 0) |
1587 | lcd.hwidth = DEFAULT_LCD_HWIDTH; | 1011 | charlcd->hwidth = DEFAULT_LCD_HWIDTH; |
1588 | if (lcd.height <= 0) | 1012 | if (charlcd->height <= 0) |
1589 | lcd.height = DEFAULT_LCD_HEIGHT; | 1013 | charlcd->height = DEFAULT_LCD_HEIGHT; |
1590 | 1014 | ||
1591 | if (lcd.proto == LCD_PROTO_SERIAL) { /* SERIAL */ | 1015 | if (lcd.proto == LCD_PROTO_SERIAL) { /* SERIAL */ |
1592 | lcd_write_cmd = lcd_write_cmd_s; | 1016 | charlcd->ops = &charlcd_serial_ops; |
1593 | lcd_write_data = lcd_write_data_s; | ||
1594 | lcd_clear_fast = lcd_clear_fast_s; | ||
1595 | 1017 | ||
1596 | if (lcd.pins.cl == PIN_NOT_SET) | 1018 | if (lcd.pins.cl == PIN_NOT_SET) |
1597 | lcd.pins.cl = DEFAULT_LCD_PIN_SCL; | 1019 | lcd.pins.cl = DEFAULT_LCD_PIN_SCL; |
@@ -1599,9 +1021,7 @@ static void lcd_init(void) | |||
1599 | lcd.pins.da = DEFAULT_LCD_PIN_SDA; | 1021 | lcd.pins.da = DEFAULT_LCD_PIN_SDA; |
1600 | 1022 | ||
1601 | } else if (lcd.proto == LCD_PROTO_PARALLEL) { /* PARALLEL */ | 1023 | } else if (lcd.proto == LCD_PROTO_PARALLEL) { /* PARALLEL */ |
1602 | lcd_write_cmd = lcd_write_cmd_p8; | 1024 | charlcd->ops = &charlcd_parallel_ops; |
1603 | lcd_write_data = lcd_write_data_p8; | ||
1604 | lcd_clear_fast = lcd_clear_fast_p8; | ||
1605 | 1025 | ||
1606 | if (lcd.pins.e == PIN_NOT_SET) | 1026 | if (lcd.pins.e == PIN_NOT_SET) |
1607 | lcd.pins.e = DEFAULT_LCD_PIN_E; | 1027 | lcd.pins.e = DEFAULT_LCD_PIN_E; |
@@ -1610,9 +1030,7 @@ static void lcd_init(void) | |||
1610 | if (lcd.pins.rw == PIN_NOT_SET) | 1030 | if (lcd.pins.rw == PIN_NOT_SET) |
1611 | lcd.pins.rw = DEFAULT_LCD_PIN_RW; | 1031 | lcd.pins.rw = DEFAULT_LCD_PIN_RW; |
1612 | } else { | 1032 | } else { |
1613 | lcd_write_cmd = lcd_write_cmd_tilcd; | 1033 | charlcd->ops = &charlcd_tilcd_ops; |
1614 | lcd_write_data = lcd_write_data_tilcd; | ||
1615 | lcd_clear_fast = lcd_clear_fast_tilcd; | ||
1616 | } | 1034 | } |
1617 | 1035 | ||
1618 | if (lcd.pins.bl == PIN_NOT_SET) | 1036 | if (lcd.pins.bl == PIN_NOT_SET) |
@@ -1635,14 +1053,9 @@ static void lcd_init(void) | |||
1635 | lcd.charset = DEFAULT_LCD_CHARSET; | 1053 | lcd.charset = DEFAULT_LCD_CHARSET; |
1636 | 1054 | ||
1637 | if (lcd.charset == LCD_CHARSET_KS0074) | 1055 | if (lcd.charset == LCD_CHARSET_KS0074) |
1638 | lcd_char_conv = lcd_char_conv_ks0074; | 1056 | charlcd->char_conv = lcd_char_conv_ks0074; |
1639 | else | 1057 | else |
1640 | lcd_char_conv = NULL; | 1058 | charlcd->char_conv = NULL; |
1641 | |||
1642 | if (lcd.pins.bl != PIN_NONE) { | ||
1643 | mutex_init(&lcd.bl_tempo_lock); | ||
1644 | INIT_DELAYED_WORK(&lcd.bl_work, lcd_bl_off); | ||
1645 | } | ||
1646 | 1059 | ||
1647 | pin_to_bits(lcd.pins.e, lcd_bits[LCD_PORT_D][LCD_BIT_E], | 1060 | pin_to_bits(lcd.pins.e, lcd_bits[LCD_PORT_D][LCD_BIT_E], |
1648 | lcd_bits[LCD_PORT_C][LCD_BIT_E]); | 1061 | lcd_bits[LCD_PORT_C][LCD_BIT_E]); |
@@ -1657,25 +1070,8 @@ static void lcd_init(void) | |||
1657 | pin_to_bits(lcd.pins.da, lcd_bits[LCD_PORT_D][LCD_BIT_DA], | 1070 | pin_to_bits(lcd.pins.da, lcd_bits[LCD_PORT_D][LCD_BIT_DA], |
1658 | lcd_bits[LCD_PORT_C][LCD_BIT_DA]); | 1071 | lcd_bits[LCD_PORT_C][LCD_BIT_DA]); |
1659 | 1072 | ||
1660 | /* | 1073 | lcd.charlcd = charlcd; |
1661 | * before this line, we must NOT send anything to the display. | ||
1662 | * Since lcd_init_display() needs to write data, we have to | ||
1663 | * enable mark the LCD initialized just before. | ||
1664 | */ | ||
1665 | lcd.initialized = true; | 1074 | lcd.initialized = true; |
1666 | lcd_init_display(); | ||
1667 | |||
1668 | /* display a short message */ | ||
1669 | #ifdef CONFIG_PANEL_CHANGE_MESSAGE | ||
1670 | #ifdef CONFIG_PANEL_BOOT_MESSAGE | ||
1671 | panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE); | ||
1672 | #endif | ||
1673 | #else | ||
1674 | panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE); | ||
1675 | #endif | ||
1676 | /* clear the display on the next device opening */ | ||
1677 | lcd.must_clear = true; | ||
1678 | lcd_home(); | ||
1679 | } | 1075 | } |
1680 | 1076 | ||
1681 | /* | 1077 | /* |
@@ -2011,7 +1407,7 @@ static void panel_scan_timer(void) | |||
2011 | } | 1407 | } |
2012 | 1408 | ||
2013 | if (keypressed && lcd.enabled && lcd.initialized) | 1409 | if (keypressed && lcd.enabled && lcd.initialized) |
2014 | lcd_poke(); | 1410 | charlcd_poke(lcd.charlcd); |
2015 | 1411 | ||
2016 | mod_timer(&scan_timer, jiffies + INPUT_POLL_TIME); | 1412 | mod_timer(&scan_timer, jiffies + INPUT_POLL_TIME); |
2017 | } | 1413 | } |
@@ -2175,35 +1571,6 @@ static void keypad_init(void) | |||
2175 | /* device initialization */ | 1571 | /* device initialization */ |
2176 | /**************************************************/ | 1572 | /**************************************************/ |
2177 | 1573 | ||
2178 | static int panel_notify_sys(struct notifier_block *this, unsigned long code, | ||
2179 | void *unused) | ||
2180 | { | ||
2181 | if (lcd.enabled && lcd.initialized) { | ||
2182 | switch (code) { | ||
2183 | case SYS_DOWN: | ||
2184 | panel_lcd_print | ||
2185 | ("\x0cReloading\nSystem...\x1b[Lc\x1b[Lb\x1b[L+"); | ||
2186 | break; | ||
2187 | case SYS_HALT: | ||
2188 | panel_lcd_print | ||
2189 | ("\x0cSystem Halted.\x1b[Lc\x1b[Lb\x1b[L+"); | ||
2190 | break; | ||
2191 | case SYS_POWER_OFF: | ||
2192 | panel_lcd_print("\x0cPower off.\x1b[Lc\x1b[Lb\x1b[L+"); | ||
2193 | break; | ||
2194 | default: | ||
2195 | break; | ||
2196 | } | ||
2197 | } | ||
2198 | return NOTIFY_DONE; | ||
2199 | } | ||
2200 | |||
2201 | static struct notifier_block panel_notifier = { | ||
2202 | panel_notify_sys, | ||
2203 | NULL, | ||
2204 | 0 | ||
2205 | }; | ||
2206 | |||
2207 | static void panel_attach(struct parport *port) | 1574 | static void panel_attach(struct parport *port) |
2208 | { | 1575 | { |
2209 | struct pardev_cb panel_cb; | 1576 | struct pardev_cb panel_cb; |
@@ -2239,7 +1606,7 @@ static void panel_attach(struct parport *port) | |||
2239 | */ | 1606 | */ |
2240 | if (lcd.enabled) { | 1607 | if (lcd.enabled) { |
2241 | lcd_init(); | 1608 | lcd_init(); |
2242 | if (misc_register(&lcd_dev)) | 1609 | if (!lcd.charlcd || charlcd_register(lcd.charlcd)) |
2243 | goto err_unreg_device; | 1610 | goto err_unreg_device; |
2244 | } | 1611 | } |
2245 | 1612 | ||
@@ -2248,13 +1615,14 @@ static void panel_attach(struct parport *port) | |||
2248 | if (misc_register(&keypad_dev)) | 1615 | if (misc_register(&keypad_dev)) |
2249 | goto err_lcd_unreg; | 1616 | goto err_lcd_unreg; |
2250 | } | 1617 | } |
2251 | register_reboot_notifier(&panel_notifier); | ||
2252 | return; | 1618 | return; |
2253 | 1619 | ||
2254 | err_lcd_unreg: | 1620 | err_lcd_unreg: |
2255 | if (lcd.enabled) | 1621 | if (lcd.enabled) |
2256 | misc_deregister(&lcd_dev); | 1622 | charlcd_unregister(lcd.charlcd); |
2257 | err_unreg_device: | 1623 | err_unreg_device: |
1624 | kfree(lcd.charlcd); | ||
1625 | lcd.charlcd = NULL; | ||
2258 | parport_unregister_device(pprt); | 1626 | parport_unregister_device(pprt); |
2259 | pprt = NULL; | 1627 | pprt = NULL; |
2260 | } | 1628 | } |
@@ -2278,20 +1646,16 @@ static void panel_detach(struct parport *port) | |||
2278 | } | 1646 | } |
2279 | 1647 | ||
2280 | if (lcd.enabled) { | 1648 | if (lcd.enabled) { |
2281 | panel_lcd_print("\x0cLCD driver unloaded.\x1b[Lc\x1b[Lb\x1b[L-"); | 1649 | charlcd_unregister(lcd.charlcd); |
2282 | misc_deregister(&lcd_dev); | ||
2283 | if (lcd.pins.bl != PIN_NONE) { | ||
2284 | cancel_delayed_work_sync(&lcd.bl_work); | ||
2285 | __lcd_backlight(0); | ||
2286 | } | ||
2287 | lcd.initialized = false; | 1650 | lcd.initialized = false; |
1651 | kfree(lcd.charlcd); | ||
1652 | lcd.charlcd = NULL; | ||
2288 | } | 1653 | } |
2289 | 1654 | ||
2290 | /* TODO: free all input signals */ | 1655 | /* TODO: free all input signals */ |
2291 | parport_release(pprt); | 1656 | parport_release(pprt); |
2292 | parport_unregister_device(pprt); | 1657 | parport_unregister_device(pprt); |
2293 | pprt = NULL; | 1658 | pprt = NULL; |
2294 | unregister_reboot_notifier(&panel_notifier); | ||
2295 | } | 1659 | } |
2296 | 1660 | ||
2297 | static struct parport_driver panel_driver = { | 1661 | static struct parport_driver panel_driver = { |
@@ -2369,10 +1733,6 @@ static int __init panel_init_module(void) | |||
2369 | * Init lcd struct with load-time values to preserve exact | 1733 | * Init lcd struct with load-time values to preserve exact |
2370 | * current functionality (at least for now). | 1734 | * current functionality (at least for now). |
2371 | */ | 1735 | */ |
2372 | lcd.height = lcd_height; | ||
2373 | lcd.width = lcd_width; | ||
2374 | lcd.bwidth = lcd_bwidth; | ||
2375 | lcd.hwidth = lcd_hwidth; | ||
2376 | lcd.charset = lcd_charset; | 1736 | lcd.charset = lcd_charset; |
2377 | lcd.proto = lcd_proto; | 1737 | lcd.proto = lcd_proto; |
2378 | lcd.pins.e = lcd_e_pin; | 1738 | lcd.pins.e = lcd_e_pin; |
@@ -2381,9 +1741,6 @@ static int __init panel_init_module(void) | |||
2381 | lcd.pins.cl = lcd_cl_pin; | 1741 | lcd.pins.cl = lcd_cl_pin; |
2382 | lcd.pins.da = lcd_da_pin; | 1742 | lcd.pins.da = lcd_da_pin; |
2383 | lcd.pins.bl = lcd_bl_pin; | 1743 | lcd.pins.bl = lcd_bl_pin; |
2384 | |||
2385 | /* Leave it for now, just in case */ | ||
2386 | lcd.esc_seq.len = -1; | ||
2387 | } | 1744 | } |
2388 | 1745 | ||
2389 | switch (selected_keypad_type) { | 1746 | switch (selected_keypad_type) { |
diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index 4f337375252e..5406b90bf626 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c | |||
@@ -32,7 +32,7 @@ | |||
32 | * timer and 180 seconds for the margin of error. IOW, a timer is set | 32 | * timer and 180 seconds for the margin of error. IOW, a timer is set |
33 | * for 60 seconds. When the timer fires, the callback checks the | 33 | * for 60 seconds. When the timer fires, the callback checks the |
34 | * actual duration that the timer waited. If the duration exceeds the | 34 | * actual duration that the timer waited. If the duration exceeds the |
35 | * alloted time and margin (here 60 + 180, or 240 seconds), the machine | 35 | * allotted time and margin (here 60 + 180, or 240 seconds), the machine |
36 | * is restarted. A healthy machine will have the duration match the | 36 | * is restarted. A healthy machine will have the duration match the |
37 | * expected timeout very closely. | 37 | * expected timeout very closely. |
38 | */ | 38 | */ |
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 8bdc38d81adf..b941e6d59fd6 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c | |||
@@ -575,7 +575,7 @@ static inline unsigned long hpet_time_div(struct hpets *hpets, | |||
575 | } | 575 | } |
576 | 576 | ||
577 | static int | 577 | static int |
578 | hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, | 578 | hpet_ioctl_common(struct hpet_dev *devp, unsigned int cmd, unsigned long arg, |
579 | struct hpet_info *info) | 579 | struct hpet_info *info) |
580 | { | 580 | { |
581 | struct hpet_timer __iomem *timer; | 581 | struct hpet_timer __iomem *timer; |
diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 8069b361b8dd..c9cd1ea6844a 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c | |||
@@ -109,7 +109,7 @@ static const struct file_operations misc_proc_fops = { | |||
109 | }; | 109 | }; |
110 | #endif | 110 | #endif |
111 | 111 | ||
112 | static int misc_open(struct inode * inode, struct file * file) | 112 | static int misc_open(struct inode *inode, struct file *file) |
113 | { | 113 | { |
114 | int minor = iminor(inode); | 114 | int minor = iminor(inode); |
115 | struct miscdevice *c; | 115 | struct miscdevice *c; |
@@ -150,7 +150,7 @@ static int misc_open(struct inode * inode, struct file * file) | |||
150 | err = 0; | 150 | err = 0; |
151 | replace_fops(file, new_fops); | 151 | replace_fops(file, new_fops); |
152 | if (file->f_op->open) | 152 | if (file->f_op->open) |
153 | err = file->f_op->open(inode,file); | 153 | err = file->f_op->open(inode, file); |
154 | fail: | 154 | fail: |
155 | mutex_unlock(&misc_mtx); | 155 | mutex_unlock(&misc_mtx); |
156 | return err; | 156 | return err; |
@@ -182,7 +182,7 @@ static const struct file_operations misc_fops = { | |||
182 | * failure. | 182 | * failure. |
183 | */ | 183 | */ |
184 | 184 | ||
185 | int misc_register(struct miscdevice * misc) | 185 | int misc_register(struct miscdevice *misc) |
186 | { | 186 | { |
187 | dev_t dev; | 187 | dev_t dev; |
188 | int err = 0; | 188 | int err = 0; |
@@ -194,6 +194,7 @@ int misc_register(struct miscdevice * misc) | |||
194 | 194 | ||
195 | if (is_dynamic) { | 195 | if (is_dynamic) { |
196 | int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); | 196 | int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); |
197 | |||
197 | if (i >= DYNAMIC_MINORS) { | 198 | if (i >= DYNAMIC_MINORS) { |
198 | err = -EBUSY; | 199 | err = -EBUSY; |
199 | goto out; | 200 | goto out; |
@@ -287,13 +288,13 @@ static int __init misc_init(void) | |||
287 | goto fail_remove; | 288 | goto fail_remove; |
288 | 289 | ||
289 | err = -EIO; | 290 | err = -EIO; |
290 | if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) | 291 | if (register_chrdev(MISC_MAJOR, "misc", &misc_fops)) |
291 | goto fail_printk; | 292 | goto fail_printk; |
292 | misc_class->devnode = misc_devnode; | 293 | misc_class->devnode = misc_devnode; |
293 | return 0; | 294 | return 0; |
294 | 295 | ||
295 | fail_printk: | 296 | fail_printk: |
296 | printk("unable to get major %d for misc devices\n", MISC_MAJOR); | 297 | pr_err("unable to get major %d for misc devices\n", MISC_MAJOR); |
297 | class_destroy(misc_class); | 298 | class_destroy(misc_class); |
298 | fail_remove: | 299 | fail_remove: |
299 | if (ret) | 300 | if (ret) |
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index a9c2fa3c81e5..7b75669d3670 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <linux/string.h> | 43 | #include <linux/string.h> |
44 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
45 | #include <linux/numa.h> | 45 | #include <linux/numa.h> |
46 | #include <linux/refcount.h> | ||
46 | #include <asm/page.h> | 47 | #include <asm/page.h> |
47 | #include <asm/pgtable.h> | 48 | #include <asm/pgtable.h> |
48 | #include <linux/atomic.h> | 49 | #include <linux/atomic.h> |
@@ -89,7 +90,7 @@ static int is_sn2; | |||
89 | * protect in fork case where multiple tasks share the vma_data. | 90 | * protect in fork case where multiple tasks share the vma_data. |
90 | */ | 91 | */ |
91 | struct vma_data { | 92 | struct vma_data { |
92 | atomic_t refcnt; /* Number of vmas sharing the data. */ | 93 | refcount_t refcnt; /* Number of vmas sharing the data. */ |
93 | spinlock_t lock; /* Serialize access to this structure. */ | 94 | spinlock_t lock; /* Serialize access to this structure. */ |
94 | int count; /* Number of pages allocated. */ | 95 | int count; /* Number of pages allocated. */ |
95 | enum mspec_page_type type; /* Type of pages allocated. */ | 96 | enum mspec_page_type type; /* Type of pages allocated. */ |
@@ -144,7 +145,7 @@ mspec_open(struct vm_area_struct *vma) | |||
144 | struct vma_data *vdata; | 145 | struct vma_data *vdata; |
145 | 146 | ||
146 | vdata = vma->vm_private_data; | 147 | vdata = vma->vm_private_data; |
147 | atomic_inc(&vdata->refcnt); | 148 | refcount_inc(&vdata->refcnt); |
148 | } | 149 | } |
149 | 150 | ||
150 | /* | 151 | /* |
@@ -162,7 +163,7 @@ mspec_close(struct vm_area_struct *vma) | |||
162 | 163 | ||
163 | vdata = vma->vm_private_data; | 164 | vdata = vma->vm_private_data; |
164 | 165 | ||
165 | if (!atomic_dec_and_test(&vdata->refcnt)) | 166 | if (!refcount_dec_and_test(&vdata->refcnt)) |
166 | return; | 167 | return; |
167 | 168 | ||
168 | last_index = (vdata->vm_end - vdata->vm_start) >> PAGE_SHIFT; | 169 | last_index = (vdata->vm_end - vdata->vm_start) >> PAGE_SHIFT; |
@@ -274,7 +275,7 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma, | |||
274 | vdata->vm_end = vma->vm_end; | 275 | vdata->vm_end = vma->vm_end; |
275 | vdata->type = type; | 276 | vdata->type = type; |
276 | spin_lock_init(&vdata->lock); | 277 | spin_lock_init(&vdata->lock); |
277 | atomic_set(&vdata->refcnt, 1); | 278 | refcount_set(&vdata->refcnt, 1); |
278 | vma->vm_private_data = vdata; | 279 | vma->vm_private_data = vdata; |
279 | 280 | ||
280 | vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; | 281 | vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; |
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 9dec9f551b83..322b8a51ffc6 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c | |||
@@ -218,8 +218,6 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, | |||
218 | cdev_init(&chip->cdevs, &tpmrm_fops); | 218 | cdev_init(&chip->cdevs, &tpmrm_fops); |
219 | chip->cdev.owner = THIS_MODULE; | 219 | chip->cdev.owner = THIS_MODULE; |
220 | chip->cdevs.owner = THIS_MODULE; | 220 | chip->cdevs.owner = THIS_MODULE; |
221 | chip->cdev.kobj.parent = &chip->dev.kobj; | ||
222 | chip->cdevs.kobj.parent = &chip->devs.kobj; | ||
223 | 221 | ||
224 | chip->work_space.context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); | 222 | chip->work_space.context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); |
225 | if (!chip->work_space.context_buf) { | 223 | if (!chip->work_space.context_buf) { |
@@ -275,45 +273,24 @@ static int tpm_add_char_device(struct tpm_chip *chip) | |||
275 | { | 273 | { |
276 | int rc; | 274 | int rc; |
277 | 275 | ||
278 | rc = cdev_add(&chip->cdev, chip->dev.devt, 1); | 276 | rc = cdev_device_add(&chip->cdev, &chip->dev); |
279 | if (rc) { | 277 | if (rc) { |
280 | dev_err(&chip->dev, | 278 | dev_err(&chip->dev, |
281 | "unable to cdev_add() %s, major %d, minor %d, err=%d\n", | 279 | "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n", |
282 | dev_name(&chip->dev), MAJOR(chip->dev.devt), | 280 | dev_name(&chip->dev), MAJOR(chip->dev.devt), |
283 | MINOR(chip->dev.devt), rc); | 281 | MINOR(chip->dev.devt), rc); |
284 | return rc; | 282 | return rc; |
285 | } | 283 | } |
286 | 284 | ||
287 | rc = device_add(&chip->dev); | 285 | if (chip->flags & TPM_CHIP_FLAG_TPM2) { |
288 | if (rc) { | 286 | rc = cdev_device_add(&chip->cdevs, &chip->devs); |
289 | dev_err(&chip->dev, | 287 | if (rc) { |
290 | "unable to device_register() %s, major %d, minor %d, err=%d\n", | 288 | dev_err(&chip->devs, |
291 | dev_name(&chip->dev), MAJOR(chip->dev.devt), | 289 | "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n", |
292 | MINOR(chip->dev.devt), rc); | 290 | dev_name(&chip->devs), MAJOR(chip->devs.devt), |
293 | 291 | MINOR(chip->devs.devt), rc); | |
294 | cdev_del(&chip->cdev); | 292 | return rc; |
295 | return rc; | 293 | } |
296 | } | ||
297 | |||
298 | if (chip->flags & TPM_CHIP_FLAG_TPM2) | ||
299 | rc = cdev_add(&chip->cdevs, chip->devs.devt, 1); | ||
300 | if (rc) { | ||
301 | dev_err(&chip->dev, | ||
302 | "unable to cdev_add() %s, major %d, minor %d, err=%d\n", | ||
303 | dev_name(&chip->devs), MAJOR(chip->devs.devt), | ||
304 | MINOR(chip->devs.devt), rc); | ||
305 | return rc; | ||
306 | } | ||
307 | |||
308 | if (chip->flags & TPM_CHIP_FLAG_TPM2) | ||
309 | rc = device_add(&chip->devs); | ||
310 | if (rc) { | ||
311 | dev_err(&chip->dev, | ||
312 | "unable to device_register() %s, major %d, minor %d, err=%d\n", | ||
313 | dev_name(&chip->devs), MAJOR(chip->devs.devt), | ||
314 | MINOR(chip->devs.devt), rc); | ||
315 | cdev_del(&chip->cdevs); | ||
316 | return rc; | ||
317 | } | 294 | } |
318 | 295 | ||
319 | /* Make the chip available. */ | 296 | /* Make the chip available. */ |
@@ -326,8 +303,7 @@ static int tpm_add_char_device(struct tpm_chip *chip) | |||
326 | 303 | ||
327 | static void tpm_del_char_device(struct tpm_chip *chip) | 304 | static void tpm_del_char_device(struct tpm_chip *chip) |
328 | { | 305 | { |
329 | cdev_del(&chip->cdev); | 306 | cdev_device_del(&chip->cdev, &chip->dev); |
330 | device_del(&chip->dev); | ||
331 | 307 | ||
332 | /* Make the chip unavailable. */ | 308 | /* Make the chip unavailable. */ |
333 | mutex_lock(&idr_lock); | 309 | mutex_lock(&idr_lock); |
@@ -449,10 +425,8 @@ void tpm_chip_unregister(struct tpm_chip *chip) | |||
449 | { | 425 | { |
450 | tpm_del_legacy_sysfs(chip); | 426 | tpm_del_legacy_sysfs(chip); |
451 | tpm_bios_log_teardown(chip); | 427 | tpm_bios_log_teardown(chip); |
452 | if (chip->flags & TPM_CHIP_FLAG_TPM2) { | 428 | if (chip->flags & TPM_CHIP_FLAG_TPM2) |
453 | cdev_del(&chip->cdevs); | 429 | cdev_device_del(&chip->cdevs, &chip->devs); |
454 | device_del(&chip->devs); | ||
455 | } | ||
456 | tpm_del_char_device(chip); | 430 | tpm_del_char_device(chip); |
457 | } | 431 | } |
458 | EXPORT_SYMBOL_GPL(tpm_chip_unregister); | 432 | EXPORT_SYMBOL_GPL(tpm_chip_unregister); |
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 87fe111d0be6..7d041d026680 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c | |||
@@ -2304,7 +2304,7 @@ static int __init init(void) | |||
2304 | 2304 | ||
2305 | pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL); | 2305 | pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL); |
2306 | if (!pdrvdata.debugfs_dir) | 2306 | if (!pdrvdata.debugfs_dir) |
2307 | pr_warning("Error creating debugfs dir for virtio-ports\n"); | 2307 | pr_warn("Error creating debugfs dir for virtio-ports\n"); |
2308 | INIT_LIST_HEAD(&pdrvdata.consoles); | 2308 | INIT_LIST_HEAD(&pdrvdata.consoles); |
2309 | INIT_LIST_HEAD(&pdrvdata.portdevs); | 2309 | INIT_LIST_HEAD(&pdrvdata.portdevs); |
2310 | 2310 | ||
diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index 806f180c80d8..19795eb35579 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c | |||
@@ -703,13 +703,8 @@ static void dax_dev_release(struct device *dev) | |||
703 | kfree(dax_dev); | 703 | kfree(dax_dev); |
704 | } | 704 | } |
705 | 705 | ||
706 | static void unregister_dax_dev(void *dev) | 706 | static void kill_dax_dev(struct dax_dev *dax_dev) |
707 | { | 707 | { |
708 | struct dax_dev *dax_dev = to_dax_dev(dev); | ||
709 | struct cdev *cdev = &dax_dev->cdev; | ||
710 | |||
711 | dev_dbg(dev, "%s\n", __func__); | ||
712 | |||
713 | /* | 708 | /* |
714 | * Note, rcu is not protecting the liveness of dax_dev, rcu is | 709 | * Note, rcu is not protecting the liveness of dax_dev, rcu is |
715 | * ensuring that any fault handlers that might have seen | 710 | * ensuring that any fault handlers that might have seen |
@@ -720,8 +715,17 @@ static void unregister_dax_dev(void *dev) | |||
720 | dax_dev->alive = false; | 715 | dax_dev->alive = false; |
721 | synchronize_srcu(&dax_srcu); | 716 | synchronize_srcu(&dax_srcu); |
722 | unmap_mapping_range(dax_dev->inode->i_mapping, 0, 0, 1); | 717 | unmap_mapping_range(dax_dev->inode->i_mapping, 0, 0, 1); |
723 | cdev_del(cdev); | 718 | } |
724 | device_unregister(dev); | 719 | |
720 | static void unregister_dax_dev(void *dev) | ||
721 | { | ||
722 | struct dax_dev *dax_dev = to_dax_dev(dev); | ||
723 | |||
724 | dev_dbg(dev, "%s\n", __func__); | ||
725 | |||
726 | kill_dax_dev(dax_dev); | ||
727 | cdev_device_del(&dax_dev->cdev, dev); | ||
728 | put_device(dev); | ||
725 | } | 729 | } |
726 | 730 | ||
727 | struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, | 731 | struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, |
@@ -772,18 +776,13 @@ struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, | |||
772 | goto err_inode; | 776 | goto err_inode; |
773 | } | 777 | } |
774 | 778 | ||
775 | /* device_initialize() so cdev can reference kobj parent */ | 779 | /* from here on we're committed to teardown via dax_dev_release() */ |
776 | device_initialize(dev); | 780 | device_initialize(dev); |
777 | 781 | ||
778 | cdev = &dax_dev->cdev; | 782 | cdev = &dax_dev->cdev; |
779 | cdev_init(cdev, &dax_fops); | 783 | cdev_init(cdev, &dax_fops); |
780 | cdev->owner = parent->driver->owner; | 784 | cdev->owner = parent->driver->owner; |
781 | cdev->kobj.parent = &dev->kobj; | ||
782 | rc = cdev_add(&dax_dev->cdev, dev_t, 1); | ||
783 | if (rc) | ||
784 | goto err_cdev; | ||
785 | 785 | ||
786 | /* from here on we're committed to teardown via dax_dev_release() */ | ||
787 | dax_dev->num_resources = count; | 786 | dax_dev->num_resources = count; |
788 | dax_dev->alive = true; | 787 | dax_dev->alive = true; |
789 | dax_dev->region = dax_region; | 788 | dax_dev->region = dax_region; |
@@ -795,8 +794,10 @@ struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, | |||
795 | dev->groups = dax_attribute_groups; | 794 | dev->groups = dax_attribute_groups; |
796 | dev->release = dax_dev_release; | 795 | dev->release = dax_dev_release; |
797 | dev_set_name(dev, "dax%d.%d", dax_region->id, dax_dev->id); | 796 | dev_set_name(dev, "dax%d.%d", dax_region->id, dax_dev->id); |
798 | rc = device_add(dev); | 797 | |
798 | rc = cdev_device_add(cdev, dev); | ||
799 | if (rc) { | 799 | if (rc) { |
800 | kill_dax_dev(dax_dev); | ||
800 | put_device(dev); | 801 | put_device(dev); |
801 | return ERR_PTR(rc); | 802 | return ERR_PTR(rc); |
802 | } | 803 | } |
@@ -807,8 +808,6 @@ struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region, | |||
807 | 808 | ||
808 | return dax_dev; | 809 | return dax_dev; |
809 | 810 | ||
810 | err_cdev: | ||
811 | iput(dax_dev->inode); | ||
812 | err_inode: | 811 | err_inode: |
813 | ida_simple_remove(&dax_minor_ida, minor); | 812 | ida_simple_remove(&dax_minor_ida, minor); |
814 | err_minor: | 813 | err_minor: |
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index fc09c76248b4..32f2dc8e4702 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig | |||
@@ -52,6 +52,13 @@ config EXTCON_INTEL_INT3496 | |||
52 | This ACPI device is typically found on Intel Baytrail or Cherrytrail | 52 | This ACPI device is typically found on Intel Baytrail or Cherrytrail |
53 | based tablets, or other Baytrail / Cherrytrail devices. | 53 | based tablets, or other Baytrail / Cherrytrail devices. |
54 | 54 | ||
55 | config EXTCON_INTEL_CHT_WC | ||
56 | tristate "Intel Cherrytrail Whiskey Cove PMIC extcon driver" | ||
57 | depends on INTEL_SOC_PMIC_CHTWC | ||
58 | help | ||
59 | Say Y here to enable extcon support for charger detection / control | ||
60 | on the Intel Cherrytrail Whiskey Cove PMIC. | ||
61 | |||
55 | config EXTCON_MAX14577 | 62 | config EXTCON_MAX14577 |
56 | tristate "Maxim MAX14577/77836 EXTCON Support" | 63 | tristate "Maxim MAX14577/77836 EXTCON Support" |
57 | depends on MFD_MAX14577 | 64 | depends on MFD_MAX14577 |
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile index 237ac3f953c2..ecfa95804427 100644 --- a/drivers/extcon/Makefile +++ b/drivers/extcon/Makefile | |||
@@ -9,6 +9,7 @@ obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o | |||
9 | obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o | 9 | obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o |
10 | obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o | 10 | obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o |
11 | obj-$(CONFIG_EXTCON_INTEL_INT3496) += extcon-intel-int3496.o | 11 | obj-$(CONFIG_EXTCON_INTEL_INT3496) += extcon-intel-int3496.o |
12 | obj-$(CONFIG_EXTCON_INTEL_CHT_WC) += extcon-intel-cht-wc.o | ||
12 | obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o | 13 | obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o |
13 | obj-$(CONFIG_EXTCON_MAX3355) += extcon-max3355.o | 14 | obj-$(CONFIG_EXTCON_MAX3355) += extcon-max3355.o |
14 | obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o | 15 | obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o |
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index ed78b7c26627..e2d78cd7030d 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c | |||
@@ -51,6 +51,9 @@ | |||
51 | #define HPDET_DEBOUNCE 500 | 51 | #define HPDET_DEBOUNCE 500 |
52 | #define DEFAULT_MICD_TIMEOUT 2000 | 52 | #define DEFAULT_MICD_TIMEOUT 2000 |
53 | 53 | ||
54 | #define ARIZONA_HPDET_WAIT_COUNT 15 | ||
55 | #define ARIZONA_HPDET_WAIT_DELAY_MS 20 | ||
56 | |||
54 | #define QUICK_HEADPHONE_MAX_OHM 3 | 57 | #define QUICK_HEADPHONE_MAX_OHM 3 |
55 | #define MICROPHONE_MIN_OHM 1257 | 58 | #define MICROPHONE_MIN_OHM 1257 |
56 | #define MICROPHONE_MAX_OHM 30000 | 59 | #define MICROPHONE_MAX_OHM 30000 |
@@ -1049,6 +1052,40 @@ static void arizona_hpdet_work(struct work_struct *work) | |||
1049 | mutex_unlock(&info->lock); | 1052 | mutex_unlock(&info->lock); |
1050 | } | 1053 | } |
1051 | 1054 | ||
1055 | static int arizona_hpdet_wait(struct arizona_extcon_info *info) | ||
1056 | { | ||
1057 | struct arizona *arizona = info->arizona; | ||
1058 | unsigned int val; | ||
1059 | int i, ret; | ||
1060 | |||
1061 | for (i = 0; i < ARIZONA_HPDET_WAIT_COUNT; i++) { | ||
1062 | ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, | ||
1063 | &val); | ||
1064 | if (ret) { | ||
1065 | dev_err(arizona->dev, | ||
1066 | "Failed to read HPDET state: %d\n", ret); | ||
1067 | return ret; | ||
1068 | } | ||
1069 | |||
1070 | switch (info->hpdet_ip_version) { | ||
1071 | case 0: | ||
1072 | if (val & ARIZONA_HP_DONE) | ||
1073 | return 0; | ||
1074 | break; | ||
1075 | default: | ||
1076 | if (val & ARIZONA_HP_DONE_B) | ||
1077 | return 0; | ||
1078 | break; | ||
1079 | } | ||
1080 | |||
1081 | msleep(ARIZONA_HPDET_WAIT_DELAY_MS); | ||
1082 | } | ||
1083 | |||
1084 | dev_warn(arizona->dev, "HPDET did not appear to complete\n"); | ||
1085 | |||
1086 | return -ETIMEDOUT; | ||
1087 | } | ||
1088 | |||
1052 | static irqreturn_t arizona_jackdet(int irq, void *data) | 1089 | static irqreturn_t arizona_jackdet(int irq, void *data) |
1053 | { | 1090 | { |
1054 | struct arizona_extcon_info *info = data; | 1091 | struct arizona_extcon_info *info = data; |
@@ -1155,6 +1192,15 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
1155 | "Removal report failed: %d\n", ret); | 1192 | "Removal report failed: %d\n", ret); |
1156 | } | 1193 | } |
1157 | 1194 | ||
1195 | /* | ||
1196 | * If the jack was removed during a headphone detection we | ||
1197 | * need to wait for the headphone detection to finish, as | ||
1198 | * it can not be aborted. We don't want to be able to start | ||
1199 | * a new headphone detection from a fresh insert until this | ||
1200 | * one is finished. | ||
1201 | */ | ||
1202 | arizona_hpdet_wait(info); | ||
1203 | |||
1158 | regmap_update_bits(arizona->regmap, | 1204 | regmap_update_bits(arizona->regmap, |
1159 | ARIZONA_JACK_DETECT_DEBOUNCE, | 1205 | ARIZONA_JACK_DETECT_DEBOUNCE, |
1160 | ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, | 1206 | ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, |
diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c new file mode 100644 index 000000000000..91a0023074af --- /dev/null +++ b/drivers/extcon/extcon-intel-cht-wc.c | |||
@@ -0,0 +1,395 @@ | |||
1 | /* | ||
2 | * Extcon charger detection driver for Intel Cherrytrail Whiskey Cove PMIC | ||
3 | * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> | ||
4 | * | ||
5 | * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: | ||
6 | * Copyright (C) 2013-2015 Intel Corporation. All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/extcon.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/mfd/intel_soc_pmic.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/regmap.h> | ||
25 | #include <linux/slab.h> | ||
26 | |||
27 | #define CHT_WC_PHYCTRL 0x5e07 | ||
28 | |||
29 | #define CHT_WC_CHGRCTRL0 0x5e16 | ||
30 | #define CHT_WC_CHGRCTRL0_CHGRRESET BIT(0) | ||
31 | #define CHT_WC_CHGRCTRL0_EMRGCHREN BIT(1) | ||
32 | #define CHT_WC_CHGRCTRL0_EXTCHRDIS BIT(2) | ||
33 | #define CHT_WC_CHGRCTRL0_SWCONTROL BIT(3) | ||
34 | #define CHT_WC_CHGRCTRL0_TTLCK_MASK BIT(4) | ||
35 | #define CHT_WC_CHGRCTRL0_CCSM_OFF_MASK BIT(5) | ||
36 | #define CHT_WC_CHGRCTRL0_DBPOFF_MASK BIT(6) | ||
37 | #define CHT_WC_CHGRCTRL0_WDT_NOKICK BIT(7) | ||
38 | |||
39 | #define CHT_WC_CHGRCTRL1 0x5e17 | ||
40 | |||
41 | #define CHT_WC_USBSRC 0x5e29 | ||
42 | #define CHT_WC_USBSRC_STS_MASK GENMASK(1, 0) | ||
43 | #define CHT_WC_USBSRC_STS_SUCCESS 2 | ||
44 | #define CHT_WC_USBSRC_STS_FAIL 3 | ||
45 | #define CHT_WC_USBSRC_TYPE_SHIFT 2 | ||
46 | #define CHT_WC_USBSRC_TYPE_MASK GENMASK(5, 2) | ||
47 | #define CHT_WC_USBSRC_TYPE_NONE 0 | ||
48 | #define CHT_WC_USBSRC_TYPE_SDP 1 | ||
49 | #define CHT_WC_USBSRC_TYPE_DCP 2 | ||
50 | #define CHT_WC_USBSRC_TYPE_CDP 3 | ||
51 | #define CHT_WC_USBSRC_TYPE_ACA 4 | ||
52 | #define CHT_WC_USBSRC_TYPE_SE1 5 | ||
53 | #define CHT_WC_USBSRC_TYPE_MHL 6 | ||
54 | #define CHT_WC_USBSRC_TYPE_FLOAT_DP_DN 7 | ||
55 | #define CHT_WC_USBSRC_TYPE_OTHER 8 | ||
56 | #define CHT_WC_USBSRC_TYPE_DCP_EXTPHY 9 | ||
57 | |||
58 | #define CHT_WC_PWRSRC_IRQ 0x6e03 | ||
59 | #define CHT_WC_PWRSRC_IRQ_MASK 0x6e0f | ||
60 | #define CHT_WC_PWRSRC_STS 0x6e1e | ||
61 | #define CHT_WC_PWRSRC_VBUS BIT(0) | ||
62 | #define CHT_WC_PWRSRC_DC BIT(1) | ||
63 | #define CHT_WC_PWRSRC_BAT BIT(2) | ||
64 | #define CHT_WC_PWRSRC_ID_GND BIT(3) | ||
65 | #define CHT_WC_PWRSRC_ID_FLOAT BIT(4) | ||
66 | |||
67 | #define CHT_WC_VBUS_GPIO_CTLO 0x6e2d | ||
68 | #define CHT_WC_VBUS_GPIO_CTLO_OUTPUT BIT(0) | ||
69 | |||
70 | enum cht_wc_usb_id { | ||
71 | USB_ID_OTG, | ||
72 | USB_ID_GND, | ||
73 | USB_ID_FLOAT, | ||
74 | USB_RID_A, | ||
75 | USB_RID_B, | ||
76 | USB_RID_C, | ||
77 | }; | ||
78 | |||
79 | enum cht_wc_mux_select { | ||
80 | MUX_SEL_PMIC = 0, | ||
81 | MUX_SEL_SOC, | ||
82 | }; | ||
83 | |||
84 | static const unsigned int cht_wc_extcon_cables[] = { | ||
85 | EXTCON_USB, | ||
86 | EXTCON_USB_HOST, | ||
87 | EXTCON_CHG_USB_SDP, | ||
88 | EXTCON_CHG_USB_CDP, | ||
89 | EXTCON_CHG_USB_DCP, | ||
90 | EXTCON_CHG_USB_ACA, | ||
91 | EXTCON_NONE, | ||
92 | }; | ||
93 | |||
94 | struct cht_wc_extcon_data { | ||
95 | struct device *dev; | ||
96 | struct regmap *regmap; | ||
97 | struct extcon_dev *edev; | ||
98 | unsigned int previous_cable; | ||
99 | bool usb_host; | ||
100 | }; | ||
101 | |||
102 | static int cht_wc_extcon_get_id(struct cht_wc_extcon_data *ext, int pwrsrc_sts) | ||
103 | { | ||
104 | if (pwrsrc_sts & CHT_WC_PWRSRC_ID_GND) | ||
105 | return USB_ID_GND; | ||
106 | if (pwrsrc_sts & CHT_WC_PWRSRC_ID_FLOAT) | ||
107 | return USB_ID_FLOAT; | ||
108 | |||
109 | /* | ||
110 | * Once we have iio support for the gpadc we should read the USBID | ||
111 | * gpadc channel here and determine ACA role based on that. | ||
112 | */ | ||
113 | return USB_ID_FLOAT; | ||
114 | } | ||
115 | |||
116 | static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext, | ||
117 | bool ignore_errors) | ||
118 | { | ||
119 | int ret, usbsrc, status; | ||
120 | unsigned long timeout; | ||
121 | |||
122 | /* Charger detection can take upto 600ms, wait 800ms max. */ | ||
123 | timeout = jiffies + msecs_to_jiffies(800); | ||
124 | do { | ||
125 | ret = regmap_read(ext->regmap, CHT_WC_USBSRC, &usbsrc); | ||
126 | if (ret) { | ||
127 | dev_err(ext->dev, "Error reading usbsrc: %d\n", ret); | ||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | status = usbsrc & CHT_WC_USBSRC_STS_MASK; | ||
132 | if (status == CHT_WC_USBSRC_STS_SUCCESS || | ||
133 | status == CHT_WC_USBSRC_STS_FAIL) | ||
134 | break; | ||
135 | |||
136 | msleep(50); /* Wait a bit before retrying */ | ||
137 | } while (time_before(jiffies, timeout)); | ||
138 | |||
139 | if (status != CHT_WC_USBSRC_STS_SUCCESS) { | ||
140 | if (ignore_errors) | ||
141 | return EXTCON_CHG_USB_SDP; /* Save fallback */ | ||
142 | |||
143 | if (status == CHT_WC_USBSRC_STS_FAIL) | ||
144 | dev_warn(ext->dev, "Could not detect charger type\n"); | ||
145 | else | ||
146 | dev_warn(ext->dev, "Timeout detecting charger type\n"); | ||
147 | return EXTCON_CHG_USB_SDP; /* Save fallback */ | ||
148 | } | ||
149 | |||
150 | usbsrc = (usbsrc & CHT_WC_USBSRC_TYPE_MASK) >> CHT_WC_USBSRC_TYPE_SHIFT; | ||
151 | switch (usbsrc) { | ||
152 | default: | ||
153 | dev_warn(ext->dev, | ||
154 | "Unhandled charger type %d, defaulting to SDP\n", | ||
155 | ret); | ||
156 | /* Fall through, treat as SDP */ | ||
157 | case CHT_WC_USBSRC_TYPE_SDP: | ||
158 | case CHT_WC_USBSRC_TYPE_FLOAT_DP_DN: | ||
159 | case CHT_WC_USBSRC_TYPE_OTHER: | ||
160 | return EXTCON_CHG_USB_SDP; | ||
161 | case CHT_WC_USBSRC_TYPE_CDP: | ||
162 | return EXTCON_CHG_USB_CDP; | ||
163 | case CHT_WC_USBSRC_TYPE_DCP: | ||
164 | case CHT_WC_USBSRC_TYPE_DCP_EXTPHY: | ||
165 | case CHT_WC_USBSRC_TYPE_MHL: /* MHL2+ delivers upto 2A, treat as DCP */ | ||
166 | return EXTCON_CHG_USB_DCP; | ||
167 | case CHT_WC_USBSRC_TYPE_ACA: | ||
168 | return EXTCON_CHG_USB_ACA; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | static void cht_wc_extcon_set_phymux(struct cht_wc_extcon_data *ext, u8 state) | ||
173 | { | ||
174 | int ret; | ||
175 | |||
176 | ret = regmap_write(ext->regmap, CHT_WC_PHYCTRL, state); | ||
177 | if (ret) | ||
178 | dev_err(ext->dev, "Error writing phyctrl: %d\n", ret); | ||
179 | } | ||
180 | |||
181 | static void cht_wc_extcon_set_5v_boost(struct cht_wc_extcon_data *ext, | ||
182 | bool enable) | ||
183 | { | ||
184 | int ret, val; | ||
185 | |||
186 | val = enable ? CHT_WC_VBUS_GPIO_CTLO_OUTPUT : 0; | ||
187 | |||
188 | /* | ||
189 | * The 5V boost converter is enabled through a gpio on the PMIC, since | ||
190 | * there currently is no gpio driver we access the gpio reg directly. | ||
191 | */ | ||
192 | ret = regmap_update_bits(ext->regmap, CHT_WC_VBUS_GPIO_CTLO, | ||
193 | CHT_WC_VBUS_GPIO_CTLO_OUTPUT, val); | ||
194 | if (ret) | ||
195 | dev_err(ext->dev, "Error writing Vbus GPIO CTLO: %d\n", ret); | ||
196 | } | ||
197 | |||
198 | /* Small helper to sync EXTCON_CHG_USB_SDP and EXTCON_USB state */ | ||
199 | static void cht_wc_extcon_set_state(struct cht_wc_extcon_data *ext, | ||
200 | unsigned int cable, bool state) | ||
201 | { | ||
202 | extcon_set_state_sync(ext->edev, cable, state); | ||
203 | if (cable == EXTCON_CHG_USB_SDP) | ||
204 | extcon_set_state_sync(ext->edev, EXTCON_USB, state); | ||
205 | } | ||
206 | |||
207 | static void cht_wc_extcon_pwrsrc_event(struct cht_wc_extcon_data *ext) | ||
208 | { | ||
209 | int ret, pwrsrc_sts, id; | ||
210 | unsigned int cable = EXTCON_NONE; | ||
211 | /* Ignore errors in host mode, as the 5v boost converter is on then */ | ||
212 | bool ignore_get_charger_errors = ext->usb_host; | ||
213 | |||
214 | ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts); | ||
215 | if (ret) { | ||
216 | dev_err(ext->dev, "Error reading pwrsrc status: %d\n", ret); | ||
217 | return; | ||
218 | } | ||
219 | |||
220 | id = cht_wc_extcon_get_id(ext, pwrsrc_sts); | ||
221 | if (id == USB_ID_GND) { | ||
222 | /* The 5v boost causes a false VBUS / SDP detect, skip */ | ||
223 | goto charger_det_done; | ||
224 | } | ||
225 | |||
226 | /* Plugged into a host/charger or not connected? */ | ||
227 | if (!(pwrsrc_sts & CHT_WC_PWRSRC_VBUS)) { | ||
228 | /* Route D+ and D- to PMIC for future charger detection */ | ||
229 | cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC); | ||
230 | goto set_state; | ||
231 | } | ||
232 | |||
233 | ret = cht_wc_extcon_get_charger(ext, ignore_get_charger_errors); | ||
234 | if (ret >= 0) | ||
235 | cable = ret; | ||
236 | |||
237 | charger_det_done: | ||
238 | /* Route D+ and D- to SoC for the host or gadget controller */ | ||
239 | cht_wc_extcon_set_phymux(ext, MUX_SEL_SOC); | ||
240 | |||
241 | set_state: | ||
242 | if (cable != ext->previous_cable) { | ||
243 | cht_wc_extcon_set_state(ext, cable, true); | ||
244 | cht_wc_extcon_set_state(ext, ext->previous_cable, false); | ||
245 | ext->previous_cable = cable; | ||
246 | } | ||
247 | |||
248 | ext->usb_host = ((id == USB_ID_GND) || (id == USB_RID_A)); | ||
249 | extcon_set_state_sync(ext->edev, EXTCON_USB_HOST, ext->usb_host); | ||
250 | } | ||
251 | |||
252 | static irqreturn_t cht_wc_extcon_isr(int irq, void *data) | ||
253 | { | ||
254 | struct cht_wc_extcon_data *ext = data; | ||
255 | int ret, irqs; | ||
256 | |||
257 | ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_IRQ, &irqs); | ||
258 | if (ret) { | ||
259 | dev_err(ext->dev, "Error reading irqs: %d\n", ret); | ||
260 | return IRQ_NONE; | ||
261 | } | ||
262 | |||
263 | cht_wc_extcon_pwrsrc_event(ext); | ||
264 | |||
265 | ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ, irqs); | ||
266 | if (ret) { | ||
267 | dev_err(ext->dev, "Error writing irqs: %d\n", ret); | ||
268 | return IRQ_NONE; | ||
269 | } | ||
270 | |||
271 | return IRQ_HANDLED; | ||
272 | } | ||
273 | |||
274 | static int cht_wc_extcon_sw_control(struct cht_wc_extcon_data *ext, bool enable) | ||
275 | { | ||
276 | int ret, mask, val; | ||
277 | |||
278 | mask = CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF_MASK; | ||
279 | val = enable ? mask : 0; | ||
280 | ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL0, mask, val); | ||
281 | if (ret) | ||
282 | dev_err(ext->dev, "Error setting sw control: %d\n", ret); | ||
283 | |||
284 | return ret; | ||
285 | } | ||
286 | |||
287 | static int cht_wc_extcon_probe(struct platform_device *pdev) | ||
288 | { | ||
289 | struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); | ||
290 | struct cht_wc_extcon_data *ext; | ||
291 | int irq, ret; | ||
292 | |||
293 | irq = platform_get_irq(pdev, 0); | ||
294 | if (irq < 0) | ||
295 | return irq; | ||
296 | |||
297 | ext = devm_kzalloc(&pdev->dev, sizeof(*ext), GFP_KERNEL); | ||
298 | if (!ext) | ||
299 | return -ENOMEM; | ||
300 | |||
301 | ext->dev = &pdev->dev; | ||
302 | ext->regmap = pmic->regmap; | ||
303 | ext->previous_cable = EXTCON_NONE; | ||
304 | |||
305 | /* Initialize extcon device */ | ||
306 | ext->edev = devm_extcon_dev_allocate(ext->dev, cht_wc_extcon_cables); | ||
307 | if (IS_ERR(ext->edev)) | ||
308 | return PTR_ERR(ext->edev); | ||
309 | |||
310 | /* | ||
311 | * When a host-cable is detected the BIOS enables an external 5v boost | ||
312 | * converter to power connected devices there are 2 problems with this: | ||
313 | * 1) This gets seen by the external battery charger as a valid Vbus | ||
314 | * supply and it then tries to feed Vsys from this creating a | ||
315 | * feedback loop which causes aprox. 300 mA extra battery drain | ||
316 | * (and unless we drive the external-charger-disable pin high it | ||
317 | * also tries to charge the battery causing even more feedback). | ||
318 | * 2) This gets seen by the pwrsrc block as a SDP USB Vbus supply | ||
319 | * Since the external battery charger has its own 5v boost converter | ||
320 | * which does not have these issues, we simply turn the separate | ||
321 | * external 5v boost converter off and leave it off entirely. | ||
322 | */ | ||
323 | cht_wc_extcon_set_5v_boost(ext, false); | ||
324 | |||
325 | /* Enable sw control */ | ||
326 | ret = cht_wc_extcon_sw_control(ext, true); | ||
327 | if (ret) | ||
328 | return ret; | ||
329 | |||
330 | /* Register extcon device */ | ||
331 | ret = devm_extcon_dev_register(ext->dev, ext->edev); | ||
332 | if (ret) { | ||
333 | dev_err(ext->dev, "Error registering extcon device: %d\n", ret); | ||
334 | goto disable_sw_control; | ||
335 | } | ||
336 | |||
337 | /* Route D+ and D- to PMIC for initial charger detection */ | ||
338 | cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC); | ||
339 | |||
340 | /* Get initial state */ | ||
341 | cht_wc_extcon_pwrsrc_event(ext); | ||
342 | |||
343 | ret = devm_request_threaded_irq(ext->dev, irq, NULL, cht_wc_extcon_isr, | ||
344 | IRQF_ONESHOT, pdev->name, ext); | ||
345 | if (ret) { | ||
346 | dev_err(ext->dev, "Error requesting interrupt: %d\n", ret); | ||
347 | goto disable_sw_control; | ||
348 | } | ||
349 | |||
350 | /* Unmask irqs */ | ||
351 | ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK, | ||
352 | (int)~(CHT_WC_PWRSRC_VBUS | CHT_WC_PWRSRC_ID_GND | | ||
353 | CHT_WC_PWRSRC_ID_FLOAT)); | ||
354 | if (ret) { | ||
355 | dev_err(ext->dev, "Error writing irq-mask: %d\n", ret); | ||
356 | goto disable_sw_control; | ||
357 | } | ||
358 | |||
359 | platform_set_drvdata(pdev, ext); | ||
360 | |||
361 | return 0; | ||
362 | |||
363 | disable_sw_control: | ||
364 | cht_wc_extcon_sw_control(ext, false); | ||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | static int cht_wc_extcon_remove(struct platform_device *pdev) | ||
369 | { | ||
370 | struct cht_wc_extcon_data *ext = platform_get_drvdata(pdev); | ||
371 | |||
372 | cht_wc_extcon_sw_control(ext, false); | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static const struct platform_device_id cht_wc_extcon_table[] = { | ||
378 | { .name = "cht_wcove_pwrsrc" }, | ||
379 | {}, | ||
380 | }; | ||
381 | MODULE_DEVICE_TABLE(platform, cht_wc_extcon_table); | ||
382 | |||
383 | static struct platform_driver cht_wc_extcon_driver = { | ||
384 | .probe = cht_wc_extcon_probe, | ||
385 | .remove = cht_wc_extcon_remove, | ||
386 | .id_table = cht_wc_extcon_table, | ||
387 | .driver = { | ||
388 | .name = "cht_wcove_pwrsrc", | ||
389 | }, | ||
390 | }; | ||
391 | module_platform_driver(cht_wc_extcon_driver); | ||
392 | |||
393 | MODULE_DESCRIPTION("Intel Cherrytrail Whiskey Cove PMIC extcon driver"); | ||
394 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); | ||
395 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c index ca904e8b3235..2af4369a2d73 100644 --- a/drivers/extcon/extcon-palmas.c +++ b/drivers/extcon/extcon-palmas.c | |||
@@ -413,6 +413,12 @@ static int palmas_usb_resume(struct device *dev) | |||
413 | if (palmas_usb->enable_gpio_id_detection) | 413 | if (palmas_usb->enable_gpio_id_detection) |
414 | disable_irq_wake(palmas_usb->gpio_id_irq); | 414 | disable_irq_wake(palmas_usb->gpio_id_irq); |
415 | } | 415 | } |
416 | |||
417 | /* check if GPIO states changed while suspend/resume */ | ||
418 | if (palmas_usb->enable_gpio_vbus_detection) | ||
419 | palmas_vbus_irq_handler(palmas_usb->gpio_vbus_irq, palmas_usb); | ||
420 | palmas_gpio_id_detect(&palmas_usb->wq_detectid.work); | ||
421 | |||
416 | return 0; | 422 | return 0; |
417 | }; | 423 | }; |
418 | #endif | 424 | #endif |
diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index a5e1882b4ca6..9c925b05b7aa 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
29 | #include <linux/acpi.h> | ||
30 | #include <linux/pinctrl/consumer.h> | 29 | #include <linux/pinctrl/consumer.h> |
31 | 30 | ||
32 | #define USB_GPIO_DEBOUNCE_MS 20 /* ms */ | 31 | #define USB_GPIO_DEBOUNCE_MS 20 /* ms */ |
@@ -111,7 +110,7 @@ static int usb_extcon_probe(struct platform_device *pdev) | |||
111 | struct usb_extcon_info *info; | 110 | struct usb_extcon_info *info; |
112 | int ret; | 111 | int ret; |
113 | 112 | ||
114 | if (!np && !ACPI_HANDLE(dev)) | 113 | if (!np) |
115 | return -EINVAL; | 114 | return -EINVAL; |
116 | 115 | ||
117 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); | 116 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); |
@@ -195,7 +194,7 @@ static int usb_extcon_probe(struct platform_device *pdev) | |||
195 | } | 194 | } |
196 | 195 | ||
197 | platform_set_drvdata(pdev, info); | 196 | platform_set_drvdata(pdev, info); |
198 | device_init_wakeup(dev, true); | 197 | device_set_wakeup_capable(&pdev->dev, true); |
199 | 198 | ||
200 | /* Perform initial detection */ | 199 | /* Perform initial detection */ |
201 | usb_extcon_detect_cable(&info->wq_detcable.work); | 200 | usb_extcon_detect_cable(&info->wq_detcable.work); |
@@ -282,9 +281,8 @@ static int usb_extcon_resume(struct device *dev) | |||
282 | if (info->vbus_gpiod) | 281 | if (info->vbus_gpiod) |
283 | enable_irq(info->vbus_irq); | 282 | enable_irq(info->vbus_irq); |
284 | 283 | ||
285 | if (!device_may_wakeup(dev)) | 284 | queue_delayed_work(system_power_efficient_wq, |
286 | queue_delayed_work(system_power_efficient_wq, | 285 | &info->wq_detcable, 0); |
287 | &info->wq_detcable, 0); | ||
288 | 286 | ||
289 | return ret; | 287 | return ret; |
290 | } | 288 | } |
diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index e7750545469f..f422a78ba342 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c | |||
@@ -230,9 +230,6 @@ struct extcon_cable { | |||
230 | }; | 230 | }; |
231 | 231 | ||
232 | static struct class *extcon_class; | 232 | static struct class *extcon_class; |
233 | #if defined(CONFIG_ANDROID) | ||
234 | static struct class_compat *switch_class; | ||
235 | #endif /* CONFIG_ANDROID */ | ||
236 | 233 | ||
237 | static LIST_HEAD(extcon_dev_list); | 234 | static LIST_HEAD(extcon_dev_list); |
238 | static DEFINE_MUTEX(extcon_dev_list_lock); | 235 | static DEFINE_MUTEX(extcon_dev_list_lock); |
@@ -380,7 +377,7 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr, | |||
380 | for (i = 0; i < edev->max_supported; i++) { | 377 | for (i = 0; i < edev->max_supported; i++) { |
381 | count += sprintf(buf + count, "%s=%d\n", | 378 | count += sprintf(buf + count, "%s=%d\n", |
382 | extcon_info[edev->supported_cable[i]].name, | 379 | extcon_info[edev->supported_cable[i]].name, |
383 | !!(edev->state & (1 << i))); | 380 | !!(edev->state & BIT(i))); |
384 | } | 381 | } |
385 | 382 | ||
386 | return count; | 383 | return count; |
@@ -1032,12 +1029,6 @@ static int create_extcon_class(void) | |||
1032 | if (IS_ERR(extcon_class)) | 1029 | if (IS_ERR(extcon_class)) |
1033 | return PTR_ERR(extcon_class); | 1030 | return PTR_ERR(extcon_class); |
1034 | extcon_class->dev_groups = extcon_groups; | 1031 | extcon_class->dev_groups = extcon_groups; |
1035 | |||
1036 | #if defined(CONFIG_ANDROID) | ||
1037 | switch_class = class_compat_register("switch"); | ||
1038 | if (WARN(!switch_class, "cannot allocate")) | ||
1039 | return -ENOMEM; | ||
1040 | #endif /* CONFIG_ANDROID */ | ||
1041 | } | 1032 | } |
1042 | 1033 | ||
1043 | return 0; | 1034 | return 0; |
@@ -1259,10 +1250,6 @@ int extcon_dev_register(struct extcon_dev *edev) | |||
1259 | put_device(&edev->dev); | 1250 | put_device(&edev->dev); |
1260 | goto err_dev; | 1251 | goto err_dev; |
1261 | } | 1252 | } |
1262 | #if defined(CONFIG_ANDROID) | ||
1263 | if (switch_class) | ||
1264 | ret = class_compat_create_link(switch_class, &edev->dev, NULL); | ||
1265 | #endif /* CONFIG_ANDROID */ | ||
1266 | 1253 | ||
1267 | spin_lock_init(&edev->lock); | 1254 | spin_lock_init(&edev->lock); |
1268 | 1255 | ||
@@ -1350,10 +1337,6 @@ void extcon_dev_unregister(struct extcon_dev *edev) | |||
1350 | kfree(edev->cables); | 1337 | kfree(edev->cables); |
1351 | } | 1338 | } |
1352 | 1339 | ||
1353 | #if defined(CONFIG_ANDROID) | ||
1354 | if (switch_class) | ||
1355 | class_compat_remove_link(switch_class, &edev->dev, NULL); | ||
1356 | #endif | ||
1357 | put_device(&edev->dev); | 1340 | put_device(&edev->dev); |
1358 | } | 1341 | } |
1359 | EXPORT_SYMBOL_GPL(extcon_dev_unregister); | 1342 | EXPORT_SYMBOL_GPL(extcon_dev_unregister); |
@@ -1424,9 +1407,6 @@ module_init(extcon_class_init); | |||
1424 | 1407 | ||
1425 | static void __exit extcon_class_exit(void) | 1408 | static void __exit extcon_class_exit(void) |
1426 | { | 1409 | { |
1427 | #if defined(CONFIG_ANDROID) | ||
1428 | class_compat_unregister(switch_class); | ||
1429 | #endif | ||
1430 | class_destroy(extcon_class); | 1410 | class_destroy(extcon_class); |
1431 | } | 1411 | } |
1432 | module_exit(extcon_class_exit); | 1412 | module_exit(extcon_class_exit); |
diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c index 0de83508f321..939d259ddf19 100644 --- a/drivers/firewire/core-topology.c +++ b/drivers/firewire/core-topology.c | |||
@@ -124,7 +124,7 @@ static struct fw_node *fw_node_create(u32 sid, int port_count, int color) | |||
124 | node->initiated_reset = SELF_ID_PHY_INITIATOR(sid); | 124 | node->initiated_reset = SELF_ID_PHY_INITIATOR(sid); |
125 | node->port_count = port_count; | 125 | node->port_count = port_count; |
126 | 126 | ||
127 | atomic_set(&node->ref_count, 1); | 127 | refcount_set(&node->ref_count, 1); |
128 | INIT_LIST_HEAD(&node->link); | 128 | INIT_LIST_HEAD(&node->link); |
129 | 129 | ||
130 | return node; | 130 | return node; |
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index e1480ff683d2..c07962ead5e4 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h | |||
@@ -12,7 +12,7 @@ | |||
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | 14 | ||
15 | #include <linux/atomic.h> | 15 | #include <linux/refcount.h> |
16 | 16 | ||
17 | struct device; | 17 | struct device; |
18 | struct fw_card; | 18 | struct fw_card; |
@@ -184,7 +184,7 @@ struct fw_node { | |||
184 | * local node to this node. */ | 184 | * local node to this node. */ |
185 | u8 max_depth:4; /* Maximum depth to any leaf node */ | 185 | u8 max_depth:4; /* Maximum depth to any leaf node */ |
186 | u8 max_hops:4; /* Max hops in this sub tree */ | 186 | u8 max_hops:4; /* Max hops in this sub tree */ |
187 | atomic_t ref_count; | 187 | refcount_t ref_count; |
188 | 188 | ||
189 | /* For serializing node topology into a list. */ | 189 | /* For serializing node topology into a list. */ |
190 | struct list_head link; | 190 | struct list_head link; |
@@ -197,14 +197,14 @@ struct fw_node { | |||
197 | 197 | ||
198 | static inline struct fw_node *fw_node_get(struct fw_node *node) | 198 | static inline struct fw_node *fw_node_get(struct fw_node *node) |
199 | { | 199 | { |
200 | atomic_inc(&node->ref_count); | 200 | refcount_inc(&node->ref_count); |
201 | 201 | ||
202 | return node; | 202 | return node; |
203 | } | 203 | } |
204 | 204 | ||
205 | static inline void fw_node_put(struct fw_node *node) | 205 | static inline void fw_node_put(struct fw_node *node) |
206 | { | 206 | { |
207 | if (atomic_dec_and_test(&node->ref_count)) | 207 | if (refcount_dec_and_test(&node->ref_count)) |
208 | kfree(node); | 208 | kfree(node); |
209 | } | 209 | } |
210 | 210 | ||
diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig index 29c8cdda82a1..f16b381a569c 100644 --- a/drivers/firmware/google/Kconfig +++ b/drivers/firmware/google/Kconfig | |||
@@ -1,18 +1,16 @@ | |||
1 | config GOOGLE_FIRMWARE | 1 | menuconfig GOOGLE_FIRMWARE |
2 | bool "Google Firmware Drivers" | 2 | bool "Google Firmware Drivers" |
3 | depends on X86 | ||
4 | default n | 3 | default n |
5 | help | 4 | help |
6 | These firmware drivers are used by Google's servers. They are | 5 | These firmware drivers are used by Google's servers. They are |
7 | only useful if you are working directly on one of their | 6 | only useful if you are working directly on one of their |
8 | proprietary servers. If in doubt, say "N". | 7 | proprietary servers. If in doubt, say "N". |
9 | 8 | ||
10 | menu "Google Firmware Drivers" | 9 | if GOOGLE_FIRMWARE |
11 | depends on GOOGLE_FIRMWARE | ||
12 | 10 | ||
13 | config GOOGLE_SMI | 11 | config GOOGLE_SMI |
14 | tristate "SMI interface for Google platforms" | 12 | tristate "SMI interface for Google platforms" |
15 | depends on ACPI && DMI && EFI | 13 | depends on X86 && ACPI && DMI && EFI |
16 | select EFI_VARS | 14 | select EFI_VARS |
17 | help | 15 | help |
18 | Say Y here if you want to enable SMI callbacks for Google | 16 | Say Y here if you want to enable SMI callbacks for Google |
@@ -20,12 +18,57 @@ config GOOGLE_SMI | |||
20 | clearing the EFI event log and reading and writing NVRAM | 18 | clearing the EFI event log and reading and writing NVRAM |
21 | variables. | 19 | variables. |
22 | 20 | ||
21 | config GOOGLE_COREBOOT_TABLE | ||
22 | tristate | ||
23 | depends on GOOGLE_COREBOOT_TABLE_ACPI || GOOGLE_COREBOOT_TABLE_OF | ||
24 | |||
25 | config GOOGLE_COREBOOT_TABLE_ACPI | ||
26 | tristate "Coreboot Table Access - ACPI" | ||
27 | depends on ACPI | ||
28 | select GOOGLE_COREBOOT_TABLE | ||
29 | help | ||
30 | This option enables the coreboot_table module, which provides other | ||
31 | firmware modules to access to the coreboot table. The coreboot table | ||
32 | pointer is accessed through the ACPI "GOOGCB00" object. | ||
33 | If unsure say N. | ||
34 | |||
35 | config GOOGLE_COREBOOT_TABLE_OF | ||
36 | tristate "Coreboot Table Access - Device Tree" | ||
37 | depends on OF | ||
38 | select GOOGLE_COREBOOT_TABLE | ||
39 | help | ||
40 | This option enable the coreboot_table module, which provide other | ||
41 | firmware modules to access coreboot table. The coreboot table pointer | ||
42 | is accessed through the device tree node /firmware/coreboot. | ||
43 | If unsure say N. | ||
44 | |||
23 | config GOOGLE_MEMCONSOLE | 45 | config GOOGLE_MEMCONSOLE |
24 | tristate "Firmware Memory Console" | 46 | tristate |
25 | depends on DMI | 47 | depends on GOOGLE_MEMCONSOLE_X86_LEGACY || GOOGLE_MEMCONSOLE_COREBOOT |
48 | |||
49 | config GOOGLE_MEMCONSOLE_X86_LEGACY | ||
50 | tristate "Firmware Memory Console - X86 Legacy support" | ||
51 | depends on X86 && ACPI && DMI | ||
52 | select GOOGLE_MEMCONSOLE | ||
26 | help | 53 | help |
27 | This option enables the kernel to search for a firmware log in | 54 | This option enables the kernel to search for a firmware log in |
28 | the EBDA on Google servers. If found, this log is exported to | 55 | the EBDA on Google servers. If found, this log is exported to |
29 | userland in the file /sys/firmware/log. | 56 | userland in the file /sys/firmware/log. |
30 | 57 | ||
31 | endmenu | 58 | config GOOGLE_MEMCONSOLE_COREBOOT |
59 | tristate "Firmware Memory Console" | ||
60 | depends on GOOGLE_COREBOOT_TABLE | ||
61 | select GOOGLE_MEMCONSOLE | ||
62 | help | ||
63 | This option enables the kernel to search for a firmware log in | ||
64 | the coreboot table. If found, this log is exported to userland | ||
65 | in the file /sys/firmware/log. | ||
66 | |||
67 | config GOOGLE_VPD | ||
68 | tristate "Vital Product Data" | ||
69 | depends on GOOGLE_COREBOOT_TABLE | ||
70 | help | ||
71 | This option enables the kernel to expose the content of Google VPD | ||
72 | under /sys/firmware/vpd. | ||
73 | |||
74 | endif # GOOGLE_FIRMWARE | ||
diff --git a/drivers/firmware/google/Makefile b/drivers/firmware/google/Makefile index 54a294e3cb61..bc4de02202ad 100644 --- a/drivers/firmware/google/Makefile +++ b/drivers/firmware/google/Makefile | |||
@@ -1,3 +1,11 @@ | |||
1 | 1 | ||
2 | obj-$(CONFIG_GOOGLE_SMI) += gsmi.o | 2 | obj-$(CONFIG_GOOGLE_SMI) += gsmi.o |
3 | obj-$(CONFIG_GOOGLE_MEMCONSOLE) += memconsole.o | 3 | obj-$(CONFIG_GOOGLE_COREBOOT_TABLE) += coreboot_table.o |
4 | obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_ACPI) += coreboot_table-acpi.o | ||
5 | obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_OF) += coreboot_table-of.o | ||
6 | obj-$(CONFIG_GOOGLE_MEMCONSOLE) += memconsole.o | ||
7 | obj-$(CONFIG_GOOGLE_MEMCONSOLE_COREBOOT) += memconsole-coreboot.o | ||
8 | obj-$(CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY) += memconsole-x86-legacy.o | ||
9 | |||
10 | vpd-sysfs-y := vpd.o vpd_decode.o | ||
11 | obj-$(CONFIG_GOOGLE_VPD) += vpd-sysfs.o | ||
diff --git a/drivers/firmware/google/coreboot_table-acpi.c b/drivers/firmware/google/coreboot_table-acpi.c new file mode 100644 index 000000000000..fb98db2d20e2 --- /dev/null +++ b/drivers/firmware/google/coreboot_table-acpi.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * coreboot_table-acpi.c | ||
3 | * | ||
4 | * Using ACPI to locate Coreboot table and provide coreboot table access. | ||
5 | * | ||
6 | * Copyright 2017 Google Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License v2.0 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/acpi.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | |||
27 | #include "coreboot_table.h" | ||
28 | |||
29 | static int coreboot_table_acpi_probe(struct platform_device *pdev) | ||
30 | { | ||
31 | phys_addr_t phyaddr; | ||
32 | resource_size_t len; | ||
33 | struct coreboot_table_header __iomem *header = NULL; | ||
34 | struct resource *res; | ||
35 | void __iomem *ptr = NULL; | ||
36 | |||
37 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
38 | if (!res) | ||
39 | return -EINVAL; | ||
40 | |||
41 | len = resource_size(res); | ||
42 | if (!res->start || !len) | ||
43 | return -EINVAL; | ||
44 | |||
45 | phyaddr = res->start; | ||
46 | header = ioremap_cache(phyaddr, sizeof(*header)); | ||
47 | if (header == NULL) | ||
48 | return -ENOMEM; | ||
49 | |||
50 | ptr = ioremap_cache(phyaddr, | ||
51 | header->header_bytes + header->table_bytes); | ||
52 | iounmap(header); | ||
53 | if (!ptr) | ||
54 | return -ENOMEM; | ||
55 | |||
56 | return coreboot_table_init(ptr); | ||
57 | } | ||
58 | |||
59 | static int coreboot_table_acpi_remove(struct platform_device *pdev) | ||
60 | { | ||
61 | return coreboot_table_exit(); | ||
62 | } | ||
63 | |||
64 | static const struct acpi_device_id cros_coreboot_acpi_match[] = { | ||
65 | { "GOOGCB00", 0 }, | ||
66 | { "BOOT0000", 0 }, | ||
67 | { } | ||
68 | }; | ||
69 | MODULE_DEVICE_TABLE(acpi, cros_coreboot_acpi_match); | ||
70 | |||
71 | static struct platform_driver coreboot_table_acpi_driver = { | ||
72 | .probe = coreboot_table_acpi_probe, | ||
73 | .remove = coreboot_table_acpi_remove, | ||
74 | .driver = { | ||
75 | .name = "coreboot_table_acpi", | ||
76 | .acpi_match_table = ACPI_PTR(cros_coreboot_acpi_match), | ||
77 | }, | ||
78 | }; | ||
79 | |||
80 | static int __init coreboot_table_acpi_init(void) | ||
81 | { | ||
82 | return platform_driver_register(&coreboot_table_acpi_driver); | ||
83 | } | ||
84 | |||
85 | module_init(coreboot_table_acpi_init); | ||
86 | |||
87 | MODULE_AUTHOR("Google, Inc."); | ||
88 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/firmware/google/coreboot_table-of.c b/drivers/firmware/google/coreboot_table-of.c new file mode 100644 index 000000000000..727acdc83e83 --- /dev/null +++ b/drivers/firmware/google/coreboot_table-of.c | |||
@@ -0,0 +1,82 @@ | |||
1 | /* | ||
2 | * coreboot_table-of.c | ||
3 | * | ||
4 | * Coreboot table access through open firmware. | ||
5 | * | ||
6 | * Copyright 2017 Google Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License v2.0 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/device.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/of_address.h> | ||
22 | #include <linux/of_platform.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | #include "coreboot_table.h" | ||
26 | |||
27 | static int coreboot_table_of_probe(struct platform_device *pdev) | ||
28 | { | ||
29 | struct device_node *fw_dn = pdev->dev.of_node; | ||
30 | void __iomem *ptr; | ||
31 | |||
32 | ptr = of_iomap(fw_dn, 0); | ||
33 | of_node_put(fw_dn); | ||
34 | if (!ptr) | ||
35 | return -ENOMEM; | ||
36 | |||
37 | return coreboot_table_init(ptr); | ||
38 | } | ||
39 | |||
40 | static int coreboot_table_of_remove(struct platform_device *pdev) | ||
41 | { | ||
42 | return coreboot_table_exit(); | ||
43 | } | ||
44 | |||
45 | static const struct of_device_id coreboot_of_match[] = { | ||
46 | { .compatible = "coreboot" }, | ||
47 | {}, | ||
48 | }; | ||
49 | |||
50 | static struct platform_driver coreboot_table_of_driver = { | ||
51 | .probe = coreboot_table_of_probe, | ||
52 | .remove = coreboot_table_of_remove, | ||
53 | .driver = { | ||
54 | .name = "coreboot_table_of", | ||
55 | .of_match_table = coreboot_of_match, | ||
56 | }, | ||
57 | }; | ||
58 | |||
59 | static int __init platform_coreboot_table_of_init(void) | ||
60 | { | ||
61 | struct platform_device *pdev; | ||
62 | struct device_node *of_node; | ||
63 | |||
64 | /* Limit device creation to the presence of /firmware/coreboot node */ | ||
65 | of_node = of_find_node_by_path("/firmware/coreboot"); | ||
66 | if (!of_node) | ||
67 | return -ENODEV; | ||
68 | |||
69 | if (!of_match_node(coreboot_of_match, of_node)) | ||
70 | return -ENODEV; | ||
71 | |||
72 | pdev = of_platform_device_create(of_node, "coreboot_table_of", NULL); | ||
73 | if (!pdev) | ||
74 | return -ENODEV; | ||
75 | |||
76 | return platform_driver_register(&coreboot_table_of_driver); | ||
77 | } | ||
78 | |||
79 | module_init(platform_coreboot_table_of_init); | ||
80 | |||
81 | MODULE_AUTHOR("Google, Inc."); | ||
82 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c new file mode 100644 index 000000000000..0019d3ec18dd --- /dev/null +++ b/drivers/firmware/google/coreboot_table.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | * coreboot_table.c | ||
3 | * | ||
4 | * Module providing coreboot table access. | ||
5 | * | ||
6 | * Copyright 2017 Google Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License v2.0 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/err.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | |||
24 | #include "coreboot_table.h" | ||
25 | |||
26 | struct coreboot_table_entry { | ||
27 | u32 tag; | ||
28 | u32 size; | ||
29 | }; | ||
30 | |||
31 | static struct coreboot_table_header __iomem *ptr_header; | ||
32 | |||
33 | /* | ||
34 | * This function parses the coreboot table for an entry that contains the base | ||
35 | * address of the given entry tag. The coreboot table consists of a header | ||
36 | * directly followed by a number of small, variable-sized entries, which each | ||
37 | * contain an identifying tag and their length as the first two fields. | ||
38 | */ | ||
39 | int coreboot_table_find(int tag, void *data, size_t data_size) | ||
40 | { | ||
41 | struct coreboot_table_header header; | ||
42 | struct coreboot_table_entry entry; | ||
43 | void *ptr_entry; | ||
44 | int i; | ||
45 | |||
46 | if (!ptr_header) | ||
47 | return -EPROBE_DEFER; | ||
48 | |||
49 | memcpy_fromio(&header, ptr_header, sizeof(header)); | ||
50 | |||
51 | if (strncmp(header.signature, "LBIO", sizeof(header.signature))) { | ||
52 | pr_warn("coreboot_table: coreboot table missing or corrupt!\n"); | ||
53 | return -ENODEV; | ||
54 | } | ||
55 | |||
56 | ptr_entry = (void *)ptr_header + header.header_bytes; | ||
57 | |||
58 | for (i = 0; i < header.table_entries; i++) { | ||
59 | memcpy_fromio(&entry, ptr_entry, sizeof(entry)); | ||
60 | if (entry.tag == tag) { | ||
61 | if (data_size < entry.size) | ||
62 | return -EINVAL; | ||
63 | |||
64 | memcpy_fromio(data, ptr_entry, entry.size); | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | ptr_entry += entry.size; | ||
70 | } | ||
71 | |||
72 | return -ENOENT; | ||
73 | } | ||
74 | EXPORT_SYMBOL(coreboot_table_find); | ||
75 | |||
76 | int coreboot_table_init(void __iomem *ptr) | ||
77 | { | ||
78 | ptr_header = ptr; | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | EXPORT_SYMBOL(coreboot_table_init); | ||
83 | |||
84 | int coreboot_table_exit(void) | ||
85 | { | ||
86 | if (ptr_header) | ||
87 | iounmap(ptr_header); | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | EXPORT_SYMBOL(coreboot_table_exit); | ||
92 | |||
93 | MODULE_AUTHOR("Google, Inc."); | ||
94 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/firmware/google/coreboot_table.h b/drivers/firmware/google/coreboot_table.h new file mode 100644 index 000000000000..6eff1ae0c5d3 --- /dev/null +++ b/drivers/firmware/google/coreboot_table.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * coreboot_table.h | ||
3 | * | ||
4 | * Internal header for coreboot table access. | ||
5 | * | ||
6 | * Copyright 2017 Google Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License v2.0 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #ifndef __COREBOOT_TABLE_H | ||
19 | #define __COREBOOT_TABLE_H | ||
20 | |||
21 | #include <linux/io.h> | ||
22 | |||
23 | /* List of coreboot entry structures that is used */ | ||
24 | struct lb_cbmem_ref { | ||
25 | uint32_t tag; | ||
26 | uint32_t size; | ||
27 | |||
28 | uint64_t cbmem_addr; | ||
29 | }; | ||
30 | |||
31 | /* Coreboot table header structure */ | ||
32 | struct coreboot_table_header { | ||
33 | char signature[4]; | ||
34 | u32 header_bytes; | ||
35 | u32 header_checksum; | ||
36 | u32 table_bytes; | ||
37 | u32 table_checksum; | ||
38 | u32 table_entries; | ||
39 | }; | ||
40 | |||
41 | /* Retrieve coreboot table entry with tag *tag* and copy it to data */ | ||
42 | int coreboot_table_find(int tag, void *data, size_t data_size); | ||
43 | |||
44 | /* Initialize coreboot table module given a pointer to iomem */ | ||
45 | int coreboot_table_init(void __iomem *ptr); | ||
46 | |||
47 | /* Cleanup coreboot table module */ | ||
48 | int coreboot_table_exit(void); | ||
49 | |||
50 | #endif /* __COREBOOT_TABLE_H */ | ||
diff --git a/drivers/firmware/google/memconsole-coreboot.c b/drivers/firmware/google/memconsole-coreboot.c new file mode 100644 index 000000000000..02711114dece --- /dev/null +++ b/drivers/firmware/google/memconsole-coreboot.c | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * memconsole-coreboot.c | ||
3 | * | ||
4 | * Memory based BIOS console accessed through coreboot table. | ||
5 | * | ||
6 | * Copyright 2017 Google Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License v2.0 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | |||
22 | #include "memconsole.h" | ||
23 | #include "coreboot_table.h" | ||
24 | |||
25 | #define CB_TAG_CBMEM_CONSOLE 0x17 | ||
26 | |||
27 | /* CBMEM firmware console log descriptor. */ | ||
28 | struct cbmem_cons { | ||
29 | u32 buffer_size; | ||
30 | u32 buffer_cursor; | ||
31 | u8 buffer_body[0]; | ||
32 | } __packed; | ||
33 | |||
34 | static struct cbmem_cons __iomem *cbmem_console; | ||
35 | |||
36 | static int memconsole_coreboot_init(phys_addr_t physaddr) | ||
37 | { | ||
38 | struct cbmem_cons __iomem *tmp_cbmc; | ||
39 | |||
40 | tmp_cbmc = memremap(physaddr, sizeof(*tmp_cbmc), MEMREMAP_WB); | ||
41 | |||
42 | if (!tmp_cbmc) | ||
43 | return -ENOMEM; | ||
44 | |||
45 | cbmem_console = memremap(physaddr, | ||
46 | tmp_cbmc->buffer_size + sizeof(*cbmem_console), | ||
47 | MEMREMAP_WB); | ||
48 | memunmap(tmp_cbmc); | ||
49 | |||
50 | if (!cbmem_console) | ||
51 | return -ENOMEM; | ||
52 | |||
53 | memconsole_setup(cbmem_console->buffer_body, | ||
54 | min(cbmem_console->buffer_cursor, cbmem_console->buffer_size)); | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static int memconsole_probe(struct platform_device *pdev) | ||
60 | { | ||
61 | int ret; | ||
62 | struct lb_cbmem_ref entry; | ||
63 | |||
64 | ret = coreboot_table_find(CB_TAG_CBMEM_CONSOLE, &entry, sizeof(entry)); | ||
65 | if (ret) | ||
66 | return ret; | ||
67 | |||
68 | ret = memconsole_coreboot_init(entry.cbmem_addr); | ||
69 | if (ret) | ||
70 | return ret; | ||
71 | |||
72 | return memconsole_sysfs_init(); | ||
73 | } | ||
74 | |||
75 | static int memconsole_remove(struct platform_device *pdev) | ||
76 | { | ||
77 | memconsole_exit(); | ||
78 | |||
79 | if (cbmem_console) | ||
80 | memunmap(cbmem_console); | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static struct platform_driver memconsole_driver = { | ||
86 | .probe = memconsole_probe, | ||
87 | .remove = memconsole_remove, | ||
88 | .driver = { | ||
89 | .name = "memconsole", | ||
90 | }, | ||
91 | }; | ||
92 | |||
93 | static int __init platform_memconsole_init(void) | ||
94 | { | ||
95 | struct platform_device *pdev; | ||
96 | |||
97 | pdev = platform_device_register_simple("memconsole", -1, NULL, 0); | ||
98 | if (IS_ERR(pdev)) | ||
99 | return PTR_ERR(pdev); | ||
100 | |||
101 | platform_driver_register(&memconsole_driver); | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | module_init(platform_memconsole_init); | ||
107 | |||
108 | MODULE_AUTHOR("Google, Inc."); | ||
109 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/firmware/google/memconsole-x86-legacy.c b/drivers/firmware/google/memconsole-x86-legacy.c new file mode 100644 index 000000000000..1f279ee883b9 --- /dev/null +++ b/drivers/firmware/google/memconsole-x86-legacy.c | |||
@@ -0,0 +1,153 @@ | |||
1 | /* | ||
2 | * memconsole-x86-legacy.c | ||
3 | * | ||
4 | * EBDA specific parts of the memory based BIOS console. | ||
5 | * | ||
6 | * Copyright 2017 Google Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License v2.0 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/dmi.h> | ||
21 | #include <linux/mm.h> | ||
22 | #include <asm/bios_ebda.h> | ||
23 | #include <linux/acpi.h> | ||
24 | |||
25 | #include "memconsole.h" | ||
26 | |||
27 | #define BIOS_MEMCONSOLE_V1_MAGIC 0xDEADBABE | ||
28 | #define BIOS_MEMCONSOLE_V2_MAGIC (('M')|('C'<<8)|('O'<<16)|('N'<<24)) | ||
29 | |||
30 | struct biosmemcon_ebda { | ||
31 | u32 signature; | ||
32 | union { | ||
33 | struct { | ||
34 | u8 enabled; | ||
35 | u32 buffer_addr; | ||
36 | u16 start; | ||
37 | u16 end; | ||
38 | u16 num_chars; | ||
39 | u8 wrapped; | ||
40 | } __packed v1; | ||
41 | struct { | ||
42 | u32 buffer_addr; | ||
43 | /* Misdocumented as number of pages! */ | ||
44 | u16 num_bytes; | ||
45 | u16 start; | ||
46 | u16 end; | ||
47 | } __packed v2; | ||
48 | }; | ||
49 | } __packed; | ||
50 | |||
51 | static void found_v1_header(struct biosmemcon_ebda *hdr) | ||
52 | { | ||
53 | pr_info("memconsole: BIOS console v1 EBDA structure found at %p\n", | ||
54 | hdr); | ||
55 | pr_info("memconsole: BIOS console buffer at 0x%.8x, start = %d, end = %d, num = %d\n", | ||
56 | hdr->v1.buffer_addr, hdr->v1.start, | ||
57 | hdr->v1.end, hdr->v1.num_chars); | ||
58 | |||
59 | memconsole_setup(phys_to_virt(hdr->v1.buffer_addr), hdr->v1.num_chars); | ||
60 | } | ||
61 | |||
62 | static void found_v2_header(struct biosmemcon_ebda *hdr) | ||
63 | { | ||
64 | pr_info("memconsole: BIOS console v2 EBDA structure found at %p\n", | ||
65 | hdr); | ||
66 | pr_info("memconsole: BIOS console buffer at 0x%.8x, start = %d, end = %d, num_bytes = %d\n", | ||
67 | hdr->v2.buffer_addr, hdr->v2.start, | ||
68 | hdr->v2.end, hdr->v2.num_bytes); | ||
69 | |||
70 | memconsole_setup(phys_to_virt(hdr->v2.buffer_addr + hdr->v2.start), | ||
71 | hdr->v2.end - hdr->v2.start); | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * Search through the EBDA for the BIOS Memory Console, and | ||
76 | * set the global variables to point to it. Return true if found. | ||
77 | */ | ||
78 | static bool memconsole_ebda_init(void) | ||
79 | { | ||
80 | unsigned int address; | ||
81 | size_t length, cur; | ||
82 | |||
83 | address = get_bios_ebda(); | ||
84 | if (!address) { | ||
85 | pr_info("memconsole: BIOS EBDA non-existent.\n"); | ||
86 | return false; | ||
87 | } | ||
88 | |||
89 | /* EBDA length is byte 0 of EBDA (in KB) */ | ||
90 | length = *(u8 *)phys_to_virt(address); | ||
91 | length <<= 10; /* convert to bytes */ | ||
92 | |||
93 | /* | ||
94 | * Search through EBDA for BIOS memory console structure | ||
95 | * note: signature is not necessarily dword-aligned | ||
96 | */ | ||
97 | for (cur = 0; cur < length; cur++) { | ||
98 | struct biosmemcon_ebda *hdr = phys_to_virt(address + cur); | ||
99 | |||
100 | /* memconsole v1 */ | ||
101 | if (hdr->signature == BIOS_MEMCONSOLE_V1_MAGIC) { | ||
102 | found_v1_header(hdr); | ||
103 | return true; | ||
104 | } | ||
105 | |||
106 | /* memconsole v2 */ | ||
107 | if (hdr->signature == BIOS_MEMCONSOLE_V2_MAGIC) { | ||
108 | found_v2_header(hdr); | ||
109 | return true; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | pr_info("memconsole: BIOS console EBDA structure not found!\n"); | ||
114 | return false; | ||
115 | } | ||
116 | |||
117 | static struct dmi_system_id memconsole_dmi_table[] __initdata = { | ||
118 | { | ||
119 | .ident = "Google Board", | ||
120 | .matches = { | ||
121 | DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."), | ||
122 | }, | ||
123 | }, | ||
124 | {} | ||
125 | }; | ||
126 | MODULE_DEVICE_TABLE(dmi, memconsole_dmi_table); | ||
127 | |||
128 | static bool __init memconsole_find(void) | ||
129 | { | ||
130 | if (!dmi_check_system(memconsole_dmi_table)) | ||
131 | return false; | ||
132 | |||
133 | return memconsole_ebda_init(); | ||
134 | } | ||
135 | |||
136 | static int __init memconsole_x86_init(void) | ||
137 | { | ||
138 | if (!memconsole_find()) | ||
139 | return -ENODEV; | ||
140 | |||
141 | return memconsole_sysfs_init(); | ||
142 | } | ||
143 | |||
144 | static void __exit memconsole_x86_exit(void) | ||
145 | { | ||
146 | memconsole_exit(); | ||
147 | } | ||
148 | |||
149 | module_init(memconsole_x86_init); | ||
150 | module_exit(memconsole_x86_exit); | ||
151 | |||
152 | MODULE_AUTHOR("Google, Inc."); | ||
153 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/firmware/google/memconsole.c b/drivers/firmware/google/memconsole.c index 2f569aaed4c7..94e200ddb4fa 100644 --- a/drivers/firmware/google/memconsole.c +++ b/drivers/firmware/google/memconsole.c | |||
@@ -1,66 +1,36 @@ | |||
1 | /* | 1 | /* |
2 | * memconsole.c | 2 | * memconsole.c |
3 | * | 3 | * |
4 | * Infrastructure for importing the BIOS memory based console | 4 | * Architecture-independent parts of the memory based BIOS console. |
5 | * into the kernel log ringbuffer. | ||
6 | * | 5 | * |
7 | * Copyright 2010 Google Inc. All rights reserved. | 6 | * Copyright 2017 Google Inc. |
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License v2.0 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
8 | */ | 16 | */ |
9 | 17 | ||
10 | #include <linux/ctype.h> | ||
11 | #include <linux/init.h> | 18 | #include <linux/init.h> |
12 | #include <linux/kernel.h> | ||
13 | #include <linux/string.h> | ||
14 | #include <linux/sysfs.h> | 19 | #include <linux/sysfs.h> |
15 | #include <linux/kobject.h> | 20 | #include <linux/kobject.h> |
16 | #include <linux/module.h> | 21 | #include <linux/module.h> |
17 | #include <linux/dmi.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <asm/bios_ebda.h> | ||
20 | 22 | ||
21 | #define BIOS_MEMCONSOLE_V1_MAGIC 0xDEADBABE | 23 | #include "memconsole.h" |
22 | #define BIOS_MEMCONSOLE_V2_MAGIC (('M')|('C'<<8)|('O'<<16)|('N'<<24)) | ||
23 | 24 | ||
24 | struct biosmemcon_ebda { | 25 | static char *memconsole_baseaddr; |
25 | u32 signature; | ||
26 | union { | ||
27 | struct { | ||
28 | u8 enabled; | ||
29 | u32 buffer_addr; | ||
30 | u16 start; | ||
31 | u16 end; | ||
32 | u16 num_chars; | ||
33 | u8 wrapped; | ||
34 | } __packed v1; | ||
35 | struct { | ||
36 | u32 buffer_addr; | ||
37 | /* Misdocumented as number of pages! */ | ||
38 | u16 num_bytes; | ||
39 | u16 start; | ||
40 | u16 end; | ||
41 | } __packed v2; | ||
42 | }; | ||
43 | } __packed; | ||
44 | |||
45 | static u32 memconsole_baseaddr; | ||
46 | static size_t memconsole_length; | 26 | static size_t memconsole_length; |
47 | 27 | ||
48 | static ssize_t memconsole_read(struct file *filp, struct kobject *kobp, | 28 | static ssize_t memconsole_read(struct file *filp, struct kobject *kobp, |
49 | struct bin_attribute *bin_attr, char *buf, | 29 | struct bin_attribute *bin_attr, char *buf, |
50 | loff_t pos, size_t count) | 30 | loff_t pos, size_t count) |
51 | { | 31 | { |
52 | char *memconsole; | 32 | return memory_read_from_buffer(buf, count, &pos, memconsole_baseaddr, |
53 | ssize_t ret; | 33 | memconsole_length); |
54 | |||
55 | memconsole = ioremap_cache(memconsole_baseaddr, memconsole_length); | ||
56 | if (!memconsole) { | ||
57 | pr_err("memconsole: ioremap_cache failed\n"); | ||
58 | return -ENOMEM; | ||
59 | } | ||
60 | ret = memory_read_from_buffer(buf, count, &pos, memconsole, | ||
61 | memconsole_length); | ||
62 | iounmap(memconsole); | ||
63 | return ret; | ||
64 | } | 34 | } |
65 | 35 | ||
66 | static struct bin_attribute memconsole_bin_attr = { | 36 | static struct bin_attribute memconsole_bin_attr = { |
@@ -68,104 +38,25 @@ static struct bin_attribute memconsole_bin_attr = { | |||
68 | .read = memconsole_read, | 38 | .read = memconsole_read, |
69 | }; | 39 | }; |
70 | 40 | ||
71 | 41 | void memconsole_setup(void *baseaddr, size_t length) | |
72 | static void __init found_v1_header(struct biosmemcon_ebda *hdr) | ||
73 | { | ||
74 | pr_info("BIOS console v1 EBDA structure found at %p\n", hdr); | ||
75 | pr_info("BIOS console buffer at 0x%.8x, " | ||
76 | "start = %d, end = %d, num = %d\n", | ||
77 | hdr->v1.buffer_addr, hdr->v1.start, | ||
78 | hdr->v1.end, hdr->v1.num_chars); | ||
79 | |||
80 | memconsole_length = hdr->v1.num_chars; | ||
81 | memconsole_baseaddr = hdr->v1.buffer_addr; | ||
82 | } | ||
83 | |||
84 | static void __init found_v2_header(struct biosmemcon_ebda *hdr) | ||
85 | { | ||
86 | pr_info("BIOS console v2 EBDA structure found at %p\n", hdr); | ||
87 | pr_info("BIOS console buffer at 0x%.8x, " | ||
88 | "start = %d, end = %d, num_bytes = %d\n", | ||
89 | hdr->v2.buffer_addr, hdr->v2.start, | ||
90 | hdr->v2.end, hdr->v2.num_bytes); | ||
91 | |||
92 | memconsole_length = hdr->v2.end - hdr->v2.start; | ||
93 | memconsole_baseaddr = hdr->v2.buffer_addr + hdr->v2.start; | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * Search through the EBDA for the BIOS Memory Console, and | ||
98 | * set the global variables to point to it. Return true if found. | ||
99 | */ | ||
100 | static bool __init found_memconsole(void) | ||
101 | { | 42 | { |
102 | unsigned int address; | 43 | memconsole_baseaddr = baseaddr; |
103 | size_t length, cur; | 44 | memconsole_length = length; |
104 | |||
105 | address = get_bios_ebda(); | ||
106 | if (!address) { | ||
107 | pr_info("BIOS EBDA non-existent.\n"); | ||
108 | return false; | ||
109 | } | ||
110 | |||
111 | /* EBDA length is byte 0 of EBDA (in KB) */ | ||
112 | length = *(u8 *)phys_to_virt(address); | ||
113 | length <<= 10; /* convert to bytes */ | ||
114 | |||
115 | /* | ||
116 | * Search through EBDA for BIOS memory console structure | ||
117 | * note: signature is not necessarily dword-aligned | ||
118 | */ | ||
119 | for (cur = 0; cur < length; cur++) { | ||
120 | struct biosmemcon_ebda *hdr = phys_to_virt(address + cur); | ||
121 | |||
122 | /* memconsole v1 */ | ||
123 | if (hdr->signature == BIOS_MEMCONSOLE_V1_MAGIC) { | ||
124 | found_v1_header(hdr); | ||
125 | return true; | ||
126 | } | ||
127 | |||
128 | /* memconsole v2 */ | ||
129 | if (hdr->signature == BIOS_MEMCONSOLE_V2_MAGIC) { | ||
130 | found_v2_header(hdr); | ||
131 | return true; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | pr_info("BIOS console EBDA structure not found!\n"); | ||
136 | return false; | ||
137 | } | 45 | } |
46 | EXPORT_SYMBOL(memconsole_setup); | ||
138 | 47 | ||
139 | static struct dmi_system_id memconsole_dmi_table[] __initdata = { | 48 | int memconsole_sysfs_init(void) |
140 | { | ||
141 | .ident = "Google Board", | ||
142 | .matches = { | ||
143 | DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."), | ||
144 | }, | ||
145 | }, | ||
146 | {} | ||
147 | }; | ||
148 | MODULE_DEVICE_TABLE(dmi, memconsole_dmi_table); | ||
149 | |||
150 | static int __init memconsole_init(void) | ||
151 | { | 49 | { |
152 | if (!dmi_check_system(memconsole_dmi_table)) | ||
153 | return -ENODEV; | ||
154 | |||
155 | if (!found_memconsole()) | ||
156 | return -ENODEV; | ||
157 | |||
158 | memconsole_bin_attr.size = memconsole_length; | 50 | memconsole_bin_attr.size = memconsole_length; |
159 | return sysfs_create_bin_file(firmware_kobj, &memconsole_bin_attr); | 51 | return sysfs_create_bin_file(firmware_kobj, &memconsole_bin_attr); |
160 | } | 52 | } |
53 | EXPORT_SYMBOL(memconsole_sysfs_init); | ||
161 | 54 | ||
162 | static void __exit memconsole_exit(void) | 55 | void memconsole_exit(void) |
163 | { | 56 | { |
164 | sysfs_remove_bin_file(firmware_kobj, &memconsole_bin_attr); | 57 | sysfs_remove_bin_file(firmware_kobj, &memconsole_bin_attr); |
165 | } | 58 | } |
166 | 59 | EXPORT_SYMBOL(memconsole_exit); | |
167 | module_init(memconsole_init); | ||
168 | module_exit(memconsole_exit); | ||
169 | 60 | ||
170 | MODULE_AUTHOR("Google, Inc."); | 61 | MODULE_AUTHOR("Google, Inc."); |
171 | MODULE_LICENSE("GPL"); | 62 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/firmware/google/memconsole.h b/drivers/firmware/google/memconsole.h new file mode 100644 index 000000000000..190fc03a51ae --- /dev/null +++ b/drivers/firmware/google/memconsole.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * memconsole.h | ||
3 | * | ||
4 | * Internal headers of the memory based BIOS console. | ||
5 | * | ||
6 | * Copyright 2017 Google Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License v2.0 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #ifndef __FIRMWARE_GOOGLE_MEMCONSOLE_H | ||
19 | #define __FIRMWARE_GOOGLE_MEMCONSOLE_H | ||
20 | |||
21 | /* | ||
22 | * memconsole_setup | ||
23 | * | ||
24 | * Initialize the memory console from raw (virtual) base | ||
25 | * address and length. | ||
26 | */ | ||
27 | void memconsole_setup(void *baseaddr, size_t length); | ||
28 | |||
29 | /* | ||
30 | * memconsole_sysfs_init | ||
31 | * | ||
32 | * Update memory console length and create binary file | ||
33 | * for firmware object. | ||
34 | */ | ||
35 | int memconsole_sysfs_init(void); | ||
36 | |||
37 | /* memconsole_exit | ||
38 | * | ||
39 | * Unmap the console buffer. | ||
40 | */ | ||
41 | void memconsole_exit(void); | ||
42 | |||
43 | #endif /* __FIRMWARE_GOOGLE_MEMCONSOLE_H */ | ||
diff --git a/drivers/firmware/google/vpd.c b/drivers/firmware/google/vpd.c new file mode 100644 index 000000000000..3ce813110d5e --- /dev/null +++ b/drivers/firmware/google/vpd.c | |||
@@ -0,0 +1,332 @@ | |||
1 | /* | ||
2 | * vpd.c | ||
3 | * | ||
4 | * Driver for exporting VPD content to sysfs. | ||
5 | * | ||
6 | * Copyright 2017 Google Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License v2.0 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/ctype.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/kobject.h> | ||
23 | #include <linux/list.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/of_address.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/sysfs.h> | ||
29 | |||
30 | #include "coreboot_table.h" | ||
31 | #include "vpd_decode.h" | ||
32 | |||
33 | #define CB_TAG_VPD 0x2c | ||
34 | #define VPD_CBMEM_MAGIC 0x43524f53 | ||
35 | |||
36 | static struct kobject *vpd_kobj; | ||
37 | |||
38 | struct vpd_cbmem { | ||
39 | u32 magic; | ||
40 | u32 version; | ||
41 | u32 ro_size; | ||
42 | u32 rw_size; | ||
43 | u8 blob[0]; | ||
44 | }; | ||
45 | |||
46 | struct vpd_section { | ||
47 | bool enabled; | ||
48 | const char *name; | ||
49 | char *raw_name; /* the string name_raw */ | ||
50 | struct kobject *kobj; /* vpd/name directory */ | ||
51 | char *baseaddr; | ||
52 | struct bin_attribute bin_attr; /* vpd/name_raw bin_attribute */ | ||
53 | struct list_head attribs; /* key/value in vpd_attrib_info list */ | ||
54 | }; | ||
55 | |||
56 | struct vpd_attrib_info { | ||
57 | char *key; | ||
58 | const char *value; | ||
59 | struct bin_attribute bin_attr; | ||
60 | struct list_head list; | ||
61 | }; | ||
62 | |||
63 | static struct vpd_section ro_vpd; | ||
64 | static struct vpd_section rw_vpd; | ||
65 | |||
66 | static ssize_t vpd_attrib_read(struct file *filp, struct kobject *kobp, | ||
67 | struct bin_attribute *bin_attr, char *buf, | ||
68 | loff_t pos, size_t count) | ||
69 | { | ||
70 | struct vpd_attrib_info *info = bin_attr->private; | ||
71 | |||
72 | return memory_read_from_buffer(buf, count, &pos, info->value, | ||
73 | info->bin_attr.size); | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * vpd_section_check_key_name() | ||
78 | * | ||
79 | * The VPD specification supports only [a-zA-Z0-9_]+ characters in key names but | ||
80 | * old firmware versions may have entries like "S/N" which are problematic when | ||
81 | * exporting them as sysfs attributes. These keys present in old firmwares are | ||
82 | * ignored. | ||
83 | * | ||
84 | * Returns VPD_OK for a valid key name, VPD_FAIL otherwise. | ||
85 | * | ||
86 | * @key: The key name to check | ||
87 | * @key_len: key name length | ||
88 | */ | ||
89 | static int vpd_section_check_key_name(const u8 *key, s32 key_len) | ||
90 | { | ||
91 | int c; | ||
92 | |||
93 | while (key_len-- > 0) { | ||
94 | c = *key++; | ||
95 | |||
96 | if (!isalnum(c) && c != '_') | ||
97 | return VPD_FAIL; | ||
98 | } | ||
99 | |||
100 | return VPD_OK; | ||
101 | } | ||
102 | |||
103 | static int vpd_section_attrib_add(const u8 *key, s32 key_len, | ||
104 | const u8 *value, s32 value_len, | ||
105 | void *arg) | ||
106 | { | ||
107 | int ret; | ||
108 | struct vpd_section *sec = arg; | ||
109 | struct vpd_attrib_info *info; | ||
110 | |||
111 | /* | ||
112 | * Return VPD_OK immediately to decode next entry if the current key | ||
113 | * name contains invalid characters. | ||
114 | */ | ||
115 | if (vpd_section_check_key_name(key, key_len) != VPD_OK) | ||
116 | return VPD_OK; | ||
117 | |||
118 | info = kzalloc(sizeof(*info), GFP_KERNEL); | ||
119 | info->key = kzalloc(key_len + 1, GFP_KERNEL); | ||
120 | if (!info->key) | ||
121 | return -ENOMEM; | ||
122 | |||
123 | memcpy(info->key, key, key_len); | ||
124 | |||
125 | sysfs_bin_attr_init(&info->bin_attr); | ||
126 | info->bin_attr.attr.name = info->key; | ||
127 | info->bin_attr.attr.mode = 0444; | ||
128 | info->bin_attr.size = value_len; | ||
129 | info->bin_attr.read = vpd_attrib_read; | ||
130 | info->bin_attr.private = info; | ||
131 | |||
132 | info->value = value; | ||
133 | |||
134 | INIT_LIST_HEAD(&info->list); | ||
135 | list_add_tail(&info->list, &sec->attribs); | ||
136 | |||
137 | ret = sysfs_create_bin_file(sec->kobj, &info->bin_attr); | ||
138 | if (ret) { | ||
139 | kfree(info->key); | ||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static void vpd_section_attrib_destroy(struct vpd_section *sec) | ||
147 | { | ||
148 | struct vpd_attrib_info *info; | ||
149 | struct vpd_attrib_info *temp; | ||
150 | |||
151 | list_for_each_entry_safe(info, temp, &sec->attribs, list) { | ||
152 | kfree(info->key); | ||
153 | sysfs_remove_bin_file(sec->kobj, &info->bin_attr); | ||
154 | kfree(info); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | static ssize_t vpd_section_read(struct file *filp, struct kobject *kobp, | ||
159 | struct bin_attribute *bin_attr, char *buf, | ||
160 | loff_t pos, size_t count) | ||
161 | { | ||
162 | struct vpd_section *sec = bin_attr->private; | ||
163 | |||
164 | return memory_read_from_buffer(buf, count, &pos, sec->baseaddr, | ||
165 | sec->bin_attr.size); | ||
166 | } | ||
167 | |||
168 | static int vpd_section_create_attribs(struct vpd_section *sec) | ||
169 | { | ||
170 | s32 consumed; | ||
171 | int ret; | ||
172 | |||
173 | consumed = 0; | ||
174 | do { | ||
175 | ret = vpd_decode_string(sec->bin_attr.size, sec->baseaddr, | ||
176 | &consumed, vpd_section_attrib_add, sec); | ||
177 | } while (ret == VPD_OK); | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static int vpd_section_init(const char *name, struct vpd_section *sec, | ||
183 | phys_addr_t physaddr, size_t size) | ||
184 | { | ||
185 | int ret; | ||
186 | int raw_len; | ||
187 | |||
188 | sec->baseaddr = memremap(physaddr, size, MEMREMAP_WB); | ||
189 | if (!sec->baseaddr) | ||
190 | return -ENOMEM; | ||
191 | |||
192 | sec->name = name; | ||
193 | |||
194 | /* We want to export the raw partion with name ${name}_raw */ | ||
195 | raw_len = strlen(name) + 5; | ||
196 | sec->raw_name = kzalloc(raw_len, GFP_KERNEL); | ||
197 | strncpy(sec->raw_name, name, raw_len); | ||
198 | strncat(sec->raw_name, "_raw", raw_len); | ||
199 | |||
200 | sysfs_bin_attr_init(&sec->bin_attr); | ||
201 | sec->bin_attr.attr.name = sec->raw_name; | ||
202 | sec->bin_attr.attr.mode = 0444; | ||
203 | sec->bin_attr.size = size; | ||
204 | sec->bin_attr.read = vpd_section_read; | ||
205 | sec->bin_attr.private = sec; | ||
206 | |||
207 | ret = sysfs_create_bin_file(vpd_kobj, &sec->bin_attr); | ||
208 | if (ret) | ||
209 | goto free_sec; | ||
210 | |||
211 | sec->kobj = kobject_create_and_add(name, vpd_kobj); | ||
212 | if (!sec->kobj) { | ||
213 | ret = -EINVAL; | ||
214 | goto sysfs_remove; | ||
215 | } | ||
216 | |||
217 | INIT_LIST_HEAD(&sec->attribs); | ||
218 | vpd_section_create_attribs(sec); | ||
219 | |||
220 | sec->enabled = true; | ||
221 | |||
222 | return 0; | ||
223 | |||
224 | sysfs_remove: | ||
225 | sysfs_remove_bin_file(vpd_kobj, &sec->bin_attr); | ||
226 | |||
227 | free_sec: | ||
228 | kfree(sec->raw_name); | ||
229 | iounmap(sec->baseaddr); | ||
230 | |||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | static int vpd_section_destroy(struct vpd_section *sec) | ||
235 | { | ||
236 | if (sec->enabled) { | ||
237 | vpd_section_attrib_destroy(sec); | ||
238 | kobject_del(sec->kobj); | ||
239 | sysfs_remove_bin_file(vpd_kobj, &sec->bin_attr); | ||
240 | kfree(sec->raw_name); | ||
241 | iounmap(sec->baseaddr); | ||
242 | } | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static int vpd_sections_init(phys_addr_t physaddr) | ||
248 | { | ||
249 | struct vpd_cbmem __iomem *temp; | ||
250 | struct vpd_cbmem header; | ||
251 | int ret = 0; | ||
252 | |||
253 | temp = memremap(physaddr, sizeof(struct vpd_cbmem), MEMREMAP_WB); | ||
254 | if (!temp) | ||
255 | return -ENOMEM; | ||
256 | |||
257 | memcpy_fromio(&header, temp, sizeof(struct vpd_cbmem)); | ||
258 | iounmap(temp); | ||
259 | |||
260 | if (header.magic != VPD_CBMEM_MAGIC) | ||
261 | return -ENODEV; | ||
262 | |||
263 | if (header.ro_size) { | ||
264 | ret = vpd_section_init("ro", &ro_vpd, | ||
265 | physaddr + sizeof(struct vpd_cbmem), | ||
266 | header.ro_size); | ||
267 | if (ret) | ||
268 | return ret; | ||
269 | } | ||
270 | |||
271 | if (header.rw_size) { | ||
272 | ret = vpd_section_init("rw", &rw_vpd, | ||
273 | physaddr + sizeof(struct vpd_cbmem) + | ||
274 | header.ro_size, header.rw_size); | ||
275 | if (ret) | ||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static int vpd_probe(struct platform_device *pdev) | ||
283 | { | ||
284 | int ret; | ||
285 | struct lb_cbmem_ref entry; | ||
286 | |||
287 | ret = coreboot_table_find(CB_TAG_VPD, &entry, sizeof(entry)); | ||
288 | if (ret) | ||
289 | return ret; | ||
290 | |||
291 | return vpd_sections_init(entry.cbmem_addr); | ||
292 | } | ||
293 | |||
294 | static struct platform_driver vpd_driver = { | ||
295 | .probe = vpd_probe, | ||
296 | .driver = { | ||
297 | .name = "vpd", | ||
298 | }, | ||
299 | }; | ||
300 | |||
301 | static int __init vpd_platform_init(void) | ||
302 | { | ||
303 | struct platform_device *pdev; | ||
304 | |||
305 | pdev = platform_device_register_simple("vpd", -1, NULL, 0); | ||
306 | if (IS_ERR(pdev)) | ||
307 | return PTR_ERR(pdev); | ||
308 | |||
309 | vpd_kobj = kobject_create_and_add("vpd", firmware_kobj); | ||
310 | if (!vpd_kobj) | ||
311 | return -ENOMEM; | ||
312 | |||
313 | memset(&ro_vpd, 0, sizeof(ro_vpd)); | ||
314 | memset(&rw_vpd, 0, sizeof(rw_vpd)); | ||
315 | |||
316 | platform_driver_register(&vpd_driver); | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | static void __exit vpd_platform_exit(void) | ||
322 | { | ||
323 | vpd_section_destroy(&ro_vpd); | ||
324 | vpd_section_destroy(&rw_vpd); | ||
325 | kobject_del(vpd_kobj); | ||
326 | } | ||
327 | |||
328 | module_init(vpd_platform_init); | ||
329 | module_exit(vpd_platform_exit); | ||
330 | |||
331 | MODULE_AUTHOR("Google, Inc."); | ||
332 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/firmware/google/vpd_decode.c b/drivers/firmware/google/vpd_decode.c new file mode 100644 index 000000000000..943acaa8aa76 --- /dev/null +++ b/drivers/firmware/google/vpd_decode.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * vpd_decode.c | ||
3 | * | ||
4 | * Google VPD decoding routines. | ||
5 | * | ||
6 | * Copyright 2017 Google Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License v2.0 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/export.h> | ||
19 | |||
20 | #include "vpd_decode.h" | ||
21 | |||
22 | static int vpd_decode_len(const s32 max_len, const u8 *in, | ||
23 | s32 *length, s32 *decoded_len) | ||
24 | { | ||
25 | u8 more; | ||
26 | int i = 0; | ||
27 | |||
28 | if (!length || !decoded_len) | ||
29 | return VPD_FAIL; | ||
30 | |||
31 | *length = 0; | ||
32 | do { | ||
33 | if (i >= max_len) | ||
34 | return VPD_FAIL; | ||
35 | |||
36 | more = in[i] & 0x80; | ||
37 | *length <<= 7; | ||
38 | *length |= in[i] & 0x7f; | ||
39 | ++i; | ||
40 | } while (more); | ||
41 | |||
42 | *decoded_len = i; | ||
43 | |||
44 | return VPD_OK; | ||
45 | } | ||
46 | |||
47 | int vpd_decode_string(const s32 max_len, const u8 *input_buf, s32 *consumed, | ||
48 | vpd_decode_callback callback, void *callback_arg) | ||
49 | { | ||
50 | int type; | ||
51 | int res; | ||
52 | s32 key_len; | ||
53 | s32 value_len; | ||
54 | s32 decoded_len; | ||
55 | const u8 *key; | ||
56 | const u8 *value; | ||
57 | |||
58 | /* type */ | ||
59 | if (*consumed >= max_len) | ||
60 | return VPD_FAIL; | ||
61 | |||
62 | type = input_buf[*consumed]; | ||
63 | |||
64 | switch (type) { | ||
65 | case VPD_TYPE_INFO: | ||
66 | case VPD_TYPE_STRING: | ||
67 | (*consumed)++; | ||
68 | |||
69 | /* key */ | ||
70 | res = vpd_decode_len(max_len - *consumed, &input_buf[*consumed], | ||
71 | &key_len, &decoded_len); | ||
72 | if (res != VPD_OK || *consumed + decoded_len >= max_len) | ||
73 | return VPD_FAIL; | ||
74 | |||
75 | *consumed += decoded_len; | ||
76 | key = &input_buf[*consumed]; | ||
77 | *consumed += key_len; | ||
78 | |||
79 | /* value */ | ||
80 | res = vpd_decode_len(max_len - *consumed, &input_buf[*consumed], | ||
81 | &value_len, &decoded_len); | ||
82 | if (res != VPD_OK || *consumed + decoded_len > max_len) | ||
83 | return VPD_FAIL; | ||
84 | |||
85 | *consumed += decoded_len; | ||
86 | value = &input_buf[*consumed]; | ||
87 | *consumed += value_len; | ||
88 | |||
89 | if (type == VPD_TYPE_STRING) | ||
90 | return callback(key, key_len, value, value_len, | ||
91 | callback_arg); | ||
92 | break; | ||
93 | |||
94 | default: | ||
95 | return VPD_FAIL; | ||
96 | } | ||
97 | |||
98 | return VPD_OK; | ||
99 | } | ||
diff --git a/drivers/firmware/google/vpd_decode.h b/drivers/firmware/google/vpd_decode.h new file mode 100644 index 000000000000..be3d62c5ca2f --- /dev/null +++ b/drivers/firmware/google/vpd_decode.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * vpd_decode.h | ||
3 | * | ||
4 | * Google VPD decoding routines. | ||
5 | * | ||
6 | * Copyright 2017 Google Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License v2.0 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #ifndef __VPD_DECODE_H | ||
19 | #define __VPD_DECODE_H | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | |||
23 | enum { | ||
24 | VPD_OK = 0, | ||
25 | VPD_FAIL, | ||
26 | }; | ||
27 | |||
28 | enum { | ||
29 | VPD_TYPE_TERMINATOR = 0, | ||
30 | VPD_TYPE_STRING, | ||
31 | VPD_TYPE_INFO = 0xfe, | ||
32 | VPD_TYPE_IMPLICIT_TERMINATOR = 0xff, | ||
33 | }; | ||
34 | |||
35 | /* Callback for vpd_decode_string to invoke. */ | ||
36 | typedef int vpd_decode_callback(const u8 *key, s32 key_len, | ||
37 | const u8 *value, s32 value_len, | ||
38 | void *arg); | ||
39 | |||
40 | /* | ||
41 | * vpd_decode_string | ||
42 | * | ||
43 | * Given the encoded string, this function invokes callback with extracted | ||
44 | * (key, value). The *consumed will be plused the number of bytes consumed in | ||
45 | * this function. | ||
46 | * | ||
47 | * The input_buf points to the first byte of the input buffer. | ||
48 | * | ||
49 | * The *consumed starts from 0, which is actually the next byte to be decoded. | ||
50 | * It can be non-zero to be used in multiple calls. | ||
51 | * | ||
52 | * If one entry is successfully decoded, sends it to callback and returns the | ||
53 | * result. | ||
54 | */ | ||
55 | int vpd_decode_string(const s32 max_len, const u8 *input_buf, s32 *consumed, | ||
56 | vpd_decode_callback callback, void *callback_arg); | ||
57 | |||
58 | #endif /* __VPD_DECODE_H */ | ||
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index ce861a2853a4..161ba9dccede 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig | |||
@@ -20,6 +20,12 @@ config FPGA_REGION | |||
20 | FPGA Regions allow loading FPGA images under control of | 20 | FPGA Regions allow loading FPGA images under control of |
21 | the Device Tree. | 21 | the Device Tree. |
22 | 22 | ||
23 | config FPGA_MGR_ICE40_SPI | ||
24 | tristate "Lattice iCE40 SPI" | ||
25 | depends on OF && SPI | ||
26 | help | ||
27 | FPGA manager driver support for Lattice iCE40 FPGAs over SPI. | ||
28 | |||
23 | config FPGA_MGR_SOCFPGA | 29 | config FPGA_MGR_SOCFPGA |
24 | tristate "Altera SOCFPGA FPGA Manager" | 30 | tristate "Altera SOCFPGA FPGA Manager" |
25 | depends on ARCH_SOCFPGA || COMPILE_TEST | 31 | depends on ARCH_SOCFPGA || COMPILE_TEST |
@@ -33,6 +39,20 @@ config FPGA_MGR_SOCFPGA_A10 | |||
33 | help | 39 | help |
34 | FPGA manager driver support for Altera Arria10 SoCFPGA. | 40 | FPGA manager driver support for Altera Arria10 SoCFPGA. |
35 | 41 | ||
42 | config FPGA_MGR_TS73XX | ||
43 | tristate "Technologic Systems TS-73xx SBC FPGA Manager" | ||
44 | depends on ARCH_EP93XX && MACH_TS72XX | ||
45 | help | ||
46 | FPGA manager driver support for the Altera Cyclone II FPGA | ||
47 | present on the TS-73xx SBC boards. | ||
48 | |||
49 | config FPGA_MGR_XILINX_SPI | ||
50 | tristate "Xilinx Configuration over Slave Serial (SPI)" | ||
51 | depends on SPI | ||
52 | help | ||
53 | FPGA manager driver support for Xilinx FPGA configuration | ||
54 | over slave serial interface. | ||
55 | |||
36 | config FPGA_MGR_ZYNQ_FPGA | 56 | config FPGA_MGR_ZYNQ_FPGA |
37 | tristate "Xilinx Zynq FPGA" | 57 | tristate "Xilinx Zynq FPGA" |
38 | depends on ARCH_ZYNQ || COMPILE_TEST | 58 | depends on ARCH_ZYNQ || COMPILE_TEST |
@@ -63,6 +83,28 @@ config ALTERA_FREEZE_BRIDGE | |||
63 | isolate one region of the FPGA from the busses while that | 83 | isolate one region of the FPGA from the busses while that |
64 | region is being reprogrammed. | 84 | region is being reprogrammed. |
65 | 85 | ||
86 | config ALTERA_PR_IP_CORE | ||
87 | tristate "Altera Partial Reconfiguration IP Core" | ||
88 | help | ||
89 | Core driver support for Altera Partial Reconfiguration IP component | ||
90 | |||
91 | config ALTERA_PR_IP_CORE_PLAT | ||
92 | tristate "Platform support of Altera Partial Reconfiguration IP Core" | ||
93 | depends on ALTERA_PR_IP_CORE && OF && HAS_IOMEM | ||
94 | help | ||
95 | Platform driver support for Altera Partial Reconfiguration IP | ||
96 | component | ||
97 | |||
98 | config XILINX_PR_DECOUPLER | ||
99 | tristate "Xilinx LogiCORE PR Decoupler" | ||
100 | depends on FPGA_BRIDGE | ||
101 | depends on HAS_IOMEM | ||
102 | help | ||
103 | Say Y to enable drivers for Xilinx LogiCORE PR Decoupler. | ||
104 | The PR Decoupler exists in the FPGA fabric to isolate one | ||
105 | region of the FPGA from the busses while that region is | ||
106 | being reprogrammed during partial reconfig. | ||
107 | |||
66 | endif # FPGA | 108 | endif # FPGA |
67 | 109 | ||
68 | endmenu | 110 | endmenu |
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 8df07bcf42a6..2a4f0218145c 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile | |||
@@ -6,14 +6,20 @@ | |||
6 | obj-$(CONFIG_FPGA) += fpga-mgr.o | 6 | obj-$(CONFIG_FPGA) += fpga-mgr.o |
7 | 7 | ||
8 | # FPGA Manager Drivers | 8 | # FPGA Manager Drivers |
9 | obj-$(CONFIG_FPGA_MGR_ICE40_SPI) += ice40-spi.o | ||
9 | obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o | 10 | obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o |
10 | obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o | 11 | obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o |
12 | obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o | ||
13 | obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o | ||
11 | obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o | 14 | obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o |
15 | obj-$(CONFIG_ALTERA_PR_IP_CORE) += altera-pr-ip-core.o | ||
16 | obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o | ||
12 | 17 | ||
13 | # FPGA Bridge Drivers | 18 | # FPGA Bridge Drivers |
14 | obj-$(CONFIG_FPGA_BRIDGE) += fpga-bridge.o | 19 | obj-$(CONFIG_FPGA_BRIDGE) += fpga-bridge.o |
15 | obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE) += altera-hps2fpga.o altera-fpga2sdram.o | 20 | obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE) += altera-hps2fpga.o altera-fpga2sdram.o |
16 | obj-$(CONFIG_ALTERA_FREEZE_BRIDGE) += altera-freeze-bridge.o | 21 | obj-$(CONFIG_ALTERA_FREEZE_BRIDGE) += altera-freeze-bridge.o |
22 | obj-$(CONFIG_XILINX_PR_DECOUPLER) += xilinx-pr-decoupler.o | ||
17 | 23 | ||
18 | # High Level Interfaces | 24 | # High Level Interfaces |
19 | obj-$(CONFIG_FPGA_REGION) += fpga-region.o | 25 | obj-$(CONFIG_FPGA_REGION) += fpga-region.o |
diff --git a/drivers/fpga/altera-freeze-bridge.c b/drivers/fpga/altera-freeze-bridge.c index 8dcd9fb22cb9..6159cfcf78a2 100644 --- a/drivers/fpga/altera-freeze-bridge.c +++ b/drivers/fpga/altera-freeze-bridge.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #define FREEZE_CSR_REG_VERSION 12 | 28 | #define FREEZE_CSR_REG_VERSION 12 |
29 | 29 | ||
30 | #define FREEZE_CSR_SUPPORTED_VERSION 2 | 30 | #define FREEZE_CSR_SUPPORTED_VERSION 2 |
31 | #define FREEZE_CSR_OFFICIAL_VERSION 0xad000003 | ||
31 | 32 | ||
32 | #define FREEZE_CSR_STATUS_FREEZE_REQ_DONE BIT(0) | 33 | #define FREEZE_CSR_STATUS_FREEZE_REQ_DONE BIT(0) |
33 | #define FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE BIT(1) | 34 | #define FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE BIT(1) |
@@ -203,7 +204,7 @@ static int altera_freeze_br_enable_show(struct fpga_bridge *bridge) | |||
203 | return priv->enable; | 204 | return priv->enable; |
204 | } | 205 | } |
205 | 206 | ||
206 | static struct fpga_bridge_ops altera_freeze_br_br_ops = { | 207 | static const struct fpga_bridge_ops altera_freeze_br_br_ops = { |
207 | .enable_set = altera_freeze_br_enable_set, | 208 | .enable_set = altera_freeze_br_enable_set, |
208 | .enable_show = altera_freeze_br_enable_show, | 209 | .enable_show = altera_freeze_br_enable_show, |
209 | }; | 210 | }; |
@@ -218,6 +219,7 @@ static int altera_freeze_br_probe(struct platform_device *pdev) | |||
218 | { | 219 | { |
219 | struct device *dev = &pdev->dev; | 220 | struct device *dev = &pdev->dev; |
220 | struct device_node *np = pdev->dev.of_node; | 221 | struct device_node *np = pdev->dev.of_node; |
222 | void __iomem *base_addr; | ||
221 | struct altera_freeze_br_data *priv; | 223 | struct altera_freeze_br_data *priv; |
222 | struct resource *res; | 224 | struct resource *res; |
223 | u32 status, revision; | 225 | u32 status, revision; |
@@ -225,26 +227,32 @@ static int altera_freeze_br_probe(struct platform_device *pdev) | |||
225 | if (!np) | 227 | if (!np) |
226 | return -ENODEV; | 228 | return -ENODEV; |
227 | 229 | ||
230 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
231 | base_addr = devm_ioremap_resource(dev, res); | ||
232 | if (IS_ERR(base_addr)) | ||
233 | return PTR_ERR(base_addr); | ||
234 | |||
235 | revision = readl(base_addr + FREEZE_CSR_REG_VERSION); | ||
236 | if ((revision != FREEZE_CSR_SUPPORTED_VERSION) && | ||
237 | (revision != FREEZE_CSR_OFFICIAL_VERSION)) { | ||
238 | dev_err(dev, | ||
239 | "%s unexpected revision 0x%x != 0x%x != 0x%x\n", | ||
240 | __func__, revision, FREEZE_CSR_SUPPORTED_VERSION, | ||
241 | FREEZE_CSR_OFFICIAL_VERSION); | ||
242 | return -EINVAL; | ||
243 | } | ||
244 | |||
228 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | 245 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
229 | if (!priv) | 246 | if (!priv) |
230 | return -ENOMEM; | 247 | return -ENOMEM; |
231 | 248 | ||
232 | priv->dev = dev; | 249 | priv->dev = dev; |
233 | 250 | ||
234 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 251 | status = readl(base_addr + FREEZE_CSR_STATUS_OFFSET); |
235 | priv->base_addr = devm_ioremap_resource(dev, res); | ||
236 | if (IS_ERR(priv->base_addr)) | ||
237 | return PTR_ERR(priv->base_addr); | ||
238 | |||
239 | status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET); | ||
240 | if (status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE) | 252 | if (status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE) |
241 | priv->enable = 1; | 253 | priv->enable = 1; |
242 | 254 | ||
243 | revision = readl(priv->base_addr + FREEZE_CSR_REG_VERSION); | 255 | priv->base_addr = base_addr; |
244 | if (revision != FREEZE_CSR_SUPPORTED_VERSION) | ||
245 | dev_warn(dev, | ||
246 | "%s Freeze Controller unexpected revision %d != %d\n", | ||
247 | __func__, revision, FREEZE_CSR_SUPPORTED_VERSION); | ||
248 | 256 | ||
249 | return fpga_bridge_register(dev, FREEZE_BRIDGE_NAME, | 257 | return fpga_bridge_register(dev, FREEZE_BRIDGE_NAME, |
250 | &altera_freeze_br_br_ops, priv); | 258 | &altera_freeze_br_br_ops, priv); |
diff --git a/drivers/fpga/altera-hps2fpga.c b/drivers/fpga/altera-hps2fpga.c index 4b354c79be31..3066b805f2d0 100644 --- a/drivers/fpga/altera-hps2fpga.c +++ b/drivers/fpga/altera-hps2fpga.c | |||
@@ -181,15 +181,18 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev) | |||
181 | (enable ? "enabling" : "disabling")); | 181 | (enable ? "enabling" : "disabling")); |
182 | 182 | ||
183 | ret = _alt_hps2fpga_enable_set(priv, enable); | 183 | ret = _alt_hps2fpga_enable_set(priv, enable); |
184 | if (ret) { | 184 | if (ret) |
185 | fpga_bridge_unregister(&pdev->dev); | 185 | goto err; |
186 | return ret; | ||
187 | } | ||
188 | } | 186 | } |
189 | } | 187 | } |
190 | 188 | ||
191 | return fpga_bridge_register(dev, priv->name, &altera_hps2fpga_br_ops, | 189 | ret = fpga_bridge_register(dev, priv->name, &altera_hps2fpga_br_ops, |
192 | priv); | 190 | priv); |
191 | err: | ||
192 | if (ret) | ||
193 | clk_disable_unprepare(priv->clk); | ||
194 | |||
195 | return ret; | ||
193 | } | 196 | } |
194 | 197 | ||
195 | static int alt_fpga_bridge_remove(struct platform_device *pdev) | 198 | static int alt_fpga_bridge_remove(struct platform_device *pdev) |
diff --git a/drivers/fpga/altera-pr-ip-core-plat.c b/drivers/fpga/altera-pr-ip-core-plat.c new file mode 100644 index 000000000000..8fb36b8b4648 --- /dev/null +++ b/drivers/fpga/altera-pr-ip-core-plat.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * Driver for Altera Partial Reconfiguration IP Core | ||
3 | * | ||
4 | * Copyright (C) 2016-2017 Intel Corporation | ||
5 | * | ||
6 | * Based on socfpga-a10.c Copyright (C) 2015-2016 Altera Corporation | ||
7 | * by Alan Tull <atull@opensource.altera.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms and conditions of the GNU General Public License, | ||
11 | * version 2, as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | ||
21 | #include <linux/fpga/altera-pr-ip-core.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/of_device.h> | ||
24 | |||
25 | static int alt_pr_platform_probe(struct platform_device *pdev) | ||
26 | { | ||
27 | struct device *dev = &pdev->dev; | ||
28 | void __iomem *reg_base; | ||
29 | struct resource *res; | ||
30 | |||
31 | /* First mmio base is for register access */ | ||
32 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
33 | |||
34 | reg_base = devm_ioremap_resource(dev, res); | ||
35 | |||
36 | if (IS_ERR(reg_base)) | ||
37 | return PTR_ERR(reg_base); | ||
38 | |||
39 | return alt_pr_register(dev, reg_base); | ||
40 | } | ||
41 | |||
42 | static int alt_pr_platform_remove(struct platform_device *pdev) | ||
43 | { | ||
44 | struct device *dev = &pdev->dev; | ||
45 | |||
46 | return alt_pr_unregister(dev); | ||
47 | } | ||
48 | |||
49 | static const struct of_device_id alt_pr_of_match[] = { | ||
50 | { .compatible = "altr,a10-pr-ip", }, | ||
51 | {}, | ||
52 | }; | ||
53 | |||
54 | MODULE_DEVICE_TABLE(of, alt_pr_of_match); | ||
55 | |||
56 | static struct platform_driver alt_pr_platform_driver = { | ||
57 | .probe = alt_pr_platform_probe, | ||
58 | .remove = alt_pr_platform_remove, | ||
59 | .driver = { | ||
60 | .name = "alt_a10_pr_ip", | ||
61 | .of_match_table = alt_pr_of_match, | ||
62 | }, | ||
63 | }; | ||
64 | |||
65 | module_platform_driver(alt_pr_platform_driver); | ||
66 | MODULE_AUTHOR("Matthew Gerlach <matthew.gerlach@linux.intel.com>"); | ||
67 | MODULE_DESCRIPTION("Altera Partial Reconfiguration IP Platform Driver"); | ||
68 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/fpga/altera-pr-ip-core.c b/drivers/fpga/altera-pr-ip-core.c new file mode 100644 index 000000000000..a7b31f9797ce --- /dev/null +++ b/drivers/fpga/altera-pr-ip-core.c | |||
@@ -0,0 +1,220 @@ | |||
1 | /* | ||
2 | * Driver for Altera Partial Reconfiguration IP Core | ||
3 | * | ||
4 | * Copyright (C) 2016-2017 Intel Corporation | ||
5 | * | ||
6 | * Based on socfpga-a10.c Copyright (C) 2015-2016 Altera Corporation | ||
7 | * by Alan Tull <atull@opensource.altera.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms and conditions of the GNU General Public License, | ||
11 | * version 2, as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/fpga/altera-pr-ip-core.h> | ||
23 | #include <linux/fpga/fpga-mgr.h> | ||
24 | #include <linux/module.h> | ||
25 | |||
26 | #define ALT_PR_DATA_OFST 0x00 | ||
27 | #define ALT_PR_CSR_OFST 0x04 | ||
28 | |||
29 | #define ALT_PR_CSR_PR_START BIT(0) | ||
30 | #define ALT_PR_CSR_STATUS_SFT 2 | ||
31 | #define ALT_PR_CSR_STATUS_MSK (7 << ALT_PR_CSR_STATUS_SFT) | ||
32 | #define ALT_PR_CSR_STATUS_NRESET (0 << ALT_PR_CSR_STATUS_SFT) | ||
33 | #define ALT_PR_CSR_STATUS_PR_ERR (1 << ALT_PR_CSR_STATUS_SFT) | ||
34 | #define ALT_PR_CSR_STATUS_CRC_ERR (2 << ALT_PR_CSR_STATUS_SFT) | ||
35 | #define ALT_PR_CSR_STATUS_BAD_BITS (3 << ALT_PR_CSR_STATUS_SFT) | ||
36 | #define ALT_PR_CSR_STATUS_PR_IN_PROG (4 << ALT_PR_CSR_STATUS_SFT) | ||
37 | #define ALT_PR_CSR_STATUS_PR_SUCCESS (5 << ALT_PR_CSR_STATUS_SFT) | ||
38 | |||
39 | struct alt_pr_priv { | ||
40 | void __iomem *reg_base; | ||
41 | }; | ||
42 | |||
43 | static enum fpga_mgr_states alt_pr_fpga_state(struct fpga_manager *mgr) | ||
44 | { | ||
45 | struct alt_pr_priv *priv = mgr->priv; | ||
46 | const char *err = "unknown"; | ||
47 | enum fpga_mgr_states ret = FPGA_MGR_STATE_UNKNOWN; | ||
48 | u32 val; | ||
49 | |||
50 | val = readl(priv->reg_base + ALT_PR_CSR_OFST); | ||
51 | |||
52 | val &= ALT_PR_CSR_STATUS_MSK; | ||
53 | |||
54 | switch (val) { | ||
55 | case ALT_PR_CSR_STATUS_NRESET: | ||
56 | return FPGA_MGR_STATE_RESET; | ||
57 | |||
58 | case ALT_PR_CSR_STATUS_PR_ERR: | ||
59 | err = "pr error"; | ||
60 | ret = FPGA_MGR_STATE_WRITE_ERR; | ||
61 | break; | ||
62 | |||
63 | case ALT_PR_CSR_STATUS_CRC_ERR: | ||
64 | err = "crc error"; | ||
65 | ret = FPGA_MGR_STATE_WRITE_ERR; | ||
66 | break; | ||
67 | |||
68 | case ALT_PR_CSR_STATUS_BAD_BITS: | ||
69 | err = "bad bits"; | ||
70 | ret = FPGA_MGR_STATE_WRITE_ERR; | ||
71 | break; | ||
72 | |||
73 | case ALT_PR_CSR_STATUS_PR_IN_PROG: | ||
74 | return FPGA_MGR_STATE_WRITE; | ||
75 | |||
76 | case ALT_PR_CSR_STATUS_PR_SUCCESS: | ||
77 | return FPGA_MGR_STATE_OPERATING; | ||
78 | |||
79 | default: | ||
80 | break; | ||
81 | } | ||
82 | |||
83 | dev_err(&mgr->dev, "encountered error code %d (%s) in %s()\n", | ||
84 | val, err, __func__); | ||
85 | return ret; | ||
86 | } | ||
87 | |||
88 | static int alt_pr_fpga_write_init(struct fpga_manager *mgr, | ||
89 | struct fpga_image_info *info, | ||
90 | const char *buf, size_t count) | ||
91 | { | ||
92 | struct alt_pr_priv *priv = mgr->priv; | ||
93 | u32 val; | ||
94 | |||
95 | if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { | ||
96 | dev_err(&mgr->dev, "%s Partial Reconfiguration flag not set\n", | ||
97 | __func__); | ||
98 | return -EINVAL; | ||
99 | } | ||
100 | |||
101 | val = readl(priv->reg_base + ALT_PR_CSR_OFST); | ||
102 | |||
103 | if (val & ALT_PR_CSR_PR_START) { | ||
104 | dev_err(&mgr->dev, | ||
105 | "%s Partial Reconfiguration already started\n", | ||
106 | __func__); | ||
107 | return -EINVAL; | ||
108 | } | ||
109 | |||
110 | writel(val | ALT_PR_CSR_PR_START, priv->reg_base + ALT_PR_CSR_OFST); | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static int alt_pr_fpga_write(struct fpga_manager *mgr, const char *buf, | ||
116 | size_t count) | ||
117 | { | ||
118 | struct alt_pr_priv *priv = mgr->priv; | ||
119 | u32 *buffer_32 = (u32 *)buf; | ||
120 | size_t i = 0; | ||
121 | |||
122 | if (count <= 0) | ||
123 | return -EINVAL; | ||
124 | |||
125 | /* Write out the complete 32-bit chunks */ | ||
126 | while (count >= sizeof(u32)) { | ||
127 | writel(buffer_32[i++], priv->reg_base); | ||
128 | count -= sizeof(u32); | ||
129 | } | ||
130 | |||
131 | /* Write out remaining non 32-bit chunks */ | ||
132 | switch (count) { | ||
133 | case 3: | ||
134 | writel(buffer_32[i++] & 0x00ffffff, priv->reg_base); | ||
135 | break; | ||
136 | case 2: | ||
137 | writel(buffer_32[i++] & 0x0000ffff, priv->reg_base); | ||
138 | break; | ||
139 | case 1: | ||
140 | writel(buffer_32[i++] & 0x000000ff, priv->reg_base); | ||
141 | break; | ||
142 | case 0: | ||
143 | break; | ||
144 | default: | ||
145 | /* This will never happen */ | ||
146 | return -EFAULT; | ||
147 | } | ||
148 | |||
149 | if (alt_pr_fpga_state(mgr) == FPGA_MGR_STATE_WRITE_ERR) | ||
150 | return -EIO; | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static int alt_pr_fpga_write_complete(struct fpga_manager *mgr, | ||
156 | struct fpga_image_info *info) | ||
157 | { | ||
158 | u32 i = 0; | ||
159 | |||
160 | do { | ||
161 | switch (alt_pr_fpga_state(mgr)) { | ||
162 | case FPGA_MGR_STATE_WRITE_ERR: | ||
163 | return -EIO; | ||
164 | |||
165 | case FPGA_MGR_STATE_OPERATING: | ||
166 | dev_info(&mgr->dev, | ||
167 | "successful partial reconfiguration\n"); | ||
168 | return 0; | ||
169 | |||
170 | default: | ||
171 | break; | ||
172 | } | ||
173 | udelay(1); | ||
174 | } while (info->config_complete_timeout_us > i++); | ||
175 | |||
176 | dev_err(&mgr->dev, "timed out waiting for write to complete\n"); | ||
177 | return -ETIMEDOUT; | ||
178 | } | ||
179 | |||
180 | static const struct fpga_manager_ops alt_pr_ops = { | ||
181 | .state = alt_pr_fpga_state, | ||
182 | .write_init = alt_pr_fpga_write_init, | ||
183 | .write = alt_pr_fpga_write, | ||
184 | .write_complete = alt_pr_fpga_write_complete, | ||
185 | }; | ||
186 | |||
187 | int alt_pr_register(struct device *dev, void __iomem *reg_base) | ||
188 | { | ||
189 | struct alt_pr_priv *priv; | ||
190 | u32 val; | ||
191 | |||
192 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
193 | if (!priv) | ||
194 | return -ENOMEM; | ||
195 | |||
196 | priv->reg_base = reg_base; | ||
197 | |||
198 | val = readl(priv->reg_base + ALT_PR_CSR_OFST); | ||
199 | |||
200 | dev_dbg(dev, "%s status=%d start=%d\n", __func__, | ||
201 | (val & ALT_PR_CSR_STATUS_MSK) >> ALT_PR_CSR_STATUS_SFT, | ||
202 | (int)(val & ALT_PR_CSR_PR_START)); | ||
203 | |||
204 | return fpga_mgr_register(dev, dev_name(dev), &alt_pr_ops, priv); | ||
205 | } | ||
206 | EXPORT_SYMBOL_GPL(alt_pr_register); | ||
207 | |||
208 | int alt_pr_unregister(struct device *dev) | ||
209 | { | ||
210 | dev_dbg(dev, "%s\n", __func__); | ||
211 | |||
212 | fpga_mgr_unregister(dev); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | EXPORT_SYMBOL_GPL(alt_pr_unregister); | ||
217 | |||
218 | MODULE_AUTHOR("Matthew Gerlach <matthew.gerlach@linux.intel.com>"); | ||
219 | MODULE_DESCRIPTION("Altera Partial Reconfiguration IP Core"); | ||
220 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c index 33ee83e6373c..9651aa56244a 100644 --- a/drivers/fpga/fpga-bridge.c +++ b/drivers/fpga/fpga-bridge.c | |||
@@ -27,7 +27,7 @@ static DEFINE_IDA(fpga_bridge_ida); | |||
27 | static struct class *fpga_bridge_class; | 27 | static struct class *fpga_bridge_class; |
28 | 28 | ||
29 | /* Lock for adding/removing bridges to linked lists*/ | 29 | /* Lock for adding/removing bridges to linked lists*/ |
30 | spinlock_t bridge_list_lock; | 30 | static spinlock_t bridge_list_lock; |
31 | 31 | ||
32 | static int fpga_bridge_of_node_match(struct device *dev, const void *data) | 32 | static int fpga_bridge_of_node_match(struct device *dev, const void *data) |
33 | { | 33 | { |
@@ -146,11 +146,9 @@ EXPORT_SYMBOL_GPL(fpga_bridge_put); | |||
146 | int fpga_bridges_enable(struct list_head *bridge_list) | 146 | int fpga_bridges_enable(struct list_head *bridge_list) |
147 | { | 147 | { |
148 | struct fpga_bridge *bridge; | 148 | struct fpga_bridge *bridge; |
149 | struct list_head *node; | ||
150 | int ret; | 149 | int ret; |
151 | 150 | ||
152 | list_for_each(node, bridge_list) { | 151 | list_for_each_entry(bridge, bridge_list, node) { |
153 | bridge = list_entry(node, struct fpga_bridge, node); | ||
154 | ret = fpga_bridge_enable(bridge); | 152 | ret = fpga_bridge_enable(bridge); |
155 | if (ret) | 153 | if (ret) |
156 | return ret; | 154 | return ret; |
@@ -172,11 +170,9 @@ EXPORT_SYMBOL_GPL(fpga_bridges_enable); | |||
172 | int fpga_bridges_disable(struct list_head *bridge_list) | 170 | int fpga_bridges_disable(struct list_head *bridge_list) |
173 | { | 171 | { |
174 | struct fpga_bridge *bridge; | 172 | struct fpga_bridge *bridge; |
175 | struct list_head *node; | ||
176 | int ret; | 173 | int ret; |
177 | 174 | ||
178 | list_for_each(node, bridge_list) { | 175 | list_for_each_entry(bridge, bridge_list, node) { |
179 | bridge = list_entry(node, struct fpga_bridge, node); | ||
180 | ret = fpga_bridge_disable(bridge); | 176 | ret = fpga_bridge_disable(bridge); |
181 | if (ret) | 177 | if (ret) |
182 | return ret; | 178 | return ret; |
@@ -196,13 +192,10 @@ EXPORT_SYMBOL_GPL(fpga_bridges_disable); | |||
196 | */ | 192 | */ |
197 | void fpga_bridges_put(struct list_head *bridge_list) | 193 | void fpga_bridges_put(struct list_head *bridge_list) |
198 | { | 194 | { |
199 | struct fpga_bridge *bridge; | 195 | struct fpga_bridge *bridge, *next; |
200 | struct list_head *node, *next; | ||
201 | unsigned long flags; | 196 | unsigned long flags; |
202 | 197 | ||
203 | list_for_each_safe(node, next, bridge_list) { | 198 | list_for_each_entry_safe(bridge, next, bridge_list, node) { |
204 | bridge = list_entry(node, struct fpga_bridge, node); | ||
205 | |||
206 | fpga_bridge_put(bridge); | 199 | fpga_bridge_put(bridge); |
207 | 200 | ||
208 | spin_lock_irqsave(&bridge_list_lock, flags); | 201 | spin_lock_irqsave(&bridge_list_lock, flags); |
diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 86d2cb203533..188ffefa3cc3 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c | |||
@@ -361,7 +361,7 @@ static struct attribute *fpga_mgr_attrs[] = { | |||
361 | }; | 361 | }; |
362 | ATTRIBUTE_GROUPS(fpga_mgr); | 362 | ATTRIBUTE_GROUPS(fpga_mgr); |
363 | 363 | ||
364 | struct fpga_manager *__fpga_mgr_get(struct device *dev) | 364 | static struct fpga_manager *__fpga_mgr_get(struct device *dev) |
365 | { | 365 | { |
366 | struct fpga_manager *mgr; | 366 | struct fpga_manager *mgr; |
367 | int ret = -ENODEV; | 367 | int ret = -ENODEV; |
diff --git a/drivers/fpga/fpga-region.c b/drivers/fpga/fpga-region.c index 3222fdbad75a..3b6b2f4182a1 100644 --- a/drivers/fpga/fpga-region.c +++ b/drivers/fpga/fpga-region.c | |||
@@ -245,7 +245,8 @@ static int fpga_region_program_fpga(struct fpga_region *region, | |||
245 | mgr = fpga_region_get_manager(region); | 245 | mgr = fpga_region_get_manager(region); |
246 | if (IS_ERR(mgr)) { | 246 | if (IS_ERR(mgr)) { |
247 | pr_err("failed to get fpga region manager\n"); | 247 | pr_err("failed to get fpga region manager\n"); |
248 | return PTR_ERR(mgr); | 248 | ret = PTR_ERR(mgr); |
249 | goto err_put_region; | ||
249 | } | 250 | } |
250 | 251 | ||
251 | ret = fpga_region_get_bridges(region, overlay); | 252 | ret = fpga_region_get_bridges(region, overlay); |
@@ -281,6 +282,7 @@ err_put_br: | |||
281 | fpga_bridges_put(®ion->bridge_list); | 282 | fpga_bridges_put(®ion->bridge_list); |
282 | err_put_mgr: | 283 | err_put_mgr: |
283 | fpga_mgr_put(mgr); | 284 | fpga_mgr_put(mgr); |
285 | err_put_region: | ||
284 | fpga_region_put(region); | 286 | fpga_region_put(region); |
285 | 287 | ||
286 | return ret; | 288 | return ret; |
@@ -337,8 +339,9 @@ static int child_regions_with_firmware(struct device_node *overlay) | |||
337 | * The overlay must add either firmware-name or external-fpga-config property | 339 | * The overlay must add either firmware-name or external-fpga-config property |
338 | * to the FPGA Region. | 340 | * to the FPGA Region. |
339 | * | 341 | * |
340 | * firmware-name : program the FPGA | 342 | * firmware-name : program the FPGA |
341 | * external-fpga-config : FPGA is already programmed | 343 | * external-fpga-config : FPGA is already programmed |
344 | * encrypted-fpga-config : FPGA bitstream is encrypted | ||
342 | * | 345 | * |
343 | * The overlay can add other FPGA regions, but child FPGA regions cannot have a | 346 | * The overlay can add other FPGA regions, but child FPGA regions cannot have a |
344 | * firmware-name property since those regions don't exist yet. | 347 | * firmware-name property since those regions don't exist yet. |
@@ -373,6 +376,9 @@ static int fpga_region_notify_pre_apply(struct fpga_region *region, | |||
373 | if (of_property_read_bool(nd->overlay, "external-fpga-config")) | 376 | if (of_property_read_bool(nd->overlay, "external-fpga-config")) |
374 | info->flags |= FPGA_MGR_EXTERNAL_CONFIG; | 377 | info->flags |= FPGA_MGR_EXTERNAL_CONFIG; |
375 | 378 | ||
379 | if (of_property_read_bool(nd->overlay, "encrypted-fpga-config")) | ||
380 | info->flags |= FPGA_MGR_ENCRYPTED_BITSTREAM; | ||
381 | |||
376 | of_property_read_string(nd->overlay, "firmware-name", &firmware_name); | 382 | of_property_read_string(nd->overlay, "firmware-name", &firmware_name); |
377 | 383 | ||
378 | of_property_read_u32(nd->overlay, "region-unfreeze-timeout-us", | 384 | of_property_read_u32(nd->overlay, "region-unfreeze-timeout-us", |
@@ -381,6 +387,9 @@ static int fpga_region_notify_pre_apply(struct fpga_region *region, | |||
381 | of_property_read_u32(nd->overlay, "region-freeze-timeout-us", | 387 | of_property_read_u32(nd->overlay, "region-freeze-timeout-us", |
382 | &info->disable_timeout_us); | 388 | &info->disable_timeout_us); |
383 | 389 | ||
390 | of_property_read_u32(nd->overlay, "config-complete-timeout-us", | ||
391 | &info->config_complete_timeout_us); | ||
392 | |||
384 | /* If FPGA was externally programmed, don't specify firmware */ | 393 | /* If FPGA was externally programmed, don't specify firmware */ |
385 | if ((info->flags & FPGA_MGR_EXTERNAL_CONFIG) && firmware_name) { | 394 | if ((info->flags & FPGA_MGR_EXTERNAL_CONFIG) && firmware_name) { |
386 | pr_err("error: specified firmware and external-fpga-config"); | 395 | pr_err("error: specified firmware and external-fpga-config"); |
diff --git a/drivers/fpga/ice40-spi.c b/drivers/fpga/ice40-spi.c new file mode 100644 index 000000000000..7fca82023062 --- /dev/null +++ b/drivers/fpga/ice40-spi.c | |||
@@ -0,0 +1,207 @@ | |||
1 | /* | ||
2 | * FPGA Manager Driver for Lattice iCE40. | ||
3 | * | ||
4 | * Copyright (c) 2016 Joel Holdsworth | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | * | ||
10 | * This driver adds support to the FPGA manager for configuring the SRAM of | ||
11 | * Lattice iCE40 FPGAs through slave SPI. | ||
12 | */ | ||
13 | |||
14 | #include <linux/fpga/fpga-mgr.h> | ||
15 | #include <linux/gpio/consumer.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/of_gpio.h> | ||
18 | #include <linux/spi/spi.h> | ||
19 | #include <linux/stringify.h> | ||
20 | |||
21 | #define ICE40_SPI_MAX_SPEED 25000000 /* Hz */ | ||
22 | #define ICE40_SPI_MIN_SPEED 1000000 /* Hz */ | ||
23 | |||
24 | #define ICE40_SPI_RESET_DELAY 1 /* us (>200ns) */ | ||
25 | #define ICE40_SPI_HOUSEKEEPING_DELAY 1200 /* us */ | ||
26 | |||
27 | #define ICE40_SPI_NUM_ACTIVATION_BYTES DIV_ROUND_UP(49, 8) | ||
28 | |||
29 | struct ice40_fpga_priv { | ||
30 | struct spi_device *dev; | ||
31 | struct gpio_desc *reset; | ||
32 | struct gpio_desc *cdone; | ||
33 | }; | ||
34 | |||
35 | static enum fpga_mgr_states ice40_fpga_ops_state(struct fpga_manager *mgr) | ||
36 | { | ||
37 | struct ice40_fpga_priv *priv = mgr->priv; | ||
38 | |||
39 | return gpiod_get_value(priv->cdone) ? FPGA_MGR_STATE_OPERATING : | ||
40 | FPGA_MGR_STATE_UNKNOWN; | ||
41 | } | ||
42 | |||
43 | static int ice40_fpga_ops_write_init(struct fpga_manager *mgr, | ||
44 | struct fpga_image_info *info, | ||
45 | const char *buf, size_t count) | ||
46 | { | ||
47 | struct ice40_fpga_priv *priv = mgr->priv; | ||
48 | struct spi_device *dev = priv->dev; | ||
49 | struct spi_message message; | ||
50 | struct spi_transfer assert_cs_then_reset_delay = { | ||
51 | .cs_change = 1, | ||
52 | .delay_usecs = ICE40_SPI_RESET_DELAY | ||
53 | }; | ||
54 | struct spi_transfer housekeeping_delay_then_release_cs = { | ||
55 | .delay_usecs = ICE40_SPI_HOUSEKEEPING_DELAY | ||
56 | }; | ||
57 | int ret; | ||
58 | |||
59 | if ((info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { | ||
60 | dev_err(&dev->dev, | ||
61 | "Partial reconfiguration is not supported\n"); | ||
62 | return -ENOTSUPP; | ||
63 | } | ||
64 | |||
65 | /* Lock the bus, assert CRESET_B and SS_B and delay >200ns */ | ||
66 | spi_bus_lock(dev->master); | ||
67 | |||
68 | gpiod_set_value(priv->reset, 1); | ||
69 | |||
70 | spi_message_init(&message); | ||
71 | spi_message_add_tail(&assert_cs_then_reset_delay, &message); | ||
72 | ret = spi_sync_locked(dev, &message); | ||
73 | |||
74 | /* Come out of reset */ | ||
75 | gpiod_set_value(priv->reset, 0); | ||
76 | |||
77 | /* Abort if the chip-select failed */ | ||
78 | if (ret) | ||
79 | goto fail; | ||
80 | |||
81 | /* Check CDONE is de-asserted i.e. the FPGA is reset */ | ||
82 | if (gpiod_get_value(priv->cdone)) { | ||
83 | dev_err(&dev->dev, "Device reset failed, CDONE is asserted\n"); | ||
84 | ret = -EIO; | ||
85 | goto fail; | ||
86 | } | ||
87 | |||
88 | /* Wait for the housekeeping to complete, and release SS_B */ | ||
89 | spi_message_init(&message); | ||
90 | spi_message_add_tail(&housekeeping_delay_then_release_cs, &message); | ||
91 | ret = spi_sync_locked(dev, &message); | ||
92 | |||
93 | fail: | ||
94 | spi_bus_unlock(dev->master); | ||
95 | |||
96 | return ret; | ||
97 | } | ||
98 | |||
99 | static int ice40_fpga_ops_write(struct fpga_manager *mgr, | ||
100 | const char *buf, size_t count) | ||
101 | { | ||
102 | struct ice40_fpga_priv *priv = mgr->priv; | ||
103 | |||
104 | return spi_write(priv->dev, buf, count); | ||
105 | } | ||
106 | |||
107 | static int ice40_fpga_ops_write_complete(struct fpga_manager *mgr, | ||
108 | struct fpga_image_info *info) | ||
109 | { | ||
110 | struct ice40_fpga_priv *priv = mgr->priv; | ||
111 | struct spi_device *dev = priv->dev; | ||
112 | const u8 padding[ICE40_SPI_NUM_ACTIVATION_BYTES] = {0}; | ||
113 | |||
114 | /* Check CDONE is asserted */ | ||
115 | if (!gpiod_get_value(priv->cdone)) { | ||
116 | dev_err(&dev->dev, | ||
117 | "CDONE was not asserted after firmware transfer\n"); | ||
118 | return -EIO; | ||
119 | } | ||
120 | |||
121 | /* Send of zero-padding to activate the firmware */ | ||
122 | return spi_write(dev, padding, sizeof(padding)); | ||
123 | } | ||
124 | |||
125 | static const struct fpga_manager_ops ice40_fpga_ops = { | ||
126 | .state = ice40_fpga_ops_state, | ||
127 | .write_init = ice40_fpga_ops_write_init, | ||
128 | .write = ice40_fpga_ops_write, | ||
129 | .write_complete = ice40_fpga_ops_write_complete, | ||
130 | }; | ||
131 | |||
132 | static int ice40_fpga_probe(struct spi_device *spi) | ||
133 | { | ||
134 | struct device *dev = &spi->dev; | ||
135 | struct ice40_fpga_priv *priv; | ||
136 | int ret; | ||
137 | |||
138 | priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); | ||
139 | if (!priv) | ||
140 | return -ENOMEM; | ||
141 | |||
142 | priv->dev = spi; | ||
143 | |||
144 | /* Check board setup data. */ | ||
145 | if (spi->max_speed_hz > ICE40_SPI_MAX_SPEED) { | ||
146 | dev_err(dev, "SPI speed is too high, maximum speed is " | ||
147 | __stringify(ICE40_SPI_MAX_SPEED) "\n"); | ||
148 | return -EINVAL; | ||
149 | } | ||
150 | |||
151 | if (spi->max_speed_hz < ICE40_SPI_MIN_SPEED) { | ||
152 | dev_err(dev, "SPI speed is too low, minimum speed is " | ||
153 | __stringify(ICE40_SPI_MIN_SPEED) "\n"); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | if (spi->mode & SPI_CPHA) { | ||
158 | dev_err(dev, "Bad SPI mode, CPHA not supported\n"); | ||
159 | return -EINVAL; | ||
160 | } | ||
161 | |||
162 | /* Set up the GPIOs */ | ||
163 | priv->cdone = devm_gpiod_get(dev, "cdone", GPIOD_IN); | ||
164 | if (IS_ERR(priv->cdone)) { | ||
165 | ret = PTR_ERR(priv->cdone); | ||
166 | dev_err(dev, "Failed to get CDONE GPIO: %d\n", ret); | ||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); | ||
171 | if (IS_ERR(priv->reset)) { | ||
172 | ret = PTR_ERR(priv->reset); | ||
173 | dev_err(dev, "Failed to get CRESET_B GPIO: %d\n", ret); | ||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | /* Register with the FPGA manager */ | ||
178 | return fpga_mgr_register(dev, "Lattice iCE40 FPGA Manager", | ||
179 | &ice40_fpga_ops, priv); | ||
180 | } | ||
181 | |||
182 | static int ice40_fpga_remove(struct spi_device *spi) | ||
183 | { | ||
184 | fpga_mgr_unregister(&spi->dev); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static const struct of_device_id ice40_fpga_of_match[] = { | ||
189 | { .compatible = "lattice,ice40-fpga-mgr", }, | ||
190 | {}, | ||
191 | }; | ||
192 | MODULE_DEVICE_TABLE(of, ice40_fpga_of_match); | ||
193 | |||
194 | static struct spi_driver ice40_fpga_driver = { | ||
195 | .probe = ice40_fpga_probe, | ||
196 | .remove = ice40_fpga_remove, | ||
197 | .driver = { | ||
198 | .name = "ice40spi", | ||
199 | .of_match_table = of_match_ptr(ice40_fpga_of_match), | ||
200 | }, | ||
201 | }; | ||
202 | |||
203 | module_spi_driver(ice40_fpga_driver); | ||
204 | |||
205 | MODULE_AUTHOR("Joel Holdsworth <joel@airwebreathe.org.uk>"); | ||
206 | MODULE_DESCRIPTION("Lattice iCE40 FPGA Manager"); | ||
207 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/fpga/ts73xx-fpga.c b/drivers/fpga/ts73xx-fpga.c new file mode 100644 index 000000000000..f6a96b42e2ca --- /dev/null +++ b/drivers/fpga/ts73xx-fpga.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * Technologic Systems TS-73xx SBC FPGA loader | ||
3 | * | ||
4 | * Copyright (C) 2016 Florian Fainelli <f.fainelli@gmail.com> | ||
5 | * | ||
6 | * FPGA Manager Driver for the on-board Altera Cyclone II FPGA found on | ||
7 | * TS-7300, heavily based on load_fpga.c in their vendor tree. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/delay.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/iopoll.h> | ||
25 | #include <linux/fpga/fpga-mgr.h> | ||
26 | |||
27 | #define TS73XX_FPGA_DATA_REG 0 | ||
28 | #define TS73XX_FPGA_CONFIG_REG 1 | ||
29 | |||
30 | #define TS73XX_FPGA_WRITE_DONE 0x1 | ||
31 | #define TS73XX_FPGA_WRITE_DONE_TIMEOUT 1000 /* us */ | ||
32 | #define TS73XX_FPGA_RESET 0x2 | ||
33 | #define TS73XX_FPGA_RESET_LOW_DELAY 30 /* us */ | ||
34 | #define TS73XX_FPGA_RESET_HIGH_DELAY 80 /* us */ | ||
35 | #define TS73XX_FPGA_LOAD_OK 0x4 | ||
36 | #define TS73XX_FPGA_CONFIG_LOAD 0x8 | ||
37 | |||
38 | struct ts73xx_fpga_priv { | ||
39 | void __iomem *io_base; | ||
40 | struct device *dev; | ||
41 | }; | ||
42 | |||
43 | static enum fpga_mgr_states ts73xx_fpga_state(struct fpga_manager *mgr) | ||
44 | { | ||
45 | return FPGA_MGR_STATE_UNKNOWN; | ||
46 | } | ||
47 | |||
48 | static int ts73xx_fpga_write_init(struct fpga_manager *mgr, | ||
49 | struct fpga_image_info *info, | ||
50 | const char *buf, size_t count) | ||
51 | { | ||
52 | struct ts73xx_fpga_priv *priv = mgr->priv; | ||
53 | |||
54 | /* Reset the FPGA */ | ||
55 | writeb(0, priv->io_base + TS73XX_FPGA_CONFIG_REG); | ||
56 | udelay(TS73XX_FPGA_RESET_LOW_DELAY); | ||
57 | writeb(TS73XX_FPGA_RESET, priv->io_base + TS73XX_FPGA_CONFIG_REG); | ||
58 | udelay(TS73XX_FPGA_RESET_HIGH_DELAY); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static int ts73xx_fpga_write(struct fpga_manager *mgr, const char *buf, | ||
64 | size_t count) | ||
65 | { | ||
66 | struct ts73xx_fpga_priv *priv = mgr->priv; | ||
67 | size_t i = 0; | ||
68 | int ret; | ||
69 | u8 reg; | ||
70 | |||
71 | while (count--) { | ||
72 | ret = readb_poll_timeout(priv->io_base + TS73XX_FPGA_CONFIG_REG, | ||
73 | reg, !(reg & TS73XX_FPGA_WRITE_DONE), | ||
74 | 1, TS73XX_FPGA_WRITE_DONE_TIMEOUT); | ||
75 | if (ret < 0) | ||
76 | return ret; | ||
77 | |||
78 | writeb(buf[i], priv->io_base + TS73XX_FPGA_DATA_REG); | ||
79 | i++; | ||
80 | } | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int ts73xx_fpga_write_complete(struct fpga_manager *mgr, | ||
86 | struct fpga_image_info *info) | ||
87 | { | ||
88 | struct ts73xx_fpga_priv *priv = mgr->priv; | ||
89 | u8 reg; | ||
90 | |||
91 | usleep_range(1000, 2000); | ||
92 | reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG); | ||
93 | reg |= TS73XX_FPGA_CONFIG_LOAD; | ||
94 | writeb(reg, priv->io_base + TS73XX_FPGA_CONFIG_REG); | ||
95 | |||
96 | usleep_range(1000, 2000); | ||
97 | reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG); | ||
98 | reg &= ~TS73XX_FPGA_CONFIG_LOAD; | ||
99 | writeb(reg, priv->io_base + TS73XX_FPGA_CONFIG_REG); | ||
100 | |||
101 | reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG); | ||
102 | if ((reg & TS73XX_FPGA_LOAD_OK) != TS73XX_FPGA_LOAD_OK) | ||
103 | return -ETIMEDOUT; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static const struct fpga_manager_ops ts73xx_fpga_ops = { | ||
109 | .state = ts73xx_fpga_state, | ||
110 | .write_init = ts73xx_fpga_write_init, | ||
111 | .write = ts73xx_fpga_write, | ||
112 | .write_complete = ts73xx_fpga_write_complete, | ||
113 | }; | ||
114 | |||
115 | static int ts73xx_fpga_probe(struct platform_device *pdev) | ||
116 | { | ||
117 | struct device *kdev = &pdev->dev; | ||
118 | struct ts73xx_fpga_priv *priv; | ||
119 | struct resource *res; | ||
120 | |||
121 | priv = devm_kzalloc(kdev, sizeof(*priv), GFP_KERNEL); | ||
122 | if (!priv) | ||
123 | return -ENOMEM; | ||
124 | |||
125 | priv->dev = kdev; | ||
126 | |||
127 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
128 | priv->io_base = devm_ioremap_resource(kdev, res); | ||
129 | if (IS_ERR(priv->io_base)) { | ||
130 | dev_err(kdev, "unable to remap registers\n"); | ||
131 | return PTR_ERR(priv->io_base); | ||
132 | } | ||
133 | |||
134 | return fpga_mgr_register(kdev, "TS-73xx FPGA Manager", | ||
135 | &ts73xx_fpga_ops, priv); | ||
136 | } | ||
137 | |||
138 | static int ts73xx_fpga_remove(struct platform_device *pdev) | ||
139 | { | ||
140 | fpga_mgr_unregister(&pdev->dev); | ||
141 | |||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static struct platform_driver ts73xx_fpga_driver = { | ||
146 | .driver = { | ||
147 | .name = "ts73xx-fpga-mgr", | ||
148 | }, | ||
149 | .probe = ts73xx_fpga_probe, | ||
150 | .remove = ts73xx_fpga_remove, | ||
151 | }; | ||
152 | module_platform_driver(ts73xx_fpga_driver); | ||
153 | |||
154 | MODULE_AUTHOR("Florian Fainelli <f.fainelli@gmail.com>"); | ||
155 | MODULE_DESCRIPTION("TS-73xx FPGA Manager driver"); | ||
156 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c new file mode 100644 index 000000000000..e359930bebc8 --- /dev/null +++ b/drivers/fpga/xilinx-pr-decoupler.c | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2017, National Instruments Corp. | ||
3 | * Copyright (c) 2017, Xilix Inc | ||
4 | * | ||
5 | * FPGA Bridge Driver for the Xilinx LogiCORE Partial Reconfiguration | ||
6 | * Decoupler IP Core. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; version 2 of the License. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/clk.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/of_device.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/fpga/fpga-bridge.h> | ||
24 | |||
25 | #define CTRL_CMD_DECOUPLE BIT(0) | ||
26 | #define CTRL_CMD_COUPLE 0 | ||
27 | #define CTRL_OFFSET 0 | ||
28 | |||
29 | struct xlnx_pr_decoupler_data { | ||
30 | void __iomem *io_base; | ||
31 | struct clk *clk; | ||
32 | }; | ||
33 | |||
34 | static inline void xlnx_pr_decoupler_write(struct xlnx_pr_decoupler_data *d, | ||
35 | u32 offset, u32 val) | ||
36 | { | ||
37 | writel(val, d->io_base + offset); | ||
38 | } | ||
39 | |||
40 | static inline u32 xlnx_pr_decouple_read(const struct xlnx_pr_decoupler_data *d, | ||
41 | u32 offset) | ||
42 | { | ||
43 | return readl(d->io_base + offset); | ||
44 | } | ||
45 | |||
46 | static int xlnx_pr_decoupler_enable_set(struct fpga_bridge *bridge, bool enable) | ||
47 | { | ||
48 | int err; | ||
49 | struct xlnx_pr_decoupler_data *priv = bridge->priv; | ||
50 | |||
51 | err = clk_enable(priv->clk); | ||
52 | if (err) | ||
53 | return err; | ||
54 | |||
55 | if (enable) | ||
56 | xlnx_pr_decoupler_write(priv, CTRL_OFFSET, CTRL_CMD_COUPLE); | ||
57 | else | ||
58 | xlnx_pr_decoupler_write(priv, CTRL_OFFSET, CTRL_CMD_DECOUPLE); | ||
59 | |||
60 | clk_disable(priv->clk); | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int xlnx_pr_decoupler_enable_show(struct fpga_bridge *bridge) | ||
66 | { | ||
67 | const struct xlnx_pr_decoupler_data *priv = bridge->priv; | ||
68 | u32 status; | ||
69 | int err; | ||
70 | |||
71 | err = clk_enable(priv->clk); | ||
72 | if (err) | ||
73 | return err; | ||
74 | |||
75 | status = readl(priv->io_base); | ||
76 | |||
77 | clk_disable(priv->clk); | ||
78 | |||
79 | return !status; | ||
80 | } | ||
81 | |||
82 | static struct fpga_bridge_ops xlnx_pr_decoupler_br_ops = { | ||
83 | .enable_set = xlnx_pr_decoupler_enable_set, | ||
84 | .enable_show = xlnx_pr_decoupler_enable_show, | ||
85 | }; | ||
86 | |||
87 | static const struct of_device_id xlnx_pr_decoupler_of_match[] = { | ||
88 | { .compatible = "xlnx,pr-decoupler-1.00", }, | ||
89 | { .compatible = "xlnx,pr-decoupler", }, | ||
90 | {}, | ||
91 | }; | ||
92 | MODULE_DEVICE_TABLE(of, xlnx_pr_decoupler_of_match); | ||
93 | |||
94 | static int xlnx_pr_decoupler_probe(struct platform_device *pdev) | ||
95 | { | ||
96 | struct xlnx_pr_decoupler_data *priv; | ||
97 | int err; | ||
98 | struct resource *res; | ||
99 | |||
100 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||
101 | if (!priv) | ||
102 | return -ENOMEM; | ||
103 | |||
104 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
105 | priv->io_base = devm_ioremap_resource(&pdev->dev, res); | ||
106 | if (IS_ERR(priv->io_base)) | ||
107 | return PTR_ERR(priv->io_base); | ||
108 | |||
109 | priv->clk = devm_clk_get(&pdev->dev, "aclk"); | ||
110 | if (IS_ERR(priv->clk)) { | ||
111 | dev_err(&pdev->dev, "input clock not found\n"); | ||
112 | return PTR_ERR(priv->clk); | ||
113 | } | ||
114 | |||
115 | err = clk_prepare_enable(priv->clk); | ||
116 | if (err) { | ||
117 | dev_err(&pdev->dev, "unable to enable clock\n"); | ||
118 | return err; | ||
119 | } | ||
120 | |||
121 | clk_disable(priv->clk); | ||
122 | |||
123 | err = fpga_bridge_register(&pdev->dev, "Xilinx PR Decoupler", | ||
124 | &xlnx_pr_decoupler_br_ops, priv); | ||
125 | |||
126 | if (err) { | ||
127 | dev_err(&pdev->dev, "unable to register Xilinx PR Decoupler"); | ||
128 | clk_unprepare(priv->clk); | ||
129 | return err; | ||
130 | } | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static int xlnx_pr_decoupler_remove(struct platform_device *pdev) | ||
136 | { | ||
137 | struct fpga_bridge *bridge = platform_get_drvdata(pdev); | ||
138 | struct xlnx_pr_decoupler_data *p = bridge->priv; | ||
139 | |||
140 | fpga_bridge_unregister(&pdev->dev); | ||
141 | |||
142 | clk_unprepare(p->clk); | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | static struct platform_driver xlnx_pr_decoupler_driver = { | ||
148 | .probe = xlnx_pr_decoupler_probe, | ||
149 | .remove = xlnx_pr_decoupler_remove, | ||
150 | .driver = { | ||
151 | .name = "xlnx_pr_decoupler", | ||
152 | .of_match_table = of_match_ptr(xlnx_pr_decoupler_of_match), | ||
153 | }, | ||
154 | }; | ||
155 | |||
156 | module_platform_driver(xlnx_pr_decoupler_driver); | ||
157 | |||
158 | MODULE_DESCRIPTION("Xilinx Partial Reconfiguration Decoupler"); | ||
159 | MODULE_AUTHOR("Moritz Fischer <mdf@kernel.org>"); | ||
160 | MODULE_AUTHOR("Michal Simek <michal.simek@xilinx.com>"); | ||
161 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c new file mode 100644 index 000000000000..9b62a4c2a3df --- /dev/null +++ b/drivers/fpga/xilinx-spi.c | |||
@@ -0,0 +1,198 @@ | |||
1 | /* | ||
2 | * Xilinx Spartan6 Slave Serial SPI Driver | ||
3 | * | ||
4 | * Copyright (C) 2017 DENX Software Engineering | ||
5 | * | ||
6 | * Anatolij Gustschin <agust@denx.de> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * Manage Xilinx FPGA firmware that is loaded over SPI using | ||
13 | * the slave serial configuration interface. | ||
14 | */ | ||
15 | |||
16 | #include <linux/delay.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/fpga/fpga-mgr.h> | ||
19 | #include <linux/gpio/consumer.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/mod_devicetable.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/spi/spi.h> | ||
24 | #include <linux/sizes.h> | ||
25 | |||
26 | struct xilinx_spi_conf { | ||
27 | struct spi_device *spi; | ||
28 | struct gpio_desc *prog_b; | ||
29 | struct gpio_desc *done; | ||
30 | }; | ||
31 | |||
32 | static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr) | ||
33 | { | ||
34 | struct xilinx_spi_conf *conf = mgr->priv; | ||
35 | |||
36 | if (!gpiod_get_value(conf->done)) | ||
37 | return FPGA_MGR_STATE_RESET; | ||
38 | |||
39 | return FPGA_MGR_STATE_UNKNOWN; | ||
40 | } | ||
41 | |||
42 | static int xilinx_spi_write_init(struct fpga_manager *mgr, | ||
43 | struct fpga_image_info *info, | ||
44 | const char *buf, size_t count) | ||
45 | { | ||
46 | struct xilinx_spi_conf *conf = mgr->priv; | ||
47 | const size_t prog_latency_7500us = 7500; | ||
48 | const size_t prog_pulse_1us = 1; | ||
49 | |||
50 | if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) { | ||
51 | dev_err(&mgr->dev, "Partial reconfiguration not supported.\n"); | ||
52 | return -EINVAL; | ||
53 | } | ||
54 | |||
55 | gpiod_set_value(conf->prog_b, 1); | ||
56 | |||
57 | udelay(prog_pulse_1us); /* min is 500 ns */ | ||
58 | |||
59 | gpiod_set_value(conf->prog_b, 0); | ||
60 | |||
61 | if (gpiod_get_value(conf->done)) { | ||
62 | dev_err(&mgr->dev, "Unexpected DONE pin state...\n"); | ||
63 | return -EIO; | ||
64 | } | ||
65 | |||
66 | /* program latency */ | ||
67 | usleep_range(prog_latency_7500us, prog_latency_7500us + 100); | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int xilinx_spi_write(struct fpga_manager *mgr, const char *buf, | ||
72 | size_t count) | ||
73 | { | ||
74 | struct xilinx_spi_conf *conf = mgr->priv; | ||
75 | const char *fw_data = buf; | ||
76 | const char *fw_data_end = fw_data + count; | ||
77 | |||
78 | while (fw_data < fw_data_end) { | ||
79 | size_t remaining, stride; | ||
80 | int ret; | ||
81 | |||
82 | remaining = fw_data_end - fw_data; | ||
83 | stride = min_t(size_t, remaining, SZ_4K); | ||
84 | |||
85 | ret = spi_write(conf->spi, fw_data, stride); | ||
86 | if (ret) { | ||
87 | dev_err(&mgr->dev, "SPI error in firmware write: %d\n", | ||
88 | ret); | ||
89 | return ret; | ||
90 | } | ||
91 | fw_data += stride; | ||
92 | } | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int xilinx_spi_apply_cclk_cycles(struct xilinx_spi_conf *conf) | ||
98 | { | ||
99 | struct spi_device *spi = conf->spi; | ||
100 | const u8 din_data[1] = { 0xff }; | ||
101 | int ret; | ||
102 | |||
103 | ret = spi_write(conf->spi, din_data, sizeof(din_data)); | ||
104 | if (ret) | ||
105 | dev_err(&spi->dev, "applying CCLK cycles failed: %d\n", ret); | ||
106 | |||
107 | return ret; | ||
108 | } | ||
109 | |||
110 | static int xilinx_spi_write_complete(struct fpga_manager *mgr, | ||
111 | struct fpga_image_info *info) | ||
112 | { | ||
113 | struct xilinx_spi_conf *conf = mgr->priv; | ||
114 | unsigned long timeout; | ||
115 | int ret; | ||
116 | |||
117 | if (gpiod_get_value(conf->done)) | ||
118 | return xilinx_spi_apply_cclk_cycles(conf); | ||
119 | |||
120 | timeout = jiffies + usecs_to_jiffies(info->config_complete_timeout_us); | ||
121 | |||
122 | while (time_before(jiffies, timeout)) { | ||
123 | |||
124 | ret = xilinx_spi_apply_cclk_cycles(conf); | ||
125 | if (ret) | ||
126 | return ret; | ||
127 | |||
128 | if (gpiod_get_value(conf->done)) | ||
129 | return xilinx_spi_apply_cclk_cycles(conf); | ||
130 | } | ||
131 | |||
132 | dev_err(&mgr->dev, "Timeout after config data transfer.\n"); | ||
133 | return -ETIMEDOUT; | ||
134 | } | ||
135 | |||
136 | static const struct fpga_manager_ops xilinx_spi_ops = { | ||
137 | .state = xilinx_spi_state, | ||
138 | .write_init = xilinx_spi_write_init, | ||
139 | .write = xilinx_spi_write, | ||
140 | .write_complete = xilinx_spi_write_complete, | ||
141 | }; | ||
142 | |||
143 | static int xilinx_spi_probe(struct spi_device *spi) | ||
144 | { | ||
145 | struct xilinx_spi_conf *conf; | ||
146 | |||
147 | conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL); | ||
148 | if (!conf) | ||
149 | return -ENOMEM; | ||
150 | |||
151 | conf->spi = spi; | ||
152 | |||
153 | /* PROGRAM_B is active low */ | ||
154 | conf->prog_b = devm_gpiod_get(&spi->dev, "prog_b", GPIOD_OUT_LOW); | ||
155 | if (IS_ERR(conf->prog_b)) { | ||
156 | dev_err(&spi->dev, "Failed to get PROGRAM_B gpio: %ld\n", | ||
157 | PTR_ERR(conf->prog_b)); | ||
158 | return PTR_ERR(conf->prog_b); | ||
159 | } | ||
160 | |||
161 | conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN); | ||
162 | if (IS_ERR(conf->done)) { | ||
163 | dev_err(&spi->dev, "Failed to get DONE gpio: %ld\n", | ||
164 | PTR_ERR(conf->done)); | ||
165 | return PTR_ERR(conf->done); | ||
166 | } | ||
167 | |||
168 | return fpga_mgr_register(&spi->dev, "Xilinx Slave Serial FPGA Manager", | ||
169 | &xilinx_spi_ops, conf); | ||
170 | } | ||
171 | |||
172 | static int xilinx_spi_remove(struct spi_device *spi) | ||
173 | { | ||
174 | fpga_mgr_unregister(&spi->dev); | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static const struct of_device_id xlnx_spi_of_match[] = { | ||
180 | { .compatible = "xlnx,fpga-slave-serial", }, | ||
181 | {} | ||
182 | }; | ||
183 | MODULE_DEVICE_TABLE(of, xlnx_spi_of_match); | ||
184 | |||
185 | static struct spi_driver xilinx_slave_spi_driver = { | ||
186 | .driver = { | ||
187 | .name = "xlnx-slave-spi", | ||
188 | .of_match_table = of_match_ptr(xlnx_spi_of_match), | ||
189 | }, | ||
190 | .probe = xilinx_spi_probe, | ||
191 | .remove = xilinx_spi_remove, | ||
192 | }; | ||
193 | |||
194 | module_spi_driver(xilinx_slave_spi_driver) | ||
195 | |||
196 | MODULE_LICENSE("GPL v2"); | ||
197 | MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>"); | ||
198 | MODULE_DESCRIPTION("Load Xilinx FPGA firmware over SPI"); | ||
diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c index 34cb98139442..70b15b303471 100644 --- a/drivers/fpga/zynq-fpga.c +++ b/drivers/fpga/zynq-fpga.c | |||
@@ -72,6 +72,10 @@ | |||
72 | #define CTRL_PCAP_PR_MASK BIT(27) | 72 | #define CTRL_PCAP_PR_MASK BIT(27) |
73 | /* Enable PCAP */ | 73 | /* Enable PCAP */ |
74 | #define CTRL_PCAP_MODE_MASK BIT(26) | 74 | #define CTRL_PCAP_MODE_MASK BIT(26) |
75 | /* Lower rate to allow decrypt on the fly */ | ||
76 | #define CTRL_PCAP_RATE_EN_MASK BIT(25) | ||
77 | /* System booted in secure mode */ | ||
78 | #define CTRL_SEC_EN_MASK BIT(7) | ||
75 | 79 | ||
76 | /* Miscellaneous Control Register bit definitions */ | 80 | /* Miscellaneous Control Register bit definitions */ |
77 | /* Internal PCAP loopback */ | 81 | /* Internal PCAP loopback */ |
@@ -266,6 +270,17 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, | |||
266 | if (err) | 270 | if (err) |
267 | return err; | 271 | return err; |
268 | 272 | ||
273 | /* check if bitstream is encrypted & and system's still secure */ | ||
274 | if (info->flags & FPGA_MGR_ENCRYPTED_BITSTREAM) { | ||
275 | ctrl = zynq_fpga_read(priv, CTRL_OFFSET); | ||
276 | if (!(ctrl & CTRL_SEC_EN_MASK)) { | ||
277 | dev_err(&mgr->dev, | ||
278 | "System not secure, can't use crypted bitstreams\n"); | ||
279 | err = -EINVAL; | ||
280 | goto out_err; | ||
281 | } | ||
282 | } | ||
283 | |||
269 | /* don't globally reset PL if we're doing partial reconfig */ | 284 | /* don't globally reset PL if we're doing partial reconfig */ |
270 | if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { | 285 | if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { |
271 | if (!zynq_fpga_has_sync(buf, count)) { | 286 | if (!zynq_fpga_has_sync(buf, count)) { |
@@ -337,12 +352,19 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, | |||
337 | 352 | ||
338 | /* set configuration register with following options: | 353 | /* set configuration register with following options: |
339 | * - enable PCAP interface | 354 | * - enable PCAP interface |
340 | * - set throughput for maximum speed | 355 | * - set throughput for maximum speed (if bistream not crypted) |
341 | * - set CPU in user mode | 356 | * - set CPU in user mode |
342 | */ | 357 | */ |
343 | ctrl = zynq_fpga_read(priv, CTRL_OFFSET); | 358 | ctrl = zynq_fpga_read(priv, CTRL_OFFSET); |
344 | zynq_fpga_write(priv, CTRL_OFFSET, | 359 | if (info->flags & FPGA_MGR_ENCRYPTED_BITSTREAM) |
345 | (CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK | ctrl)); | 360 | zynq_fpga_write(priv, CTRL_OFFSET, |
361 | (CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK | ||
362 | | CTRL_PCAP_RATE_EN_MASK | ctrl)); | ||
363 | else | ||
364 | zynq_fpga_write(priv, CTRL_OFFSET, | ||
365 | (CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK | ||
366 | | ctrl)); | ||
367 | |||
346 | 368 | ||
347 | /* We expect that the command queue is empty right now. */ | 369 | /* We expect that the command queue is empty right now. */ |
348 | status = zynq_fpga_read(priv, STATUS_OFFSET); | 370 | status = zynq_fpga_read(priv, STATUS_OFFSET); |
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 1d1fa7248d63..5db44139cef8 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c | |||
@@ -1035,18 +1035,14 @@ static int gpiochip_setup_dev(struct gpio_device *gdev) | |||
1035 | 1035 | ||
1036 | cdev_init(&gdev->chrdev, &gpio_fileops); | 1036 | cdev_init(&gdev->chrdev, &gpio_fileops); |
1037 | gdev->chrdev.owner = THIS_MODULE; | 1037 | gdev->chrdev.owner = THIS_MODULE; |
1038 | gdev->chrdev.kobj.parent = &gdev->dev.kobj; | ||
1039 | gdev->dev.devt = MKDEV(MAJOR(gpio_devt), gdev->id); | 1038 | gdev->dev.devt = MKDEV(MAJOR(gpio_devt), gdev->id); |
1040 | status = cdev_add(&gdev->chrdev, gdev->dev.devt, 1); | 1039 | |
1041 | if (status < 0) | 1040 | status = cdev_device_add(&gdev->chrdev, &gdev->dev); |
1042 | chip_warn(gdev->chip, "failed to add char device %d:%d\n", | ||
1043 | MAJOR(gpio_devt), gdev->id); | ||
1044 | else | ||
1045 | chip_dbg(gdev->chip, "added GPIO chardev (%d:%d)\n", | ||
1046 | MAJOR(gpio_devt), gdev->id); | ||
1047 | status = device_add(&gdev->dev); | ||
1048 | if (status) | 1041 | if (status) |
1049 | goto err_remove_chardev; | 1042 | return status; |
1043 | |||
1044 | chip_dbg(gdev->chip, "added GPIO chardev (%d:%d)\n", | ||
1045 | MAJOR(gpio_devt), gdev->id); | ||
1050 | 1046 | ||
1051 | status = gpiochip_sysfs_register(gdev); | 1047 | status = gpiochip_sysfs_register(gdev); |
1052 | if (status) | 1048 | if (status) |
@@ -1061,9 +1057,7 @@ static int gpiochip_setup_dev(struct gpio_device *gdev) | |||
1061 | return 0; | 1057 | return 0; |
1062 | 1058 | ||
1063 | err_remove_device: | 1059 | err_remove_device: |
1064 | device_del(&gdev->dev); | 1060 | cdev_device_del(&gdev->chrdev, &gdev->dev); |
1065 | err_remove_chardev: | ||
1066 | cdev_del(&gdev->chrdev); | ||
1067 | return status; | 1061 | return status; |
1068 | } | 1062 | } |
1069 | 1063 | ||
@@ -1347,8 +1341,7 @@ void gpiochip_remove(struct gpio_chip *chip) | |||
1347 | * be removed, else it will be dangling until the last user is | 1341 | * be removed, else it will be dangling until the last user is |
1348 | * gone. | 1342 | * gone. |
1349 | */ | 1343 | */ |
1350 | cdev_del(&gdev->chrdev); | 1344 | cdev_device_del(&gdev->chrdev, &gdev->dev); |
1351 | device_del(&gdev->dev); | ||
1352 | put_device(&gdev->dev); | 1345 | put_device(&gdev->dev); |
1353 | } | 1346 | } |
1354 | EXPORT_SYMBOL_GPL(gpiochip_remove); | 1347 | EXPORT_SYMBOL_GPL(gpiochip_remove); |
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 321b8833fa6f..736ac76d2a6a 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c | |||
@@ -333,7 +333,7 @@ static int create_gpadl_header(void *kbuffer, u32 size, | |||
333 | * Gpadl is u32 and we are using a pointer which could | 333 | * Gpadl is u32 and we are using a pointer which could |
334 | * be 64-bit | 334 | * be 64-bit |
335 | * This is governed by the guest/host protocol and | 335 | * This is governed by the guest/host protocol and |
336 | * so the hypervisor gurantees that this is ok. | 336 | * so the hypervisor guarantees that this is ok. |
337 | */ | 337 | */ |
338 | for (i = 0; i < pfncurr; i++) | 338 | for (i = 0; i < pfncurr; i++) |
339 | gpadl_body->pfn[i] = slow_virt_to_phys( | 339 | gpadl_body->pfn[i] = slow_virt_to_phys( |
@@ -380,7 +380,7 @@ nomem: | |||
380 | } | 380 | } |
381 | 381 | ||
382 | /* | 382 | /* |
383 | * vmbus_establish_gpadl - Estabish a GPADL for the specified buffer | 383 | * vmbus_establish_gpadl - Establish a GPADL for the specified buffer |
384 | * | 384 | * |
385 | * @channel: a channel | 385 | * @channel: a channel |
386 | * @kbuffer: from kmalloc or vmalloc | 386 | * @kbuffer: from kmalloc or vmalloc |
@@ -731,7 +731,7 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel, | |||
731 | /* Setup the descriptor */ | 731 | /* Setup the descriptor */ |
732 | desc.type = VM_PKT_DATA_USING_GPA_DIRECT; | 732 | desc.type = VM_PKT_DATA_USING_GPA_DIRECT; |
733 | desc.flags = flags; | 733 | desc.flags = flags; |
734 | desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */ | 734 | desc.dataoffset8 = descsize >> 3; /* in 8-bytes granularity */ |
735 | desc.length8 = (u16)(packetlen_aligned >> 3); | 735 | desc.length8 = (u16)(packetlen_aligned >> 3); |
736 | desc.transactionid = requestid; | 736 | desc.transactionid = requestid; |
737 | desc.rangecount = pagecount; | 737 | desc.rangecount = pagecount; |
@@ -792,7 +792,7 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, | |||
792 | /* Setup the descriptor */ | 792 | /* Setup the descriptor */ |
793 | desc->type = VM_PKT_DATA_USING_GPA_DIRECT; | 793 | desc->type = VM_PKT_DATA_USING_GPA_DIRECT; |
794 | desc->flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; | 794 | desc->flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; |
795 | desc->dataoffset8 = desc_size >> 3; /* in 8-bytes grandularity */ | 795 | desc->dataoffset8 = desc_size >> 3; /* in 8-bytes granularity */ |
796 | desc->length8 = (u16)(packetlen_aligned >> 3); | 796 | desc->length8 = (u16)(packetlen_aligned >> 3); |
797 | desc->transactionid = requestid; | 797 | desc->transactionid = requestid; |
798 | desc->rangecount = 1; | 798 | desc->rangecount = 1; |
@@ -842,7 +842,7 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel, | |||
842 | /* Setup the descriptor */ | 842 | /* Setup the descriptor */ |
843 | desc.type = VM_PKT_DATA_USING_GPA_DIRECT; | 843 | desc.type = VM_PKT_DATA_USING_GPA_DIRECT; |
844 | desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; | 844 | desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; |
845 | desc.dataoffset8 = descsize >> 3; /* in 8-bytes grandularity */ | 845 | desc.dataoffset8 = descsize >> 3; /* in 8-bytes granularity */ |
846 | desc.length8 = (u16)(packetlen_aligned >> 3); | 846 | desc.length8 = (u16)(packetlen_aligned >> 3); |
847 | desc.transactionid = requestid; | 847 | desc.transactionid = requestid; |
848 | desc.rangecount = 1; | 848 | desc.rangecount = 1; |
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index fbcb06352308..735f9363f2e4 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c | |||
@@ -1080,30 +1080,30 @@ static void vmbus_onversion_response( | |||
1080 | } | 1080 | } |
1081 | 1081 | ||
1082 | /* Channel message dispatch table */ | 1082 | /* Channel message dispatch table */ |
1083 | struct vmbus_channel_message_table_entry | 1083 | const struct vmbus_channel_message_table_entry |
1084 | channel_message_table[CHANNELMSG_COUNT] = { | 1084 | channel_message_table[CHANNELMSG_COUNT] = { |
1085 | {CHANNELMSG_INVALID, 0, NULL}, | 1085 | { CHANNELMSG_INVALID, 0, NULL }, |
1086 | {CHANNELMSG_OFFERCHANNEL, 0, vmbus_onoffer}, | 1086 | { CHANNELMSG_OFFERCHANNEL, 0, vmbus_onoffer }, |
1087 | {CHANNELMSG_RESCIND_CHANNELOFFER, 0, vmbus_onoffer_rescind}, | 1087 | { CHANNELMSG_RESCIND_CHANNELOFFER, 0, vmbus_onoffer_rescind }, |
1088 | {CHANNELMSG_REQUESTOFFERS, 0, NULL}, | 1088 | { CHANNELMSG_REQUESTOFFERS, 0, NULL }, |
1089 | {CHANNELMSG_ALLOFFERS_DELIVERED, 1, vmbus_onoffers_delivered}, | 1089 | { CHANNELMSG_ALLOFFERS_DELIVERED, 1, vmbus_onoffers_delivered }, |
1090 | {CHANNELMSG_OPENCHANNEL, 0, NULL}, | 1090 | { CHANNELMSG_OPENCHANNEL, 0, NULL }, |
1091 | {CHANNELMSG_OPENCHANNEL_RESULT, 1, vmbus_onopen_result}, | 1091 | { CHANNELMSG_OPENCHANNEL_RESULT, 1, vmbus_onopen_result }, |
1092 | {CHANNELMSG_CLOSECHANNEL, 0, NULL}, | 1092 | { CHANNELMSG_CLOSECHANNEL, 0, NULL }, |
1093 | {CHANNELMSG_GPADL_HEADER, 0, NULL}, | 1093 | { CHANNELMSG_GPADL_HEADER, 0, NULL }, |
1094 | {CHANNELMSG_GPADL_BODY, 0, NULL}, | 1094 | { CHANNELMSG_GPADL_BODY, 0, NULL }, |
1095 | {CHANNELMSG_GPADL_CREATED, 1, vmbus_ongpadl_created}, | 1095 | { CHANNELMSG_GPADL_CREATED, 1, vmbus_ongpadl_created }, |
1096 | {CHANNELMSG_GPADL_TEARDOWN, 0, NULL}, | 1096 | { CHANNELMSG_GPADL_TEARDOWN, 0, NULL }, |
1097 | {CHANNELMSG_GPADL_TORNDOWN, 1, vmbus_ongpadl_torndown}, | 1097 | { CHANNELMSG_GPADL_TORNDOWN, 1, vmbus_ongpadl_torndown }, |
1098 | {CHANNELMSG_RELID_RELEASED, 0, NULL}, | 1098 | { CHANNELMSG_RELID_RELEASED, 0, NULL }, |
1099 | {CHANNELMSG_INITIATE_CONTACT, 0, NULL}, | 1099 | { CHANNELMSG_INITIATE_CONTACT, 0, NULL }, |
1100 | {CHANNELMSG_VERSION_RESPONSE, 1, vmbus_onversion_response}, | 1100 | { CHANNELMSG_VERSION_RESPONSE, 1, vmbus_onversion_response }, |
1101 | {CHANNELMSG_UNLOAD, 0, NULL}, | 1101 | { CHANNELMSG_UNLOAD, 0, NULL }, |
1102 | {CHANNELMSG_UNLOAD_RESPONSE, 1, vmbus_unload_response}, | 1102 | { CHANNELMSG_UNLOAD_RESPONSE, 1, vmbus_unload_response }, |
1103 | {CHANNELMSG_18, 0, NULL}, | 1103 | { CHANNELMSG_18, 0, NULL }, |
1104 | {CHANNELMSG_19, 0, NULL}, | 1104 | { CHANNELMSG_19, 0, NULL }, |
1105 | {CHANNELMSG_20, 0, NULL}, | 1105 | { CHANNELMSG_20, 0, NULL }, |
1106 | {CHANNELMSG_TL_CONNECT_REQUEST, 0, NULL}, | 1106 | { CHANNELMSG_TL_CONNECT_REQUEST, 0, NULL }, |
1107 | }; | 1107 | }; |
1108 | 1108 | ||
1109 | /* | 1109 | /* |
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index a8366fec1458..fce27fb141cc 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c | |||
@@ -296,44 +296,47 @@ struct vmbus_channel *relid2channel(u32 relid) | |||
296 | 296 | ||
297 | /* | 297 | /* |
298 | * vmbus_on_event - Process a channel event notification | 298 | * vmbus_on_event - Process a channel event notification |
299 | * | ||
300 | * For batched channels (default) optimize host to guest signaling | ||
301 | * by ensuring: | ||
302 | * 1. While reading the channel, we disable interrupts from host. | ||
303 | * 2. Ensure that we process all posted messages from the host | ||
304 | * before returning from this callback. | ||
305 | * 3. Once we return, enable signaling from the host. Once this | ||
306 | * state is set we check to see if additional packets are | ||
307 | * available to read. In this case we repeat the process. | ||
308 | * If this tasklet has been running for a long time | ||
309 | * then reschedule ourselves. | ||
299 | */ | 310 | */ |
300 | void vmbus_on_event(unsigned long data) | 311 | void vmbus_on_event(unsigned long data) |
301 | { | 312 | { |
302 | struct vmbus_channel *channel = (void *) data; | 313 | struct vmbus_channel *channel = (void *) data; |
303 | void (*callback_fn)(void *); | 314 | unsigned long time_limit = jiffies + 2; |
304 | 315 | ||
305 | /* | 316 | do { |
306 | * A channel once created is persistent even when there | 317 | void (*callback_fn)(void *); |
307 | * is no driver handling the device. An unloading driver | 318 | |
308 | * sets the onchannel_callback to NULL on the same CPU | 319 | /* A channel once created is persistent even when |
309 | * as where this interrupt is handled (in an interrupt context). | 320 | * there is no driver handling the device. An |
310 | * Thus, checking and invoking the driver specific callback takes | 321 | * unloading driver sets the onchannel_callback to NULL. |
311 | * care of orderly unloading of the driver. | ||
312 | */ | ||
313 | callback_fn = READ_ONCE(channel->onchannel_callback); | ||
314 | if (unlikely(callback_fn == NULL)) | ||
315 | return; | ||
316 | |||
317 | (*callback_fn)(channel->channel_callback_context); | ||
318 | |||
319 | if (channel->callback_mode == HV_CALL_BATCHED) { | ||
320 | /* | ||
321 | * This callback reads the messages sent by the host. | ||
322 | * We can optimize host to guest signaling by ensuring: | ||
323 | * 1. While reading the channel, we disable interrupts from | ||
324 | * host. | ||
325 | * 2. Ensure that we process all posted messages from the host | ||
326 | * before returning from this callback. | ||
327 | * 3. Once we return, enable signaling from the host. Once this | ||
328 | * state is set we check to see if additional packets are | ||
329 | * available to read. In this case we repeat the process. | ||
330 | */ | 322 | */ |
331 | if (hv_end_read(&channel->inbound) != 0) { | 323 | callback_fn = READ_ONCE(channel->onchannel_callback); |
332 | hv_begin_read(&channel->inbound); | 324 | if (unlikely(callback_fn == NULL)) |
325 | return; | ||
333 | 326 | ||
334 | tasklet_schedule(&channel->callback_event); | 327 | (*callback_fn)(channel->channel_callback_context); |
335 | } | 328 | |
336 | } | 329 | if (channel->callback_mode != HV_CALL_BATCHED) |
330 | return; | ||
331 | |||
332 | if (likely(hv_end_read(&channel->inbound) == 0)) | ||
333 | return; | ||
334 | |||
335 | hv_begin_read(&channel->inbound); | ||
336 | } while (likely(time_before(jiffies, time_limit))); | ||
337 | |||
338 | /* The time limit (2 jiffies) has been reached */ | ||
339 | tasklet_schedule(&channel->callback_event); | ||
337 | } | 340 | } |
338 | 341 | ||
339 | /* | 342 | /* |
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 665a64f1611e..12e7baecb84e 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c | |||
@@ -254,7 +254,10 @@ int hv_synic_init(unsigned int cpu) | |||
254 | shared_sint.as_uint64 = 0; | 254 | shared_sint.as_uint64 = 0; |
255 | shared_sint.vector = HYPERVISOR_CALLBACK_VECTOR; | 255 | shared_sint.vector = HYPERVISOR_CALLBACK_VECTOR; |
256 | shared_sint.masked = false; | 256 | shared_sint.masked = false; |
257 | shared_sint.auto_eoi = true; | 257 | if (ms_hyperv.hints & HV_X64_DEPRECATING_AEOI_RECOMMENDED) |
258 | shared_sint.auto_eoi = false; | ||
259 | else | ||
260 | shared_sint.auto_eoi = true; | ||
258 | 261 | ||
259 | hv_set_synint_state(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, | 262 | hv_set_synint_state(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, |
260 | shared_sint.as_uint64); | 263 | shared_sint.as_uint64); |
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index 5fd03e59cee5..f5728deff893 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c | |||
@@ -722,8 +722,6 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size, | |||
722 | 5*HZ); | 722 | 5*HZ); |
723 | post_status(&dm_device); | 723 | post_status(&dm_device); |
724 | } | 724 | } |
725 | |||
726 | return; | ||
727 | } | 725 | } |
728 | 726 | ||
729 | static void hv_online_page(struct page *pg) | 727 | static void hv_online_page(struct page *pg) |
diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c index a5596a642ed0..daa75bd41f86 100644 --- a/drivers/hv/hv_fcopy.c +++ b/drivers/hv/hv_fcopy.c | |||
@@ -186,8 +186,6 @@ static void fcopy_send_data(struct work_struct *dummy) | |||
186 | } | 186 | } |
187 | } | 187 | } |
188 | kfree(smsg_out); | 188 | kfree(smsg_out); |
189 | |||
190 | return; | ||
191 | } | 189 | } |
192 | 190 | ||
193 | /* | 191 | /* |
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index a1adfe2cfb34..e99ff2ddad40 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c | |||
@@ -69,7 +69,7 @@ static const int fw_versions[] = { | |||
69 | * | 69 | * |
70 | * While the request/response protocol is guaranteed by the host, we further | 70 | * While the request/response protocol is guaranteed by the host, we further |
71 | * ensure this by serializing packet processing in this driver - we do not | 71 | * ensure this by serializing packet processing in this driver - we do not |
72 | * read additional packets from the VMBUs until the current packet is fully | 72 | * read additional packets from the VMBUS until the current packet is fully |
73 | * handled. | 73 | * handled. |
74 | */ | 74 | */ |
75 | 75 | ||
@@ -397,7 +397,7 @@ kvp_send_key(struct work_struct *dummy) | |||
397 | * the max lengths specified. We will however, reserve room | 397 | * the max lengths specified. We will however, reserve room |
398 | * for the string terminating character - in the utf16s_utf8s() | 398 | * for the string terminating character - in the utf16s_utf8s() |
399 | * function we limit the size of the buffer where the converted | 399 | * function we limit the size of the buffer where the converted |
400 | * string is placed to HV_KVP_EXCHANGE_MAX_*_SIZE -1 to gaurantee | 400 | * string is placed to HV_KVP_EXCHANGE_MAX_*_SIZE -1 to guarantee |
401 | * that the strings can be properly terminated! | 401 | * that the strings can be properly terminated! |
402 | */ | 402 | */ |
403 | 403 | ||
@@ -483,8 +483,6 @@ kvp_send_key(struct work_struct *dummy) | |||
483 | } | 483 | } |
484 | 484 | ||
485 | kfree(message); | 485 | kfree(message); |
486 | |||
487 | return; | ||
488 | } | 486 | } |
489 | 487 | ||
490 | /* | 488 | /* |
@@ -533,7 +531,7 @@ kvp_respond_to_host(struct hv_kvp_msg *msg_to_host, int error) | |||
533 | */ | 531 | */ |
534 | if (error) { | 532 | if (error) { |
535 | /* | 533 | /* |
536 | * Something failed or we have timedout; | 534 | * Something failed or we have timed out; |
537 | * terminate the current host-side iteration. | 535 | * terminate the current host-side iteration. |
538 | */ | 536 | */ |
539 | goto response_done; | 537 | goto response_done; |
@@ -607,8 +605,8 @@ response_done: | |||
607 | * This callback is invoked when we get a KVP message from the host. | 605 | * This callback is invoked when we get a KVP message from the host. |
608 | * The host ensures that only one KVP transaction can be active at a time. | 606 | * The host ensures that only one KVP transaction can be active at a time. |
609 | * KVP implementation in Linux needs to forward the key to a user-mde | 607 | * KVP implementation in Linux needs to forward the key to a user-mde |
610 | * component to retrive the corresponding value. Consequently, we cannot | 608 | * component to retrieve the corresponding value. Consequently, we cannot |
611 | * respond to the host in the conext of this callback. Since the host | 609 | * respond to the host in the context of this callback. Since the host |
612 | * guarantees that at most only one transaction can be active at a time, | 610 | * guarantees that at most only one transaction can be active at a time, |
613 | * we stash away the transaction state in a set of global variables. | 611 | * we stash away the transaction state in a set of global variables. |
614 | */ | 612 | */ |
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c index e659d1b94a57..6831efd73394 100644 --- a/drivers/hv/hv_snapshot.c +++ b/drivers/hv/hv_snapshot.c | |||
@@ -212,8 +212,6 @@ static void vss_send_op(void) | |||
212 | } | 212 | } |
213 | 213 | ||
214 | kfree(vss_msg); | 214 | kfree(vss_msg); |
215 | |||
216 | return; | ||
217 | } | 215 | } |
218 | 216 | ||
219 | static void vss_handle_request(struct work_struct *dummy) | 217 | static void vss_handle_request(struct work_struct *dummy) |
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 884f83bba1ab..6113e915c50e 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h | |||
@@ -218,8 +218,8 @@ struct hv_per_cpu_context { | |||
218 | 218 | ||
219 | struct hv_context { | 219 | struct hv_context { |
220 | /* We only support running on top of Hyper-V | 220 | /* We only support running on top of Hyper-V |
221 | * So at this point this really can only contain the Hyper-V ID | 221 | * So at this point this really can only contain the Hyper-V ID |
222 | */ | 222 | */ |
223 | u64 guestid; | 223 | u64 guestid; |
224 | 224 | ||
225 | void *tsc_page; | 225 | void *tsc_page; |
@@ -248,14 +248,6 @@ struct hv_context { | |||
248 | 248 | ||
249 | extern struct hv_context hv_context; | 249 | extern struct hv_context hv_context; |
250 | 250 | ||
251 | struct hv_ring_buffer_debug_info { | ||
252 | u32 current_interrupt_mask; | ||
253 | u32 current_read_index; | ||
254 | u32 current_write_index; | ||
255 | u32 bytes_avail_toread; | ||
256 | u32 bytes_avail_towrite; | ||
257 | }; | ||
258 | |||
259 | /* Hv Interface */ | 251 | /* Hv Interface */ |
260 | 252 | ||
261 | extern int hv_init(void); | 253 | extern int hv_init(void); |
@@ -289,9 +281,6 @@ int hv_ringbuffer_read(struct vmbus_channel *channel, | |||
289 | void *buffer, u32 buflen, u32 *buffer_actual_len, | 281 | void *buffer, u32 buflen, u32 *buffer_actual_len, |
290 | u64 *requestid, bool raw); | 282 | u64 *requestid, bool raw); |
291 | 283 | ||
292 | void hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, | ||
293 | struct hv_ring_buffer_debug_info *debug_info); | ||
294 | |||
295 | /* | 284 | /* |
296 | * Maximum channels is determined by the size of the interrupt page | 285 | * Maximum channels is determined by the size of the interrupt page |
297 | * which is PAGE_SIZE. 1/2 of PAGE_SIZE is for send endpoint interrupt | 286 | * which is PAGE_SIZE. 1/2 of PAGE_SIZE is for send endpoint interrupt |
@@ -376,7 +365,7 @@ struct vmbus_channel_message_table_entry { | |||
376 | void (*message_handler)(struct vmbus_channel_message_header *msg); | 365 | void (*message_handler)(struct vmbus_channel_message_header *msg); |
377 | }; | 366 | }; |
378 | 367 | ||
379 | extern struct vmbus_channel_message_table_entry | 368 | extern const struct vmbus_channel_message_table_entry |
380 | channel_message_table[CHANNELMSG_COUNT]; | 369 | channel_message_table[CHANNELMSG_COUNT]; |
381 | 370 | ||
382 | 371 | ||
@@ -403,17 +392,17 @@ int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep); | |||
403 | void vmbus_on_event(unsigned long data); | 392 | void vmbus_on_event(unsigned long data); |
404 | void vmbus_on_msg_dpc(unsigned long data); | 393 | void vmbus_on_msg_dpc(unsigned long data); |
405 | 394 | ||
406 | int hv_kvp_init(struct hv_util_service *); | 395 | int hv_kvp_init(struct hv_util_service *srv); |
407 | void hv_kvp_deinit(void); | 396 | void hv_kvp_deinit(void); |
408 | void hv_kvp_onchannelcallback(void *); | 397 | void hv_kvp_onchannelcallback(void *context); |
409 | 398 | ||
410 | int hv_vss_init(struct hv_util_service *); | 399 | int hv_vss_init(struct hv_util_service *srv); |
411 | void hv_vss_deinit(void); | 400 | void hv_vss_deinit(void); |
412 | void hv_vss_onchannelcallback(void *); | 401 | void hv_vss_onchannelcallback(void *context); |
413 | 402 | ||
414 | int hv_fcopy_init(struct hv_util_service *); | 403 | int hv_fcopy_init(struct hv_util_service *srv); |
415 | void hv_fcopy_deinit(void); | 404 | void hv_fcopy_deinit(void); |
416 | void hv_fcopy_onchannelcallback(void *); | 405 | void hv_fcopy_onchannelcallback(void *context); |
417 | void vmbus_initiate_unload(bool crash); | 406 | void vmbus_initiate_unload(bool crash); |
418 | 407 | ||
419 | static inline void hv_poll_channel(struct vmbus_channel *channel, | 408 | static inline void hv_poll_channel(struct vmbus_channel *channel, |
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index c3f1a9e33cef..1f450c39a9b0 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c | |||
@@ -75,8 +75,6 @@ static void hv_signal_on_write(u32 old_write, struct vmbus_channel *channel) | |||
75 | */ | 75 | */ |
76 | if (old_write == READ_ONCE(rbi->ring_buffer->read_index)) | 76 | if (old_write == READ_ONCE(rbi->ring_buffer->read_index)) |
77 | vmbus_setevent(channel); | 77 | vmbus_setevent(channel); |
78 | |||
79 | return; | ||
80 | } | 78 | } |
81 | 79 | ||
82 | /* Get the next write location for the specified ring buffer. */ | 80 | /* Get the next write location for the specified ring buffer. */ |
@@ -210,6 +208,7 @@ void hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, | |||
210 | ring_info->ring_buffer->interrupt_mask; | 208 | ring_info->ring_buffer->interrupt_mask; |
211 | } | 209 | } |
212 | } | 210 | } |
211 | EXPORT_SYMBOL_GPL(hv_ringbuffer_get_debuginfo); | ||
213 | 212 | ||
214 | /* Initialize the ring buffer. */ | 213 | /* Initialize the ring buffer. */ |
215 | int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, | 214 | int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, |
@@ -269,14 +268,13 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info) | |||
269 | int hv_ringbuffer_write(struct vmbus_channel *channel, | 268 | int hv_ringbuffer_write(struct vmbus_channel *channel, |
270 | const struct kvec *kv_list, u32 kv_count) | 269 | const struct kvec *kv_list, u32 kv_count) |
271 | { | 270 | { |
272 | int i = 0; | 271 | int i; |
273 | u32 bytes_avail_towrite; | 272 | u32 bytes_avail_towrite; |
274 | u32 totalbytes_towrite = 0; | 273 | u32 totalbytes_towrite = sizeof(u64); |
275 | |||
276 | u32 next_write_location; | 274 | u32 next_write_location; |
277 | u32 old_write; | 275 | u32 old_write; |
278 | u64 prev_indices = 0; | 276 | u64 prev_indices; |
279 | unsigned long flags = 0; | 277 | unsigned long flags; |
280 | struct hv_ring_buffer_info *outring_info = &channel->outbound; | 278 | struct hv_ring_buffer_info *outring_info = &channel->outbound; |
281 | 279 | ||
282 | if (channel->rescind) | 280 | if (channel->rescind) |
@@ -285,8 +283,6 @@ int hv_ringbuffer_write(struct vmbus_channel *channel, | |||
285 | for (i = 0; i < kv_count; i++) | 283 | for (i = 0; i < kv_count; i++) |
286 | totalbytes_towrite += kv_list[i].iov_len; | 284 | totalbytes_towrite += kv_list[i].iov_len; |
287 | 285 | ||
288 | totalbytes_towrite += sizeof(u64); | ||
289 | |||
290 | spin_lock_irqsave(&outring_info->ring_lock, flags); | 286 | spin_lock_irqsave(&outring_info->ring_lock, flags); |
291 | 287 | ||
292 | bytes_avail_towrite = hv_get_bytes_to_write(outring_info); | 288 | bytes_avail_towrite = hv_get_bytes_to_write(outring_info); |
@@ -349,18 +345,16 @@ int hv_ringbuffer_read(struct vmbus_channel *channel, | |||
349 | u64 *requestid, bool raw) | 345 | u64 *requestid, bool raw) |
350 | { | 346 | { |
351 | u32 bytes_avail_toread; | 347 | u32 bytes_avail_toread; |
352 | u32 next_read_location = 0; | 348 | u32 next_read_location; |
353 | u64 prev_indices = 0; | 349 | u64 prev_indices = 0; |
354 | struct vmpacket_descriptor desc; | 350 | struct vmpacket_descriptor desc; |
355 | u32 offset; | 351 | u32 offset; |
356 | u32 packetlen; | 352 | u32 packetlen; |
357 | int ret = 0; | ||
358 | struct hv_ring_buffer_info *inring_info = &channel->inbound; | 353 | struct hv_ring_buffer_info *inring_info = &channel->inbound; |
359 | 354 | ||
360 | if (buflen <= 0) | 355 | if (buflen <= 0) |
361 | return -EINVAL; | 356 | return -EINVAL; |
362 | 357 | ||
363 | |||
364 | *buffer_actual_len = 0; | 358 | *buffer_actual_len = 0; |
365 | *requestid = 0; | 359 | *requestid = 0; |
366 | 360 | ||
@@ -371,7 +365,7 @@ int hv_ringbuffer_read(struct vmbus_channel *channel, | |||
371 | * No error is set when there is even no header, drivers are | 365 | * No error is set when there is even no header, drivers are |
372 | * supposed to analyze buffer_actual_len. | 366 | * supposed to analyze buffer_actual_len. |
373 | */ | 367 | */ |
374 | return ret; | 368 | return 0; |
375 | } | 369 | } |
376 | 370 | ||
377 | init_cached_read_index(inring_info); | 371 | init_cached_read_index(inring_info); |
@@ -417,7 +411,7 @@ int hv_ringbuffer_read(struct vmbus_channel *channel, | |||
417 | 411 | ||
418 | hv_signal_on_read(channel); | 412 | hv_signal_on_read(channel); |
419 | 413 | ||
420 | return ret; | 414 | return 0; |
421 | } | 415 | } |
422 | 416 | ||
423 | /* | 417 | /* |
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 8370b9dc6037..0087b49095eb 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c | |||
@@ -787,8 +787,6 @@ static void vmbus_shutdown(struct device *child_device) | |||
787 | 787 | ||
788 | if (drv->shutdown) | 788 | if (drv->shutdown) |
789 | drv->shutdown(dev); | 789 | drv->shutdown(dev); |
790 | |||
791 | return; | ||
792 | } | 790 | } |
793 | 791 | ||
794 | 792 | ||
@@ -855,7 +853,7 @@ void vmbus_on_msg_dpc(unsigned long data) | |||
855 | struct hv_message *msg = (struct hv_message *)page_addr + | 853 | struct hv_message *msg = (struct hv_message *)page_addr + |
856 | VMBUS_MESSAGE_SINT; | 854 | VMBUS_MESSAGE_SINT; |
857 | struct vmbus_channel_message_header *hdr; | 855 | struct vmbus_channel_message_header *hdr; |
858 | struct vmbus_channel_message_table_entry *entry; | 856 | const struct vmbus_channel_message_table_entry *entry; |
859 | struct onmessage_work_context *ctx; | 857 | struct onmessage_work_context *ctx; |
860 | u32 message_type = msg->header.message_type; | 858 | u32 message_type = msg->header.message_type; |
861 | 859 | ||
diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c index 629e031b7456..09142e99e915 100644 --- a/drivers/hwtracing/coresight/of_coresight.c +++ b/drivers/hwtracing/coresight/of_coresight.c | |||
@@ -149,7 +149,7 @@ struct coresight_platform_data *of_get_coresight_platform_data( | |||
149 | continue; | 149 | continue; |
150 | 150 | ||
151 | /* The local out port number */ | 151 | /* The local out port number */ |
152 | pdata->outports[i] = endpoint.id; | 152 | pdata->outports[i] = endpoint.port; |
153 | 153 | ||
154 | /* | 154 | /* |
155 | * Get a handle on the remote port and parent | 155 | * Get a handle on the remote port and parent |
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 3ff91e02fee3..57c14da5708f 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c | |||
@@ -1719,18 +1719,13 @@ int iio_device_register(struct iio_dev *indio_dev) | |||
1719 | 1719 | ||
1720 | cdev_init(&indio_dev->chrdev, &iio_buffer_fileops); | 1720 | cdev_init(&indio_dev->chrdev, &iio_buffer_fileops); |
1721 | indio_dev->chrdev.owner = indio_dev->info->driver_module; | 1721 | indio_dev->chrdev.owner = indio_dev->info->driver_module; |
1722 | indio_dev->chrdev.kobj.parent = &indio_dev->dev.kobj; | ||
1723 | ret = cdev_add(&indio_dev->chrdev, indio_dev->dev.devt, 1); | ||
1724 | if (ret < 0) | ||
1725 | goto error_unreg_eventset; | ||
1726 | 1722 | ||
1727 | ret = device_add(&indio_dev->dev); | 1723 | ret = cdev_device_add(&indio_dev->chrdev, &indio_dev->dev); |
1728 | if (ret < 0) | 1724 | if (ret < 0) |
1729 | goto error_cdev_del; | 1725 | goto error_unreg_eventset; |
1730 | 1726 | ||
1731 | return 0; | 1727 | return 0; |
1732 | error_cdev_del: | 1728 | |
1733 | cdev_del(&indio_dev->chrdev); | ||
1734 | error_unreg_eventset: | 1729 | error_unreg_eventset: |
1735 | iio_device_unregister_eventset(indio_dev); | 1730 | iio_device_unregister_eventset(indio_dev); |
1736 | error_free_sysfs: | 1731 | error_free_sysfs: |
@@ -1751,10 +1746,8 @@ void iio_device_unregister(struct iio_dev *indio_dev) | |||
1751 | { | 1746 | { |
1752 | mutex_lock(&indio_dev->info_exist_lock); | 1747 | mutex_lock(&indio_dev->info_exist_lock); |
1753 | 1748 | ||
1754 | device_del(&indio_dev->dev); | 1749 | cdev_device_del(&indio_dev->chrdev, &indio_dev->dev); |
1755 | 1750 | ||
1756 | if (indio_dev->chrdev.dev) | ||
1757 | cdev_del(&indio_dev->chrdev); | ||
1758 | iio_device_unregister_debugfs(indio_dev); | 1751 | iio_device_unregister_debugfs(indio_dev); |
1759 | 1752 | ||
1760 | iio_disable_all_buffers(indio_dev); | 1753 | iio_disable_all_buffers(indio_dev); |
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 80d0fca05c06..112099c86a19 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c | |||
@@ -1205,12 +1205,15 @@ static void ib_ucm_release_dev(struct device *dev) | |||
1205 | struct ib_ucm_device *ucm_dev; | 1205 | struct ib_ucm_device *ucm_dev; |
1206 | 1206 | ||
1207 | ucm_dev = container_of(dev, struct ib_ucm_device, dev); | 1207 | ucm_dev = container_of(dev, struct ib_ucm_device, dev); |
1208 | cdev_del(&ucm_dev->cdev); | 1208 | kfree(ucm_dev); |
1209 | } | ||
1210 | |||
1211 | static void ib_ucm_free_dev(struct ib_ucm_device *ucm_dev) | ||
1212 | { | ||
1209 | if (ucm_dev->devnum < IB_UCM_MAX_DEVICES) | 1213 | if (ucm_dev->devnum < IB_UCM_MAX_DEVICES) |
1210 | clear_bit(ucm_dev->devnum, dev_map); | 1214 | clear_bit(ucm_dev->devnum, dev_map); |
1211 | else | 1215 | else |
1212 | clear_bit(ucm_dev->devnum - IB_UCM_MAX_DEVICES, overflow_map); | 1216 | clear_bit(ucm_dev->devnum - IB_UCM_MAX_DEVICES, overflow_map); |
1213 | kfree(ucm_dev); | ||
1214 | } | 1217 | } |
1215 | 1218 | ||
1216 | static const struct file_operations ucm_fops = { | 1219 | static const struct file_operations ucm_fops = { |
@@ -1266,7 +1269,9 @@ static void ib_ucm_add_one(struct ib_device *device) | |||
1266 | if (!ucm_dev) | 1269 | if (!ucm_dev) |
1267 | return; | 1270 | return; |
1268 | 1271 | ||
1272 | device_initialize(&ucm_dev->dev); | ||
1269 | ucm_dev->ib_dev = device; | 1273 | ucm_dev->ib_dev = device; |
1274 | ucm_dev->dev.release = ib_ucm_release_dev; | ||
1270 | 1275 | ||
1271 | devnum = find_first_zero_bit(dev_map, IB_UCM_MAX_DEVICES); | 1276 | devnum = find_first_zero_bit(dev_map, IB_UCM_MAX_DEVICES); |
1272 | if (devnum >= IB_UCM_MAX_DEVICES) { | 1277 | if (devnum >= IB_UCM_MAX_DEVICES) { |
@@ -1286,16 +1291,14 @@ static void ib_ucm_add_one(struct ib_device *device) | |||
1286 | cdev_init(&ucm_dev->cdev, &ucm_fops); | 1291 | cdev_init(&ucm_dev->cdev, &ucm_fops); |
1287 | ucm_dev->cdev.owner = THIS_MODULE; | 1292 | ucm_dev->cdev.owner = THIS_MODULE; |
1288 | kobject_set_name(&ucm_dev->cdev.kobj, "ucm%d", ucm_dev->devnum); | 1293 | kobject_set_name(&ucm_dev->cdev.kobj, "ucm%d", ucm_dev->devnum); |
1289 | if (cdev_add(&ucm_dev->cdev, base, 1)) | ||
1290 | goto err; | ||
1291 | 1294 | ||
1292 | ucm_dev->dev.class = &cm_class; | 1295 | ucm_dev->dev.class = &cm_class; |
1293 | ucm_dev->dev.parent = device->dev.parent; | 1296 | ucm_dev->dev.parent = device->dev.parent; |
1294 | ucm_dev->dev.devt = ucm_dev->cdev.dev; | 1297 | ucm_dev->dev.devt = base; |
1295 | ucm_dev->dev.release = ib_ucm_release_dev; | 1298 | |
1296 | dev_set_name(&ucm_dev->dev, "ucm%d", ucm_dev->devnum); | 1299 | dev_set_name(&ucm_dev->dev, "ucm%d", ucm_dev->devnum); |
1297 | if (device_register(&ucm_dev->dev)) | 1300 | if (cdev_device_add(&ucm_dev->cdev, &ucm_dev->dev)) |
1298 | goto err_cdev; | 1301 | goto err_devnum; |
1299 | 1302 | ||
1300 | if (device_create_file(&ucm_dev->dev, &dev_attr_ibdev)) | 1303 | if (device_create_file(&ucm_dev->dev, &dev_attr_ibdev)) |
1301 | goto err_dev; | 1304 | goto err_dev; |
@@ -1304,15 +1307,11 @@ static void ib_ucm_add_one(struct ib_device *device) | |||
1304 | return; | 1307 | return; |
1305 | 1308 | ||
1306 | err_dev: | 1309 | err_dev: |
1307 | device_unregister(&ucm_dev->dev); | 1310 | cdev_device_del(&ucm_dev->cdev, &ucm_dev->dev); |
1308 | err_cdev: | 1311 | err_devnum: |
1309 | cdev_del(&ucm_dev->cdev); | 1312 | ib_ucm_free_dev(ucm_dev); |
1310 | if (ucm_dev->devnum < IB_UCM_MAX_DEVICES) | ||
1311 | clear_bit(devnum, dev_map); | ||
1312 | else | ||
1313 | clear_bit(devnum, overflow_map); | ||
1314 | err: | 1313 | err: |
1315 | kfree(ucm_dev); | 1314 | put_device(&ucm_dev->dev); |
1316 | return; | 1315 | return; |
1317 | } | 1316 | } |
1318 | 1317 | ||
@@ -1323,7 +1322,9 @@ static void ib_ucm_remove_one(struct ib_device *device, void *client_data) | |||
1323 | if (!ucm_dev) | 1322 | if (!ucm_dev) |
1324 | return; | 1323 | return; |
1325 | 1324 | ||
1326 | device_unregister(&ucm_dev->dev); | 1325 | cdev_device_del(&ucm_dev->cdev, &ucm_dev->dev); |
1326 | ib_ucm_free_dev(ucm_dev); | ||
1327 | put_device(&ucm_dev->dev); | ||
1327 | } | 1328 | } |
1328 | 1329 | ||
1329 | static CLASS_ATTR_STRING(abi_version, S_IRUGO, | 1330 | static CLASS_ATTR_STRING(abi_version, S_IRUGO, |
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 200422d24299..36a6f5c8914c 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c | |||
@@ -1187,7 +1187,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, | |||
1187 | 1187 | ||
1188 | cdev_init(&port->cdev, &umad_fops); | 1188 | cdev_init(&port->cdev, &umad_fops); |
1189 | port->cdev.owner = THIS_MODULE; | 1189 | port->cdev.owner = THIS_MODULE; |
1190 | port->cdev.kobj.parent = &umad_dev->kobj; | 1190 | cdev_set_parent(&port->cdev, &umad_dev->kobj); |
1191 | kobject_set_name(&port->cdev.kobj, "umad%d", port->dev_num); | 1191 | kobject_set_name(&port->cdev.kobj, "umad%d", port->dev_num); |
1192 | if (cdev_add(&port->cdev, base, 1)) | 1192 | if (cdev_add(&port->cdev, base, 1)) |
1193 | goto err_cdev; | 1193 | goto err_cdev; |
@@ -1206,7 +1206,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, | |||
1206 | base += IB_UMAD_MAX_PORTS; | 1206 | base += IB_UMAD_MAX_PORTS; |
1207 | cdev_init(&port->sm_cdev, &umad_sm_fops); | 1207 | cdev_init(&port->sm_cdev, &umad_sm_fops); |
1208 | port->sm_cdev.owner = THIS_MODULE; | 1208 | port->sm_cdev.owner = THIS_MODULE; |
1209 | port->sm_cdev.kobj.parent = &umad_dev->kobj; | 1209 | cdev_set_parent(&port->sm_cdev, &umad_dev->kobj); |
1210 | kobject_set_name(&port->sm_cdev.kobj, "issm%d", port->dev_num); | 1210 | kobject_set_name(&port->sm_cdev.kobj, "issm%d", port->dev_num); |
1211 | if (cdev_add(&port->sm_cdev, base, 1)) | 1211 | if (cdev_add(&port->sm_cdev, base, 1)) |
1212 | goto err_sm_cdev; | 1212 | goto err_sm_cdev; |
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 3a9883d1257e..3d2609608f58 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c | |||
@@ -1093,7 +1093,7 @@ static void ib_uverbs_add_one(struct ib_device *device) | |||
1093 | cdev_init(&uverbs_dev->cdev, NULL); | 1093 | cdev_init(&uverbs_dev->cdev, NULL); |
1094 | uverbs_dev->cdev.owner = THIS_MODULE; | 1094 | uverbs_dev->cdev.owner = THIS_MODULE; |
1095 | uverbs_dev->cdev.ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops; | 1095 | uverbs_dev->cdev.ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops; |
1096 | uverbs_dev->cdev.kobj.parent = &uverbs_dev->kobj; | 1096 | cdev_set_parent(&uverbs_dev->cdev, &uverbs_dev->kobj); |
1097 | kobject_set_name(&uverbs_dev->cdev.kobj, "uverbs%d", uverbs_dev->devnum); | 1097 | kobject_set_name(&uverbs_dev->cdev.kobj, "uverbs%d", uverbs_dev->devnum); |
1098 | if (cdev_add(&uverbs_dev->cdev, base, 1)) | 1098 | if (cdev_add(&uverbs_dev->cdev, base, 1)) |
1099 | goto err_cdev; | 1099 | goto err_cdev; |
diff --git a/drivers/infiniband/hw/hfi1/device.c b/drivers/infiniband/hw/hfi1/device.c index bf64b5a7bfd7..bbb6069dec2a 100644 --- a/drivers/infiniband/hw/hfi1/device.c +++ b/drivers/infiniband/hw/hfi1/device.c | |||
@@ -69,7 +69,7 @@ int hfi1_cdev_init(int minor, const char *name, | |||
69 | 69 | ||
70 | cdev_init(cdev, fops); | 70 | cdev_init(cdev, fops); |
71 | cdev->owner = THIS_MODULE; | 71 | cdev->owner = THIS_MODULE; |
72 | cdev->kobj.parent = parent; | 72 | cdev_set_parent(cdev, parent); |
73 | kobject_set_name(&cdev->kobj, name); | 73 | kobject_set_name(&cdev->kobj, name); |
74 | 74 | ||
75 | ret = cdev_add(cdev, dev, 1); | 75 | ret = cdev_add(cdev, dev, 1); |
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index e9ae3d500a55..925571475005 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -1354,8 +1354,6 @@ static void evdev_cleanup(struct evdev *evdev) | |||
1354 | evdev_mark_dead(evdev); | 1354 | evdev_mark_dead(evdev); |
1355 | evdev_hangup(evdev); | 1355 | evdev_hangup(evdev); |
1356 | 1356 | ||
1357 | cdev_del(&evdev->cdev); | ||
1358 | |||
1359 | /* evdev is marked dead so no one else accesses evdev->open */ | 1357 | /* evdev is marked dead so no one else accesses evdev->open */ |
1360 | if (evdev->open) { | 1358 | if (evdev->open) { |
1361 | input_flush_device(handle, NULL); | 1359 | input_flush_device(handle, NULL); |
@@ -1416,12 +1414,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
1416 | goto err_free_evdev; | 1414 | goto err_free_evdev; |
1417 | 1415 | ||
1418 | cdev_init(&evdev->cdev, &evdev_fops); | 1416 | cdev_init(&evdev->cdev, &evdev_fops); |
1419 | evdev->cdev.kobj.parent = &evdev->dev.kobj; | ||
1420 | error = cdev_add(&evdev->cdev, evdev->dev.devt, 1); | ||
1421 | if (error) | ||
1422 | goto err_unregister_handle; | ||
1423 | 1417 | ||
1424 | error = device_add(&evdev->dev); | 1418 | error = cdev_device_add(&evdev->cdev, &evdev->dev); |
1425 | if (error) | 1419 | if (error) |
1426 | goto err_cleanup_evdev; | 1420 | goto err_cleanup_evdev; |
1427 | 1421 | ||
@@ -1429,7 +1423,6 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
1429 | 1423 | ||
1430 | err_cleanup_evdev: | 1424 | err_cleanup_evdev: |
1431 | evdev_cleanup(evdev); | 1425 | evdev_cleanup(evdev); |
1432 | err_unregister_handle: | ||
1433 | input_unregister_handle(&evdev->handle); | 1426 | input_unregister_handle(&evdev->handle); |
1434 | err_free_evdev: | 1427 | err_free_evdev: |
1435 | put_device(&evdev->dev); | 1428 | put_device(&evdev->dev); |
@@ -1442,7 +1435,7 @@ static void evdev_disconnect(struct input_handle *handle) | |||
1442 | { | 1435 | { |
1443 | struct evdev *evdev = handle->private; | 1436 | struct evdev *evdev = handle->private; |
1444 | 1437 | ||
1445 | device_del(&evdev->dev); | 1438 | cdev_device_del(&evdev->cdev, &evdev->dev); |
1446 | evdev_cleanup(evdev); | 1439 | evdev_cleanup(evdev); |
1447 | input_free_minor(MINOR(evdev->dev.devt)); | 1440 | input_free_minor(MINOR(evdev->dev.devt)); |
1448 | input_unregister_handle(handle); | 1441 | input_unregister_handle(handle); |
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 065e67bf56dd..29d677c714d2 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c | |||
@@ -742,8 +742,6 @@ static void joydev_cleanup(struct joydev *joydev) | |||
742 | joydev_mark_dead(joydev); | 742 | joydev_mark_dead(joydev); |
743 | joydev_hangup(joydev); | 743 | joydev_hangup(joydev); |
744 | 744 | ||
745 | cdev_del(&joydev->cdev); | ||
746 | |||
747 | /* joydev is marked dead so no one else accesses joydev->open */ | 745 | /* joydev is marked dead so no one else accesses joydev->open */ |
748 | if (joydev->open) | 746 | if (joydev->open) |
749 | input_close_device(handle); | 747 | input_close_device(handle); |
@@ -913,12 +911,8 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
913 | goto err_free_joydev; | 911 | goto err_free_joydev; |
914 | 912 | ||
915 | cdev_init(&joydev->cdev, &joydev_fops); | 913 | cdev_init(&joydev->cdev, &joydev_fops); |
916 | joydev->cdev.kobj.parent = &joydev->dev.kobj; | ||
917 | error = cdev_add(&joydev->cdev, joydev->dev.devt, 1); | ||
918 | if (error) | ||
919 | goto err_unregister_handle; | ||
920 | 914 | ||
921 | error = device_add(&joydev->dev); | 915 | error = cdev_device_add(&joydev->cdev, &joydev->dev); |
922 | if (error) | 916 | if (error) |
923 | goto err_cleanup_joydev; | 917 | goto err_cleanup_joydev; |
924 | 918 | ||
@@ -926,7 +920,6 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
926 | 920 | ||
927 | err_cleanup_joydev: | 921 | err_cleanup_joydev: |
928 | joydev_cleanup(joydev); | 922 | joydev_cleanup(joydev); |
929 | err_unregister_handle: | ||
930 | input_unregister_handle(&joydev->handle); | 923 | input_unregister_handle(&joydev->handle); |
931 | err_free_joydev: | 924 | err_free_joydev: |
932 | put_device(&joydev->dev); | 925 | put_device(&joydev->dev); |
@@ -939,7 +932,7 @@ static void joydev_disconnect(struct input_handle *handle) | |||
939 | { | 932 | { |
940 | struct joydev *joydev = handle->private; | 933 | struct joydev *joydev = handle->private; |
941 | 934 | ||
942 | device_del(&joydev->dev); | 935 | cdev_device_del(&joydev->cdev, &joydev->dev); |
943 | joydev_cleanup(joydev); | 936 | joydev_cleanup(joydev); |
944 | input_free_minor(MINOR(joydev->dev.devt)); | 937 | input_free_minor(MINOR(joydev->dev.devt)); |
945 | input_unregister_handle(handle); | 938 | input_unregister_handle(handle); |
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index b604564dec5c..0e0ff84088fd 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c | |||
@@ -812,8 +812,6 @@ static void mousedev_cleanup(struct mousedev *mousedev) | |||
812 | mousedev_mark_dead(mousedev); | 812 | mousedev_mark_dead(mousedev); |
813 | mousedev_hangup(mousedev); | 813 | mousedev_hangup(mousedev); |
814 | 814 | ||
815 | cdev_del(&mousedev->cdev); | ||
816 | |||
817 | /* mousedev is marked dead so no one else accesses mousedev->open */ | 815 | /* mousedev is marked dead so no one else accesses mousedev->open */ |
818 | if (mousedev->open) | 816 | if (mousedev->open) |
819 | input_close_device(handle); | 817 | input_close_device(handle); |
@@ -901,12 +899,8 @@ static struct mousedev *mousedev_create(struct input_dev *dev, | |||
901 | } | 899 | } |
902 | 900 | ||
903 | cdev_init(&mousedev->cdev, &mousedev_fops); | 901 | cdev_init(&mousedev->cdev, &mousedev_fops); |
904 | mousedev->cdev.kobj.parent = &mousedev->dev.kobj; | ||
905 | error = cdev_add(&mousedev->cdev, mousedev->dev.devt, 1); | ||
906 | if (error) | ||
907 | goto err_unregister_handle; | ||
908 | 902 | ||
909 | error = device_add(&mousedev->dev); | 903 | error = cdev_device_add(&mousedev->cdev, &mousedev->dev); |
910 | if (error) | 904 | if (error) |
911 | goto err_cleanup_mousedev; | 905 | goto err_cleanup_mousedev; |
912 | 906 | ||
@@ -914,7 +908,6 @@ static struct mousedev *mousedev_create(struct input_dev *dev, | |||
914 | 908 | ||
915 | err_cleanup_mousedev: | 909 | err_cleanup_mousedev: |
916 | mousedev_cleanup(mousedev); | 910 | mousedev_cleanup(mousedev); |
917 | err_unregister_handle: | ||
918 | if (!mixdev) | 911 | if (!mixdev) |
919 | input_unregister_handle(&mousedev->handle); | 912 | input_unregister_handle(&mousedev->handle); |
920 | err_free_mousedev: | 913 | err_free_mousedev: |
@@ -927,7 +920,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev, | |||
927 | 920 | ||
928 | static void mousedev_destroy(struct mousedev *mousedev) | 921 | static void mousedev_destroy(struct mousedev *mousedev) |
929 | { | 922 | { |
930 | device_del(&mousedev->dev); | 923 | cdev_device_del(&mousedev->cdev, &mousedev->dev); |
931 | mousedev_cleanup(mousedev); | 924 | mousedev_cleanup(mousedev); |
932 | input_free_minor(MINOR(mousedev->dev.devt)); | 925 | input_free_minor(MINOR(mousedev->dev.devt)); |
933 | if (mousedev != mousedev_mix) | 926 | if (mousedev != mousedev_mix) |
diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index 37217e205040..3163e038a364 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c | |||
@@ -137,24 +137,17 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode, | |||
137 | 137 | ||
138 | /* Part 2: Initialize and register the character device */ | 138 | /* Part 2: Initialize and register the character device */ |
139 | cdev_init(&devnode->cdev, &cec_devnode_fops); | 139 | cdev_init(&devnode->cdev, &cec_devnode_fops); |
140 | devnode->cdev.kobj.parent = &devnode->dev.kobj; | ||
141 | devnode->cdev.owner = owner; | 140 | devnode->cdev.owner = owner; |
142 | 141 | ||
143 | ret = cdev_add(&devnode->cdev, devnode->dev.devt, 1); | 142 | ret = cdev_device_add(&devnode->cdev, &devnode->dev); |
144 | if (ret < 0) { | 143 | if (ret) { |
145 | pr_err("%s: cdev_add failed\n", __func__); | 144 | pr_err("%s: cdev_device_add failed\n", __func__); |
146 | goto clr_bit; | 145 | goto clr_bit; |
147 | } | 146 | } |
148 | 147 | ||
149 | ret = device_add(&devnode->dev); | ||
150 | if (ret) | ||
151 | goto cdev_del; | ||
152 | |||
153 | devnode->registered = true; | 148 | devnode->registered = true; |
154 | return 0; | 149 | return 0; |
155 | 150 | ||
156 | cdev_del: | ||
157 | cdev_del(&devnode->cdev); | ||
158 | clr_bit: | 151 | clr_bit: |
159 | mutex_lock(&cec_devnode_lock); | 152 | mutex_lock(&cec_devnode_lock); |
160 | clear_bit(devnode->minor, cec_devnode_nums); | 153 | clear_bit(devnode->minor, cec_devnode_nums); |
@@ -190,8 +183,7 @@ static void cec_devnode_unregister(struct cec_devnode *devnode) | |||
190 | devnode->unregistered = true; | 183 | devnode->unregistered = true; |
191 | mutex_unlock(&devnode->lock); | 184 | mutex_unlock(&devnode->lock); |
192 | 185 | ||
193 | device_del(&devnode->dev); | 186 | cdev_device_del(&devnode->cdev, &devnode->dev); |
194 | cdev_del(&devnode->cdev); | ||
195 | put_device(&devnode->dev); | 187 | put_device(&devnode->dev); |
196 | } | 188 | } |
197 | 189 | ||
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index ae46753c90cb..423248f577b6 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c | |||
@@ -248,31 +248,22 @@ int __must_check media_devnode_register(struct media_device *mdev, | |||
248 | dev_set_name(&devnode->dev, "media%d", devnode->minor); | 248 | dev_set_name(&devnode->dev, "media%d", devnode->minor); |
249 | device_initialize(&devnode->dev); | 249 | device_initialize(&devnode->dev); |
250 | 250 | ||
251 | /* Part 2: Initialize and register the character device */ | 251 | /* Part 2: Initialize the character device */ |
252 | cdev_init(&devnode->cdev, &media_devnode_fops); | 252 | cdev_init(&devnode->cdev, &media_devnode_fops); |
253 | devnode->cdev.owner = owner; | 253 | devnode->cdev.owner = owner; |
254 | devnode->cdev.kobj.parent = &devnode->dev.kobj; | ||
255 | 254 | ||
256 | ret = cdev_add(&devnode->cdev, MKDEV(MAJOR(media_dev_t), devnode->minor), 1); | 255 | /* Part 3: Add the media and char device */ |
256 | ret = cdev_device_add(&devnode->cdev, &devnode->dev); | ||
257 | if (ret < 0) { | 257 | if (ret < 0) { |
258 | pr_err("%s: cdev_add failed\n", __func__); | 258 | pr_err("%s: cdev_device_add failed\n", __func__); |
259 | goto cdev_add_error; | 259 | goto cdev_add_error; |
260 | } | 260 | } |
261 | 261 | ||
262 | /* Part 3: Add the media device */ | ||
263 | ret = device_add(&devnode->dev); | ||
264 | if (ret < 0) { | ||
265 | pr_err("%s: device_add failed\n", __func__); | ||
266 | goto device_add_error; | ||
267 | } | ||
268 | |||
269 | /* Part 4: Activate this minor. The char device can now be used. */ | 262 | /* Part 4: Activate this minor. The char device can now be used. */ |
270 | set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); | 263 | set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); |
271 | 264 | ||
272 | return 0; | 265 | return 0; |
273 | 266 | ||
274 | device_add_error: | ||
275 | cdev_del(&devnode->cdev); | ||
276 | cdev_add_error: | 267 | cdev_add_error: |
277 | mutex_lock(&media_devnode_lock); | 268 | mutex_lock(&media_devnode_lock); |
278 | clear_bit(devnode->minor, media_devnode_nums); | 269 | clear_bit(devnode->minor, media_devnode_nums); |
@@ -298,9 +289,8 @@ void media_devnode_unregister(struct media_devnode *devnode) | |||
298 | { | 289 | { |
299 | mutex_lock(&media_devnode_lock); | 290 | mutex_lock(&media_devnode_lock); |
300 | /* Delete the cdev on this minor as well */ | 291 | /* Delete the cdev on this minor as well */ |
301 | cdev_del(&devnode->cdev); | 292 | cdev_device_del(&devnode->cdev, &devnode->dev); |
302 | mutex_unlock(&media_devnode_lock); | 293 | mutex_unlock(&media_devnode_lock); |
303 | device_del(&devnode->dev); | ||
304 | devnode->media_dev = NULL; | 294 | devnode->media_dev = NULL; |
305 | put_device(&devnode->dev); | 295 | put_device(&devnode->dev); |
306 | } | 296 | } |
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 | |||
419 | To compile this driver as a module, choose M here: the | 419 | To compile this driver as a module, choose M here: the |
420 | module will be called vmw_balloon. | 420 | module will be called vmw_balloon. |
421 | 421 | ||
422 | config ARM_CHARLCD | ||
423 | bool "ARM Ltd. Character LCD Driver" | ||
424 | depends on PLAT_VERSATILE | ||
425 | help | ||
426 | This is a driver for the character LCD found on the ARM Ltd. | ||
427 | Versatile and RealView Platform Baseboards. It doesn't do | ||
428 | very much more than display the text "ARM Linux" on the first | ||
429 | line and the Linux version on the second line, but that's | ||
430 | still useful. | ||
431 | |||
432 | config PCH_PHUB | 422 | config PCH_PHUB |
433 | tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB" | 423 | tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB" |
434 | select GENERIC_NET_UTILS | 424 | select GENERIC_NET_UTILS |
@@ -492,284 +482,13 @@ config VEXPRESS_SYSCFG | |||
492 | bus. System Configuration interface is one of the possible means | 482 | bus. System Configuration interface is one of the possible means |
493 | of generating transactions on this bus. | 483 | of generating transactions on this bus. |
494 | 484 | ||
495 | config PANEL | 485 | config ASPEED_LPC_CTRL |
496 | tristate "Parallel port LCD/Keypad Panel support" | 486 | depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON |
497 | depends on PARPORT | 487 | tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control" |
498 | ---help--- | ||
499 | Say Y here if you have an HD44780 or KS-0074 LCD connected to your | ||
500 | parallel port. This driver also features 4 and 6-key keypads. The LCD | ||
501 | is accessible through the /dev/lcd char device (10, 156), and the | ||
502 | keypad through /dev/keypad (10, 185). This code can either be | ||
503 | compiled as a module, or linked into the kernel and started at boot. | ||
504 | If you don't understand what all this is about, say N. | ||
505 | |||
506 | if PANEL | ||
507 | |||
508 | config PANEL_PARPORT | ||
509 | int "Default parallel port number (0=LPT1)" | ||
510 | range 0 255 | ||
511 | default "0" | ||
512 | ---help--- | ||
513 | This is the index of the parallel port the panel is connected to. One | ||
514 | driver instance only supports one parallel port, so if your keypad | ||
515 | and LCD are connected to two separate ports, you have to start two | ||
516 | modules with different arguments. Numbering starts with '0' for LPT1, | ||
517 | and so on. | ||
518 | |||
519 | config PANEL_PROFILE | ||
520 | int "Default panel profile (0-5, 0=custom)" | ||
521 | range 0 5 | ||
522 | default "5" | ||
523 | ---help--- | ||
524 | To ease configuration, the driver supports different configuration | ||
525 | profiles for past and recent wirings. These profiles can also be | ||
526 | used to define an approximative configuration, completed by a few | ||
527 | other options. Here are the profiles : | ||
528 | |||
529 | 0 = custom (see further) | ||
530 | 1 = 2x16 parallel LCD, old keypad | ||
531 | 2 = 2x16 serial LCD (KS-0074), new keypad | ||
532 | 3 = 2x16 parallel LCD (Hantronix), no keypad | ||
533 | 4 = 2x16 parallel LCD (Nexcom NSA1045) with Nexcom's keypad | ||
534 | 5 = 2x40 parallel LCD (old one), with old keypad | ||
535 | |||
536 | Custom configurations allow you to define how your display is | ||
537 | wired to the parallel port, and how it works. This is only intended | ||
538 | for experts. | ||
539 | |||
540 | config PANEL_KEYPAD | ||
541 | depends on PANEL_PROFILE="0" | ||
542 | int "Keypad type (0=none, 1=old 6 keys, 2=new 6 keys, 3=Nexcom 4 keys)" | ||
543 | range 0 3 | ||
544 | default 0 | ||
545 | ---help--- | ||
546 | This enables and configures a keypad connected to the parallel port. | ||
547 | The keys will be read from character device 10,185. Valid values are : | ||
548 | |||
549 | 0 : do not enable this driver | ||
550 | 1 : old 6 keys keypad | ||
551 | 2 : new 6 keys keypad, as used on the server at www.ant-computing.com | ||
552 | 3 : Nexcom NSA1045's 4 keys keypad | ||
553 | |||
554 | New profiles can be described in the driver source. The driver also | ||
555 | supports simultaneous keys pressed when the keypad supports them. | ||
556 | |||
557 | config PANEL_LCD | ||
558 | depends on PANEL_PROFILE="0" | ||
559 | int "LCD type (0=none, 1=custom, 2=old //, 3=ks0074, 4=hantronix, 5=Nexcom)" | ||
560 | range 0 5 | ||
561 | default 0 | ||
562 | ---help--- | ||
563 | This enables and configures an LCD connected to the parallel port. | ||
564 | The driver includes an interpreter for escape codes starting with | ||
565 | '\e[L' which are specific to the LCD, and a few ANSI codes. The | ||
566 | driver will be registered as character device 10,156, usually | ||
567 | under the name '/dev/lcd'. There are a total of 6 supported types : | ||
568 | |||
569 | 0 : do not enable the driver | ||
570 | 1 : custom configuration and wiring (see further) | ||
571 | 2 : 2x16 & 2x40 parallel LCD (old wiring) | ||
572 | 3 : 2x16 serial LCD (KS-0074 based) | ||
573 | 4 : 2x16 parallel LCD (Hantronix wiring) | ||
574 | 5 : 2x16 parallel LCD (Nexcom wiring) | ||
575 | |||
576 | When type '1' is specified, other options will appear to configure | ||
577 | more precise aspects (wiring, dimensions, protocol, ...). Please note | ||
578 | that those values changed from the 2.4 driver for better consistency. | ||
579 | |||
580 | config PANEL_LCD_HEIGHT | ||
581 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" | ||
582 | int "Number of lines on the LCD (1-2)" | ||
583 | range 1 2 | ||
584 | default 2 | ||
585 | ---help--- | ||
586 | This is the number of visible character lines on the LCD in custom profile. | ||
587 | It can either be 1 or 2. | ||
588 | |||
589 | config PANEL_LCD_WIDTH | ||
590 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" | ||
591 | int "Number of characters per line on the LCD (1-40)" | ||
592 | range 1 40 | ||
593 | default 40 | ||
594 | ---help--- | ||
595 | This is the number of characters per line on the LCD in custom profile. | ||
596 | Common values are 16,20,24,40. | ||
597 | |||
598 | config PANEL_LCD_BWIDTH | ||
599 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" | ||
600 | int "Internal LCD line width (1-40, 40 by default)" | ||
601 | range 1 40 | ||
602 | default 40 | ||
603 | ---help--- | ||
604 | Most LCDs use a standard controller which supports hardware lines of 40 | ||
605 | characters, although sometimes only 16, 20 or 24 of them are really wired | ||
606 | to the terminal. This results in some non-visible but addressable characters, | ||
607 | and is the case for most parallel LCDs. Other LCDs, and some serial ones, | ||
608 | however, use the same line width internally as what is visible. The KS0074 | ||
609 | for example, uses 16 characters per line for 16 visible characters per line. | ||
610 | |||
611 | This option lets you configure the value used by your LCD in 'custom' profile. | ||
612 | If you don't know, put '40' here. | ||
613 | |||
614 | config PANEL_LCD_HWIDTH | ||
615 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" | ||
616 | int "Hardware LCD line width (1-64, 64 by default)" | ||
617 | range 1 64 | ||
618 | default 64 | ||
619 | ---help--- | ||
620 | Most LCDs use a single address bit to differentiate line 0 and line 1. Since | ||
621 | some of them need to be able to address 40 chars with the lower bits, they | ||
622 | often use the immediately superior power of 2, which is 64, to address the | ||
623 | next line. | ||
624 | |||
625 | If you don't know what your LCD uses, in doubt let 16 here for a 2x16, and | ||
626 | 64 here for a 2x40. | ||
627 | |||
628 | config PANEL_LCD_CHARSET | ||
629 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" | ||
630 | int "LCD character set (0=normal, 1=KS0074)" | ||
631 | range 0 1 | ||
632 | default 0 | ||
633 | ---help--- | ||
634 | Some controllers such as the KS0074 use a somewhat strange character set | ||
635 | where many symbols are at unusual places. The driver knows how to map | ||
636 | 'standard' ASCII characters to the character sets used by these controllers. | ||
637 | Valid values are : | ||
638 | |||
639 | 0 : normal (untranslated) character set | ||
640 | 1 : KS0074 character set | ||
641 | |||
642 | If you don't know, use the normal one (0). | ||
643 | |||
644 | config PANEL_LCD_PROTO | ||
645 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" | ||
646 | int "LCD communication mode (0=parallel 8 bits, 1=serial)" | ||
647 | range 0 1 | ||
648 | default 0 | ||
649 | ---help--- | ||
650 | This driver now supports any serial or parallel LCD wired to a parallel | ||
651 | port. But before assigning signals, the driver needs to know if it will | ||
652 | be driving a serial LCD or a parallel one. Serial LCDs only use 2 wires | ||
653 | (SDA/SCL), while parallel ones use 2 or 3 wires for the control signals | ||
654 | (E, RS, sometimes RW), and 4 or 8 for the data. Use 0 here for a 8 bits | ||
655 | parallel LCD, and 1 for a serial LCD. | ||
656 | |||
657 | config PANEL_LCD_PIN_E | ||
658 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" | ||
659 | int "Parallel port pin number & polarity connected to the LCD E signal (-17...17) " | ||
660 | range -17 17 | ||
661 | default 14 | ||
662 | ---help--- | 488 | ---help--- |
663 | This describes the number of the parallel port pin to which the LCD 'E' | 489 | Control Aspeed ast2400/2500 HOST LPC to BMC mappings through |
664 | signal has been connected. It can be : | 490 | ioctl()s, the driver also provides a read/write interface to a BMC ram |
665 | 491 | region where the host LPC read/write region can be buffered. | |
666 | 0 : no connection (eg: connected to ground) | ||
667 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
668 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
669 | |||
670 | Default for the 'E' pin in custom profile is '14' (AUTOFEED). | ||
671 | |||
672 | config PANEL_LCD_PIN_RS | ||
673 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" | ||
674 | int "Parallel port pin number & polarity connected to the LCD RS signal (-17...17) " | ||
675 | range -17 17 | ||
676 | default 17 | ||
677 | ---help--- | ||
678 | This describes the number of the parallel port pin to which the LCD 'RS' | ||
679 | signal has been connected. It can be : | ||
680 | |||
681 | 0 : no connection (eg: connected to ground) | ||
682 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
683 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
684 | |||
685 | Default for the 'RS' pin in custom profile is '17' (SELECT IN). | ||
686 | |||
687 | config PANEL_LCD_PIN_RW | ||
688 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" | ||
689 | int "Parallel port pin number & polarity connected to the LCD RW signal (-17...17) " | ||
690 | range -17 17 | ||
691 | default 16 | ||
692 | ---help--- | ||
693 | This describes the number of the parallel port pin to which the LCD 'RW' | ||
694 | signal has been connected. It can be : | ||
695 | |||
696 | 0 : no connection (eg: connected to ground) | ||
697 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
698 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
699 | |||
700 | Default for the 'RW' pin in custom profile is '16' (INIT). | ||
701 | |||
702 | config PANEL_LCD_PIN_SCL | ||
703 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0" | ||
704 | int "Parallel port pin number & polarity connected to the LCD SCL signal (-17...17) " | ||
705 | range -17 17 | ||
706 | default 1 | ||
707 | ---help--- | ||
708 | This describes the number of the parallel port pin to which the serial | ||
709 | LCD 'SCL' signal has been connected. It can be : | ||
710 | |||
711 | 0 : no connection (eg: connected to ground) | ||
712 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
713 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
714 | |||
715 | Default for the 'SCL' pin in custom profile is '1' (STROBE). | ||
716 | |||
717 | config PANEL_LCD_PIN_SDA | ||
718 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0" | ||
719 | int "Parallel port pin number & polarity connected to the LCD SDA signal (-17...17) " | ||
720 | range -17 17 | ||
721 | default 2 | ||
722 | ---help--- | ||
723 | This describes the number of the parallel port pin to which the serial | ||
724 | LCD 'SDA' signal has been connected. It can be : | ||
725 | |||
726 | 0 : no connection (eg: connected to ground) | ||
727 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
728 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
729 | |||
730 | Default for the 'SDA' pin in custom profile is '2' (D0). | ||
731 | |||
732 | config PANEL_LCD_PIN_BL | ||
733 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" | ||
734 | int "Parallel port pin number & polarity connected to the LCD backlight signal (-17...17) " | ||
735 | range -17 17 | ||
736 | default 0 | ||
737 | ---help--- | ||
738 | This describes the number of the parallel port pin to which the LCD 'BL' signal | ||
739 | has been connected. It can be : | ||
740 | |||
741 | 0 : no connection (eg: connected to ground) | ||
742 | 1..17 : directly connected to any of these pins on the DB25 plug | ||
743 | -1..-17 : connected to the same pin through an inverter (eg: transistor). | ||
744 | |||
745 | Default for the 'BL' pin in custom profile is '0' (uncontrolled). | ||
746 | |||
747 | config PANEL_CHANGE_MESSAGE | ||
748 | bool "Change LCD initialization message ?" | ||
749 | default "n" | ||
750 | ---help--- | ||
751 | This allows you to replace the boot message indicating the kernel version | ||
752 | and the driver version with a custom message. This is useful on appliances | ||
753 | where a simple 'Starting system' message can be enough to stop a customer | ||
754 | from worrying. | ||
755 | |||
756 | If you say 'Y' here, you'll be able to choose a message yourself. Otherwise, | ||
757 | say 'N' and keep the default message with the version. | ||
758 | |||
759 | config PANEL_BOOT_MESSAGE | ||
760 | depends on PANEL_CHANGE_MESSAGE="y" | ||
761 | string "New initialization message" | ||
762 | default "" | ||
763 | ---help--- | ||
764 | This allows you to replace the boot message indicating the kernel version | ||
765 | and the driver version with a custom message. This is useful on appliances | ||
766 | where a simple 'Starting system' message can be enough to stop a customer | ||
767 | from worrying. | ||
768 | |||
769 | An empty message will only clear the display at driver init time. Any other | ||
770 | printf()-formatted message is valid with newline and escape codes. | ||
771 | |||
772 | endif # PANEL | ||
773 | 492 | ||
774 | source "drivers/misc/c2port/Kconfig" | 493 | source "drivers/misc/c2port/Kconfig" |
775 | source "drivers/misc/eeprom/Kconfig" | 494 | 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/ | |||
37 | obj-y += cb710/ | 37 | obj-y += cb710/ |
38 | obj-$(CONFIG_SPEAR13XX_PCIE_GADGET) += spear13xx_pcie_gadget.o | 38 | obj-$(CONFIG_SPEAR13XX_PCIE_GADGET) += spear13xx_pcie_gadget.o |
39 | obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o | 39 | obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o |
40 | obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o | ||
41 | obj-$(CONFIG_PCH_PHUB) += pch_phub.o | 40 | obj-$(CONFIG_PCH_PHUB) += pch_phub.o |
42 | obj-y += ti-st/ | 41 | obj-y += ti-st/ |
43 | obj-y += lis3lv02d/ | 42 | obj-y += lis3lv02d/ |
@@ -53,7 +52,7 @@ obj-$(CONFIG_GENWQE) += genwqe/ | |||
53 | obj-$(CONFIG_ECHO) += echo/ | 52 | obj-$(CONFIG_ECHO) += echo/ |
54 | obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o | 53 | obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o |
55 | obj-$(CONFIG_CXL_BASE) += cxl/ | 54 | obj-$(CONFIG_CXL_BASE) += cxl/ |
56 | obj-$(CONFIG_PANEL) += panel.o | 55 | obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o |
57 | 56 | ||
58 | lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o | 57 | lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o |
59 | lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o | 58 | lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o |
@@ -62,6 +61,8 @@ lkdtm-$(CONFIG_LKDTM) += lkdtm_perms.o | |||
62 | lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o | 61 | lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o |
63 | lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o | 62 | lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o |
64 | 63 | ||
64 | KCOV_INSTRUMENT_lkdtm_rodata.o := n | ||
65 | |||
65 | OBJCOPYFLAGS := | 66 | OBJCOPYFLAGS := |
66 | OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \ | 67 | OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \ |
67 | --set-section-flags .text=alloc,readonly \ | 68 | --set-section-flags .text=alloc,readonly \ |
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 @@ | |||
1 | /* | ||
2 | * Copyright 2017 IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | |||
10 | #include <linux/mfd/syscon.h> | ||
11 | #include <linux/miscdevice.h> | ||
12 | #include <linux/mm.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/of_address.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/poll.h> | ||
17 | #include <linux/regmap.h> | ||
18 | |||
19 | #include <linux/aspeed-lpc-ctrl.h> | ||
20 | |||
21 | #define DEVICE_NAME "aspeed-lpc-ctrl" | ||
22 | |||
23 | #define HICR7 0x8 | ||
24 | #define HICR8 0xc | ||
25 | |||
26 | struct aspeed_lpc_ctrl { | ||
27 | struct miscdevice miscdev; | ||
28 | struct regmap *regmap; | ||
29 | phys_addr_t mem_base; | ||
30 | resource_size_t mem_size; | ||
31 | u32 pnor_size; | ||
32 | u32 pnor_base; | ||
33 | }; | ||
34 | |||
35 | static struct aspeed_lpc_ctrl *file_aspeed_lpc_ctrl(struct file *file) | ||
36 | { | ||
37 | return container_of(file->private_data, struct aspeed_lpc_ctrl, | ||
38 | miscdev); | ||
39 | } | ||
40 | |||
41 | static int aspeed_lpc_ctrl_mmap(struct file *file, struct vm_area_struct *vma) | ||
42 | { | ||
43 | struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file); | ||
44 | unsigned long vsize = vma->vm_end - vma->vm_start; | ||
45 | pgprot_t prot = vma->vm_page_prot; | ||
46 | |||
47 | if (vma->vm_pgoff + vsize > lpc_ctrl->mem_base + lpc_ctrl->mem_size) | ||
48 | return -EINVAL; | ||
49 | |||
50 | /* ast2400/2500 AHB accesses are not cache coherent */ | ||
51 | prot = pgprot_noncached(prot); | ||
52 | |||
53 | if (remap_pfn_range(vma, vma->vm_start, | ||
54 | (lpc_ctrl->mem_base >> PAGE_SHIFT) + vma->vm_pgoff, | ||
55 | vsize, prot)) | ||
56 | return -EAGAIN; | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd, | ||
62 | unsigned long param) | ||
63 | { | ||
64 | struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file); | ||
65 | void __user *p = (void __user *)param; | ||
66 | struct aspeed_lpc_ctrl_mapping map; | ||
67 | u32 addr; | ||
68 | u32 size; | ||
69 | long rc; | ||
70 | |||
71 | if (copy_from_user(&map, p, sizeof(map))) | ||
72 | return -EFAULT; | ||
73 | |||
74 | if (map.flags != 0) | ||
75 | return -EINVAL; | ||
76 | |||
77 | switch (cmd) { | ||
78 | case ASPEED_LPC_CTRL_IOCTL_GET_SIZE: | ||
79 | /* The flash windows don't report their size */ | ||
80 | if (map.window_type != ASPEED_LPC_CTRL_WINDOW_MEMORY) | ||
81 | return -EINVAL; | ||
82 | |||
83 | /* Support more than one window id in the future */ | ||
84 | if (map.window_id != 0) | ||
85 | return -EINVAL; | ||
86 | |||
87 | map.size = lpc_ctrl->mem_size; | ||
88 | |||
89 | return copy_to_user(p, &map, sizeof(map)) ? -EFAULT : 0; | ||
90 | case ASPEED_LPC_CTRL_IOCTL_MAP: | ||
91 | |||
92 | /* | ||
93 | * The top half of HICR7 is the MSB of the BMC address of the | ||
94 | * mapping. | ||
95 | * The bottom half of HICR7 is the MSB of the HOST LPC | ||
96 | * firmware space address of the mapping. | ||
97 | * | ||
98 | * The 1 bits in the top of half of HICR8 represent the bits | ||
99 | * (in the requested address) that should be ignored and | ||
100 | * replaced with those from the top half of HICR7. | ||
101 | * The 1 bits in the bottom half of HICR8 represent the bits | ||
102 | * (in the requested address) that should be kept and pass | ||
103 | * into the BMC address space. | ||
104 | */ | ||
105 | |||
106 | /* | ||
107 | * It doesn't make sense to talk about a size or offset with | ||
108 | * low 16 bits set. Both HICR7 and HICR8 talk about the top 16 | ||
109 | * bits of addresses and sizes. | ||
110 | */ | ||
111 | |||
112 | if ((map.size & 0x0000ffff) || (map.offset & 0x0000ffff)) | ||
113 | return -EINVAL; | ||
114 | |||
115 | /* | ||
116 | * Because of the way the masks work in HICR8 offset has to | ||
117 | * be a multiple of size. | ||
118 | */ | ||
119 | if (map.offset & (map.size - 1)) | ||
120 | return -EINVAL; | ||
121 | |||
122 | if (map.window_type == ASPEED_LPC_CTRL_WINDOW_FLASH) { | ||
123 | addr = lpc_ctrl->pnor_base; | ||
124 | size = lpc_ctrl->pnor_size; | ||
125 | } else if (map.window_type == ASPEED_LPC_CTRL_WINDOW_MEMORY) { | ||
126 | addr = lpc_ctrl->mem_base; | ||
127 | size = lpc_ctrl->mem_size; | ||
128 | } else { | ||
129 | return -EINVAL; | ||
130 | } | ||
131 | |||
132 | /* Check overflow first! */ | ||
133 | if (map.offset + map.size < map.offset || | ||
134 | map.offset + map.size > size) | ||
135 | return -EINVAL; | ||
136 | |||
137 | if (map.size == 0 || map.size > size) | ||
138 | return -EINVAL; | ||
139 | |||
140 | addr += map.offset; | ||
141 | |||
142 | /* | ||
143 | * addr (host lpc address) is safe regardless of values. This | ||
144 | * simply changes the address the host has to request on its | ||
145 | * side of the LPC bus. This cannot impact the hosts own | ||
146 | * memory space by surprise as LPC specific accessors are | ||
147 | * required. The only strange thing that could be done is | ||
148 | * setting the lower 16 bits but the shift takes care of that. | ||
149 | */ | ||
150 | |||
151 | rc = regmap_write(lpc_ctrl->regmap, HICR7, | ||
152 | (addr | (map.addr >> 16))); | ||
153 | if (rc) | ||
154 | return rc; | ||
155 | |||
156 | return regmap_write(lpc_ctrl->regmap, HICR8, | ||
157 | (~(map.size - 1)) | ((map.size >> 16) - 1)); | ||
158 | } | ||
159 | |||
160 | return -EINVAL; | ||
161 | } | ||
162 | |||
163 | static const struct file_operations aspeed_lpc_ctrl_fops = { | ||
164 | .owner = THIS_MODULE, | ||
165 | .mmap = aspeed_lpc_ctrl_mmap, | ||
166 | .unlocked_ioctl = aspeed_lpc_ctrl_ioctl, | ||
167 | }; | ||
168 | |||
169 | static int aspeed_lpc_ctrl_probe(struct platform_device *pdev) | ||
170 | { | ||
171 | struct aspeed_lpc_ctrl *lpc_ctrl; | ||
172 | struct device_node *node; | ||
173 | struct resource resm; | ||
174 | struct device *dev; | ||
175 | int rc; | ||
176 | |||
177 | dev = &pdev->dev; | ||
178 | |||
179 | lpc_ctrl = devm_kzalloc(dev, sizeof(*lpc_ctrl), GFP_KERNEL); | ||
180 | if (!lpc_ctrl) | ||
181 | return -ENOMEM; | ||
182 | |||
183 | node = of_parse_phandle(dev->of_node, "flash", 0); | ||
184 | if (!node) { | ||
185 | dev_err(dev, "Didn't find host pnor flash node\n"); | ||
186 | return -ENODEV; | ||
187 | } | ||
188 | |||
189 | rc = of_address_to_resource(node, 1, &resm); | ||
190 | of_node_put(node); | ||
191 | if (rc) { | ||
192 | dev_err(dev, "Couldn't address to resource for flash\n"); | ||
193 | return rc; | ||
194 | } | ||
195 | |||
196 | lpc_ctrl->pnor_size = resource_size(&resm); | ||
197 | lpc_ctrl->pnor_base = resm.start; | ||
198 | |||
199 | dev_set_drvdata(&pdev->dev, lpc_ctrl); | ||
200 | |||
201 | node = of_parse_phandle(dev->of_node, "memory-region", 0); | ||
202 | if (!node) { | ||
203 | dev_err(dev, "Didn't find reserved memory\n"); | ||
204 | return -EINVAL; | ||
205 | } | ||
206 | |||
207 | rc = of_address_to_resource(node, 0, &resm); | ||
208 | of_node_put(node); | ||
209 | if (rc) { | ||
210 | dev_err(dev, "Couldn't address to resource for reserved memory\n"); | ||
211 | return -ENOMEM; | ||
212 | } | ||
213 | |||
214 | lpc_ctrl->mem_size = resource_size(&resm); | ||
215 | lpc_ctrl->mem_base = resm.start; | ||
216 | |||
217 | lpc_ctrl->regmap = syscon_node_to_regmap( | ||
218 | pdev->dev.parent->of_node); | ||
219 | if (IS_ERR(lpc_ctrl->regmap)) { | ||
220 | dev_err(dev, "Couldn't get regmap\n"); | ||
221 | return -ENODEV; | ||
222 | } | ||
223 | |||
224 | lpc_ctrl->miscdev.minor = MISC_DYNAMIC_MINOR; | ||
225 | lpc_ctrl->miscdev.name = DEVICE_NAME; | ||
226 | lpc_ctrl->miscdev.fops = &aspeed_lpc_ctrl_fops; | ||
227 | lpc_ctrl->miscdev.parent = dev; | ||
228 | rc = misc_register(&lpc_ctrl->miscdev); | ||
229 | if (rc) | ||
230 | dev_err(dev, "Unable to register device\n"); | ||
231 | else | ||
232 | dev_info(dev, "Loaded at %pr\n", &resm); | ||
233 | |||
234 | return rc; | ||
235 | } | ||
236 | |||
237 | static int aspeed_lpc_ctrl_remove(struct platform_device *pdev) | ||
238 | { | ||
239 | struct aspeed_lpc_ctrl *lpc_ctrl = dev_get_drvdata(&pdev->dev); | ||
240 | |||
241 | misc_deregister(&lpc_ctrl->miscdev); | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static const struct of_device_id aspeed_lpc_ctrl_match[] = { | ||
247 | { .compatible = "aspeed,ast2400-lpc-ctrl" }, | ||
248 | { .compatible = "aspeed,ast2500-lpc-ctrl" }, | ||
249 | { }, | ||
250 | }; | ||
251 | |||
252 | static struct platform_driver aspeed_lpc_ctrl_driver = { | ||
253 | .driver = { | ||
254 | .name = DEVICE_NAME, | ||
255 | .of_match_table = aspeed_lpc_ctrl_match, | ||
256 | }, | ||
257 | .probe = aspeed_lpc_ctrl_probe, | ||
258 | .remove = aspeed_lpc_ctrl_remove, | ||
259 | }; | ||
260 | |||
261 | module_platform_driver(aspeed_lpc_ctrl_driver); | ||
262 | |||
263 | MODULE_DEVICE_TABLE(of, aspeed_lpc_ctrl_match); | ||
264 | MODULE_LICENSE("GPL"); | ||
265 | MODULE_AUTHOR("Cyril Bur <cyrilbur@gmail.com>"); | ||
266 | 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[] = { | |||
227 | }; | 227 | }; |
228 | MODULE_DEVICE_TABLE(i2c, ds1682_id); | 228 | MODULE_DEVICE_TABLE(i2c, ds1682_id); |
229 | 229 | ||
230 | static const struct of_device_id ds1682_of_match[] = { | ||
231 | { .compatible = "dallas,ds1682", }, | ||
232 | {} | ||
233 | }; | ||
234 | MODULE_DEVICE_TABLE(of, ds1682_of_match); | ||
235 | |||
230 | static struct i2c_driver ds1682_driver = { | 236 | static struct i2c_driver ds1682_driver = { |
231 | .driver = { | 237 | .driver = { |
232 | .name = "ds1682", | 238 | .name = "ds1682", |
239 | .of_match_table = ds1682_of_match, | ||
233 | }, | 240 | }, |
234 | .probe = ds1682_probe, | 241 | .probe = ds1682_probe, |
235 | .remove = ds1682_remove, | 242 | .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[] = { | |||
1541 | }; | 1541 | }; |
1542 | MODULE_DEVICE_TABLE(i2c, idt_ids); | 1542 | MODULE_DEVICE_TABLE(i2c, idt_ids); |
1543 | 1543 | ||
1544 | static const struct of_device_id idt_of_match[] = { | ||
1545 | { .compatible = "idt,89hpes8nt2", }, | ||
1546 | { .compatible = "idt,89hpes12nt3", }, | ||
1547 | |||
1548 | { .compatible = "idt,89hpes24nt6ag2", }, | ||
1549 | { .compatible = "idt,89hpes32nt8ag2", }, | ||
1550 | { .compatible = "idt,89hpes32nt8bg2", }, | ||
1551 | { .compatible = "idt,89hpes12nt12g2", }, | ||
1552 | { .compatible = "idt,89hpes16nt16g2", }, | ||
1553 | { .compatible = "idt,89hpes24nt24g2", }, | ||
1554 | { .compatible = "idt,89hpes32nt24ag2", }, | ||
1555 | { .compatible = "idt,89hpes32nt24bg2", }, | ||
1556 | |||
1557 | { .compatible = "idt,89hpes12n3", }, | ||
1558 | { .compatible = "idt,89hpes12n3a", }, | ||
1559 | { .compatible = "idt,89hpes24n3", }, | ||
1560 | { .compatible = "idt,89hpes24n3a", }, | ||
1561 | |||
1562 | { .compatible = "idt,89hpes32h8", }, | ||
1563 | { .compatible = "idt,89hpes32h8g2", }, | ||
1564 | { .compatible = "idt,89hpes48h12", }, | ||
1565 | { .compatible = "idt,89hpes48h12g2", }, | ||
1566 | { .compatible = "idt,89hpes48h12ag2", }, | ||
1567 | { .compatible = "idt,89hpes16h16", }, | ||
1568 | { .compatible = "idt,89hpes22h16", }, | ||
1569 | { .compatible = "idt,89hpes22h16g2", }, | ||
1570 | { .compatible = "idt,89hpes34h16", }, | ||
1571 | { .compatible = "idt,89hpes34h16g2", }, | ||
1572 | { .compatible = "idt,89hpes64h16", }, | ||
1573 | { .compatible = "idt,89hpes64h16g2", }, | ||
1574 | { .compatible = "idt,89hpes64h16ag2", }, | ||
1575 | |||
1576 | { .compatible = "idt,89hpes12t3g2", }, | ||
1577 | { .compatible = "idt,89hpes24t3g2", }, | ||
1578 | |||
1579 | { .compatible = "idt,89hpes16t4", }, | ||
1580 | { .compatible = "idt,89hpes4t4g2", }, | ||
1581 | { .compatible = "idt,89hpes10t4g2", }, | ||
1582 | { .compatible = "idt,89hpes16t4g2", }, | ||
1583 | { .compatible = "idt,89hpes16t4ag2", }, | ||
1584 | { .compatible = "idt,89hpes5t5", }, | ||
1585 | { .compatible = "idt,89hpes6t5", }, | ||
1586 | { .compatible = "idt,89hpes8t5", }, | ||
1587 | { .compatible = "idt,89hpes8t5a", }, | ||
1588 | { .compatible = "idt,89hpes24t6", }, | ||
1589 | { .compatible = "idt,89hpes6t6g2", }, | ||
1590 | { .compatible = "idt,89hpes24t6g2", }, | ||
1591 | { .compatible = "idt,89hpes16t7", }, | ||
1592 | { .compatible = "idt,89hpes32t8", }, | ||
1593 | { .compatible = "idt,89hpes32t8g2", }, | ||
1594 | { .compatible = "idt,89hpes48t12", }, | ||
1595 | { .compatible = "idt,89hpes48t12g2", }, | ||
1596 | { }, | ||
1597 | }; | ||
1598 | MODULE_DEVICE_TABLE(of, idt_of_match); | ||
1599 | |||
1544 | /* | 1600 | /* |
1545 | * idt_driver - IDT 89HPESx driver structure | 1601 | * idt_driver - IDT 89HPESx driver structure |
1546 | */ | 1602 | */ |
1547 | static struct i2c_driver idt_driver = { | 1603 | static struct i2c_driver idt_driver = { |
1548 | .driver = { | 1604 | .driver = { |
1549 | .name = IDT_NAME, | 1605 | .name = IDT_NAME, |
1606 | .of_match_table = idt_of_match, | ||
1550 | }, | 1607 | }, |
1551 | .probe = idt_probe, | 1608 | .probe = idt_probe, |
1552 | .remove = idt_remove, | 1609 | .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); | |||
27 | void lkdtm_REFCOUNT_ZERO_ADD(void); | 27 | void lkdtm_REFCOUNT_ZERO_ADD(void); |
28 | void lkdtm_CORRUPT_LIST_ADD(void); | 28 | void lkdtm_CORRUPT_LIST_ADD(void); |
29 | void lkdtm_CORRUPT_LIST_DEL(void); | 29 | void lkdtm_CORRUPT_LIST_DEL(void); |
30 | void lkdtm_CORRUPT_USER_DS(void); | ||
30 | 31 | ||
31 | /* lkdtm_heap.c */ | 32 | /* lkdtm_heap.c */ |
32 | void lkdtm_OVERWRITE_ALLOCATION(void); | 33 | 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 @@ | |||
8 | #include <linux/list.h> | 8 | #include <linux/list.h> |
9 | #include <linux/refcount.h> | 9 | #include <linux/refcount.h> |
10 | #include <linux/sched.h> | 10 | #include <linux/sched.h> |
11 | #include <linux/sched/signal.h> | ||
12 | #include <linux/uaccess.h> | ||
11 | 13 | ||
12 | struct lkdtm_list { | 14 | struct lkdtm_list { |
13 | struct list_head node; | 15 | struct list_head node; |
@@ -67,7 +69,7 @@ void lkdtm_WARNING(void) | |||
67 | 69 | ||
68 | void lkdtm_EXCEPTION(void) | 70 | void lkdtm_EXCEPTION(void) |
69 | { | 71 | { |
70 | *((int *) 0) = 0; | 72 | *((volatile int *) 0) = 0; |
71 | } | 73 | } |
72 | 74 | ||
73 | void lkdtm_LOOP(void) | 75 | void lkdtm_LOOP(void) |
@@ -279,3 +281,12 @@ void lkdtm_CORRUPT_LIST_DEL(void) | |||
279 | else | 281 | else |
280 | pr_err("list_del() corruption not detected!\n"); | 282 | pr_err("list_del() corruption not detected!\n"); |
281 | } | 283 | } |
284 | |||
285 | void lkdtm_CORRUPT_USER_DS(void) | ||
286 | { | ||
287 | pr_info("setting bad task size limit\n"); | ||
288 | set_fs(KERNEL_DS); | ||
289 | |||
290 | /* Make sure we do not keep running with a KERNEL_DS! */ | ||
291 | force_sig(SIGKILL, current); | ||
292 | } | ||
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[] = { | |||
199 | CRASHTYPE(OVERFLOW), | 199 | CRASHTYPE(OVERFLOW), |
200 | CRASHTYPE(CORRUPT_LIST_ADD), | 200 | CRASHTYPE(CORRUPT_LIST_ADD), |
201 | CRASHTYPE(CORRUPT_LIST_DEL), | 201 | CRASHTYPE(CORRUPT_LIST_DEL), |
202 | CRASHTYPE(CORRUPT_USER_DS), | ||
202 | CRASHTYPE(CORRUPT_STACK), | 203 | CRASHTYPE(CORRUPT_STACK), |
203 | CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE), | 204 | CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE), |
204 | CRASHTYPE(OVERWRITE_ALLOCATION), | 205 | 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 | |||
8 | mei-objs += interrupt.o | 8 | mei-objs += interrupt.o |
9 | mei-objs += client.o | 9 | mei-objs += client.o |
10 | mei-objs += main.o | 10 | mei-objs += main.o |
11 | mei-objs += amthif.o | ||
12 | mei-objs += bus.o | 11 | mei-objs += bus.o |
13 | mei-objs += bus-fixup.o | 12 | mei-objs += bus-fixup.o |
14 | mei-$(CONFIG_DEBUG_FS) += debugfs.o | 13 | 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 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Intel Management Engine Interface (Intel MEI) Linux driver | ||
4 | * Copyright (c) 2003-2012, Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/fs.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/fcntl.h> | ||
22 | #include <linux/ioctl.h> | ||
23 | #include <linux/cdev.h> | ||
24 | #include <linux/list.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/uuid.h> | ||
28 | #include <linux/jiffies.h> | ||
29 | #include <linux/uaccess.h> | ||
30 | #include <linux/slab.h> | ||
31 | |||
32 | #include <linux/mei.h> | ||
33 | |||
34 | #include "mei_dev.h" | ||
35 | #include "hbm.h" | ||
36 | #include "client.h" | ||
37 | |||
38 | const uuid_le mei_amthif_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, | ||
39 | 0xac, 0xa8, 0x46, 0xe0, | ||
40 | 0xff, 0x65, 0x81, 0x4c); | ||
41 | |||
42 | /** | ||
43 | * mei_amthif_reset_params - initializes mei device iamthif | ||
44 | * | ||
45 | * @dev: the device structure | ||
46 | */ | ||
47 | void mei_amthif_reset_params(struct mei_device *dev) | ||
48 | { | ||
49 | /* reset iamthif parameters. */ | ||
50 | dev->iamthif_canceled = false; | ||
51 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
52 | dev->iamthif_stall_timer = 0; | ||
53 | dev->iamthif_open_count = 0; | ||
54 | } | ||
55 | |||
56 | /** | ||
57 | * mei_amthif_host_init - mei initialization amthif client. | ||
58 | * | ||
59 | * @dev: the device structure | ||
60 | * @me_cl: me client | ||
61 | * | ||
62 | * Return: 0 on success, <0 on failure. | ||
63 | */ | ||
64 | int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl) | ||
65 | { | ||
66 | struct mei_cl *cl = &dev->iamthif_cl; | ||
67 | int ret; | ||
68 | |||
69 | mutex_lock(&dev->device_lock); | ||
70 | |||
71 | if (mei_cl_is_connected(cl)) { | ||
72 | ret = 0; | ||
73 | goto out; | ||
74 | } | ||
75 | |||
76 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
77 | |||
78 | mei_cl_init(cl, dev); | ||
79 | |||
80 | ret = mei_cl_link(cl); | ||
81 | if (ret < 0) { | ||
82 | dev_err(dev->dev, "amthif: failed cl_link %d\n", ret); | ||
83 | goto out; | ||
84 | } | ||
85 | |||
86 | ret = mei_cl_connect(cl, me_cl, NULL); | ||
87 | |||
88 | out: | ||
89 | mutex_unlock(&dev->device_lock); | ||
90 | return ret; | ||
91 | } | ||
92 | |||
93 | /** | ||
94 | * mei_amthif_read_start - queue message for sending read credential | ||
95 | * | ||
96 | * @cl: host client | ||
97 | * @fp: file pointer of message recipient | ||
98 | * | ||
99 | * Return: 0 on success, <0 on failure. | ||
100 | */ | ||
101 | static int mei_amthif_read_start(struct mei_cl *cl, const struct file *fp) | ||
102 | { | ||
103 | struct mei_device *dev = cl->dev; | ||
104 | struct mei_cl_cb *cb; | ||
105 | |||
106 | cb = mei_cl_enqueue_ctrl_wr_cb(cl, mei_cl_mtu(cl), MEI_FOP_READ, fp); | ||
107 | if (!cb) | ||
108 | return -ENOMEM; | ||
109 | |||
110 | cl->rx_flow_ctrl_creds++; | ||
111 | |||
112 | dev->iamthif_state = MEI_IAMTHIF_READING; | ||
113 | cl->fp = cb->fp; | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | /** | ||
119 | * mei_amthif_run_next_cmd - send next amt command from queue | ||
120 | * | ||
121 | * @dev: the device structure | ||
122 | * | ||
123 | * Return: 0 on success, <0 on failure. | ||
124 | */ | ||
125 | int mei_amthif_run_next_cmd(struct mei_device *dev) | ||
126 | { | ||
127 | struct mei_cl *cl = &dev->iamthif_cl; | ||
128 | struct mei_cl_cb *cb; | ||
129 | int ret; | ||
130 | |||
131 | dev->iamthif_canceled = false; | ||
132 | |||
133 | dev_dbg(dev->dev, "complete amthif cmd_list cb.\n"); | ||
134 | |||
135 | cb = list_first_entry_or_null(&dev->amthif_cmd_list, typeof(*cb), list); | ||
136 | if (!cb) { | ||
137 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
138 | cl->fp = NULL; | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | list_del_init(&cb->list); | ||
143 | dev->iamthif_state = MEI_IAMTHIF_WRITING; | ||
144 | cl->fp = cb->fp; | ||
145 | |||
146 | ret = mei_cl_write(cl, cb); | ||
147 | if (ret < 0) | ||
148 | return ret; | ||
149 | |||
150 | if (cb->completed) | ||
151 | cb->status = mei_amthif_read_start(cl, cb->fp); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * mei_amthif_write - write amthif data to amthif client | ||
158 | * | ||
159 | * @cl: host client | ||
160 | * @cb: mei call back struct | ||
161 | * | ||
162 | * Return: 0 on success, <0 on failure. | ||
163 | */ | ||
164 | int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb) | ||
165 | { | ||
166 | |||
167 | struct mei_device *dev = cl->dev; | ||
168 | |||
169 | list_add_tail(&cb->list, &dev->amthif_cmd_list); | ||
170 | |||
171 | /* | ||
172 | * The previous request is still in processing, queue this one. | ||
173 | */ | ||
174 | if (dev->iamthif_state != MEI_IAMTHIF_IDLE) | ||
175 | return 0; | ||
176 | |||
177 | return mei_amthif_run_next_cmd(dev); | ||
178 | } | ||
179 | |||
180 | /** | ||
181 | * mei_amthif_poll - the amthif poll function | ||
182 | * | ||
183 | * @file: pointer to file structure | ||
184 | * @wait: pointer to poll_table structure | ||
185 | * | ||
186 | * Return: poll mask | ||
187 | * | ||
188 | * Locking: called under "dev->device_lock" lock | ||
189 | */ | ||
190 | unsigned int mei_amthif_poll(struct file *file, poll_table *wait) | ||
191 | { | ||
192 | struct mei_cl *cl = file->private_data; | ||
193 | struct mei_cl_cb *cb = mei_cl_read_cb(cl, file); | ||
194 | unsigned int mask = 0; | ||
195 | |||
196 | poll_wait(file, &cl->rx_wait, wait); | ||
197 | if (cb) | ||
198 | mask |= POLLIN | POLLRDNORM; | ||
199 | |||
200 | return mask; | ||
201 | } | ||
202 | |||
203 | /** | ||
204 | * mei_amthif_irq_write - write iamthif command in irq thread context. | ||
205 | * | ||
206 | * @cl: private data of the file object. | ||
207 | * @cb: callback block. | ||
208 | * @cmpl_list: complete list. | ||
209 | * | ||
210 | * Return: 0, OK; otherwise, error. | ||
211 | */ | ||
212 | int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, | ||
213 | struct list_head *cmpl_list) | ||
214 | { | ||
215 | int ret; | ||
216 | |||
217 | ret = mei_cl_irq_write(cl, cb, cmpl_list); | ||
218 | if (ret) | ||
219 | return ret; | ||
220 | |||
221 | if (cb->completed) | ||
222 | cb->status = mei_amthif_read_start(cl, cb->fp); | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | /** | ||
228 | * mei_amthif_irq_read_msg - read routine after ISR to | ||
229 | * handle the read amthif message | ||
230 | * | ||
231 | * @cl: mei client | ||
232 | * @mei_hdr: header of amthif message | ||
233 | * @cmpl_list: completed callbacks list | ||
234 | * | ||
235 | * Return: -ENODEV if cb is NULL 0 otherwise; error message is in cb->status | ||
236 | */ | ||
237 | int mei_amthif_irq_read_msg(struct mei_cl *cl, | ||
238 | struct mei_msg_hdr *mei_hdr, | ||
239 | struct list_head *cmpl_list) | ||
240 | { | ||
241 | struct mei_device *dev; | ||
242 | int ret; | ||
243 | |||
244 | dev = cl->dev; | ||
245 | |||
246 | if (dev->iamthif_state != MEI_IAMTHIF_READING) { | ||
247 | mei_irq_discard_msg(dev, mei_hdr); | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list); | ||
252 | if (ret) | ||
253 | return ret; | ||
254 | |||
255 | if (!mei_hdr->msg_complete) | ||
256 | return 0; | ||
257 | |||
258 | dev_dbg(dev->dev, "completed amthif read.\n "); | ||
259 | dev->iamthif_stall_timer = 0; | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | /** | ||
265 | * mei_amthif_complete - complete amthif callback. | ||
266 | * | ||
267 | * @cl: host client | ||
268 | * @cb: callback block. | ||
269 | */ | ||
270 | void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb) | ||
271 | { | ||
272 | struct mei_device *dev = cl->dev; | ||
273 | |||
274 | dev_dbg(dev->dev, "completing amthif call back.\n"); | ||
275 | switch (cb->fop_type) { | ||
276 | case MEI_FOP_WRITE: | ||
277 | if (!cb->status) { | ||
278 | dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER; | ||
279 | mei_schedule_stall_timer(dev); | ||
280 | mei_io_cb_free(cb); | ||
281 | return; | ||
282 | } | ||
283 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
284 | cl->fp = NULL; | ||
285 | if (!dev->iamthif_canceled) { | ||
286 | /* | ||
287 | * in case of error enqueue the write cb to complete | ||
288 | * read list so it can be propagated to the reader | ||
289 | */ | ||
290 | list_add_tail(&cb->list, &cl->rd_completed); | ||
291 | wake_up_interruptible(&cl->rx_wait); | ||
292 | } else { | ||
293 | mei_io_cb_free(cb); | ||
294 | } | ||
295 | break; | ||
296 | case MEI_FOP_READ: | ||
297 | if (!dev->iamthif_canceled) { | ||
298 | list_add_tail(&cb->list, &cl->rd_completed); | ||
299 | dev_dbg(dev->dev, "amthif read completed\n"); | ||
300 | wake_up_interruptible(&cl->rx_wait); | ||
301 | } else { | ||
302 | mei_io_cb_free(cb); | ||
303 | } | ||
304 | |||
305 | dev->iamthif_stall_timer = 0; | ||
306 | mei_amthif_run_next_cmd(dev); | ||
307 | break; | ||
308 | default: | ||
309 | WARN_ON(1); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | /** | ||
314 | * mei_amthif_release - the release function | ||
315 | * | ||
316 | * @dev: device structure | ||
317 | * @fp: pointer to file structure | ||
318 | * | ||
319 | * Return: 0 on success, <0 on error | ||
320 | */ | ||
321 | int mei_amthif_release(struct mei_device *dev, struct file *fp) | ||
322 | { | ||
323 | struct mei_cl *cl = fp->private_data; | ||
324 | |||
325 | if (dev->iamthif_open_count > 0) | ||
326 | dev->iamthif_open_count--; | ||
327 | |||
328 | if (cl->fp == fp && dev->iamthif_state != MEI_IAMTHIF_IDLE) { | ||
329 | |||
330 | dev_dbg(dev->dev, "amthif canceled iamthif state %d\n", | ||
331 | dev->iamthif_state); | ||
332 | dev->iamthif_canceled = true; | ||
333 | } | ||
334 | |||
335 | /* Don't clean ctrl_rd_list here, the reads has to be completed */ | ||
336 | mei_io_list_free_fp(&dev->amthif_cmd_list, fp); | ||
337 | mei_io_list_free_fp(&cl->rd_completed, fp); | ||
338 | |||
339 | return 0; | ||
340 | } | ||
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 { | |||
110 | u8 data[0]; | 110 | u8 data[0]; |
111 | } __packed; | 111 | } __packed; |
112 | 112 | ||
113 | #define MKHI_OSVER_BUF_LEN (sizeof(struct mkhi_msg_hdr) + \ | ||
114 | sizeof(struct mkhi_fwcaps) + \ | ||
115 | sizeof(struct mei_os_ver)) | ||
113 | static int mei_osver(struct mei_cl_device *cldev) | 116 | static int mei_osver(struct mei_cl_device *cldev) |
114 | { | 117 | { |
115 | const size_t size = sizeof(struct mkhi_msg_hdr) + | 118 | const size_t size = MKHI_OSVER_BUF_LEN; |
116 | sizeof(struct mkhi_fwcaps) + | 119 | char buf[MKHI_OSVER_BUF_LEN]; |
117 | sizeof(struct mei_os_ver); | ||
118 | char buf[size]; | ||
119 | struct mkhi_msg *req; | 120 | struct mkhi_msg *req; |
120 | struct mkhi_fwcaps *fwcaps; | 121 | struct mkhi_fwcaps *fwcaps; |
121 | struct mei_os_ver *os_ver; | 122 | 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) | |||
1076 | { | 1076 | { |
1077 | struct mei_device *bus = | 1077 | struct mei_device *bus = |
1078 | container_of(work, struct mei_device, bus_rescan_work); | 1078 | container_of(work, struct mei_device, bus_rescan_work); |
1079 | struct mei_me_client *me_cl; | ||
1080 | |||
1081 | me_cl = mei_me_cl_by_uuid(bus, &mei_amthif_guid); | ||
1082 | if (me_cl) | ||
1083 | mei_amthif_host_init(bus, me_cl); | ||
1084 | mei_me_cl_put(me_cl); | ||
1085 | 1079 | ||
1086 | mei_cl_bus_rescan(bus); | 1080 | mei_cl_bus_rescan(bus); |
1087 | } | 1081 | } |
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, | |||
428 | * @head: io list | 428 | * @head: io list |
429 | * @fp: file pointer (matching cb file object), may be NULL | 429 | * @fp: file pointer (matching cb file object), may be NULL |
430 | */ | 430 | */ |
431 | void mei_io_list_free_fp(struct list_head *head, const struct file *fp) | 431 | static void mei_io_list_free_fp(struct list_head *head, const struct file *fp) |
432 | { | 432 | { |
433 | struct mei_cl_cb *cb, *next; | 433 | struct mei_cl_cb *cb, *next; |
434 | 434 | ||
@@ -554,7 +554,7 @@ int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp) | |||
554 | * @cl: host client to be initialized | 554 | * @cl: host client to be initialized |
555 | * @dev: mei device | 555 | * @dev: mei device |
556 | */ | 556 | */ |
557 | void mei_cl_init(struct mei_cl *cl, struct mei_device *dev) | 557 | static void mei_cl_init(struct mei_cl *cl, struct mei_device *dev) |
558 | { | 558 | { |
559 | memset(cl, 0, sizeof(struct mei_cl)); | 559 | memset(cl, 0, sizeof(struct mei_cl)); |
560 | init_waitqueue_head(&cl->wait); | 560 | init_waitqueue_head(&cl->wait); |
@@ -600,7 +600,6 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev) | |||
600 | int mei_cl_link(struct mei_cl *cl) | 600 | int mei_cl_link(struct mei_cl *cl) |
601 | { | 601 | { |
602 | struct mei_device *dev; | 602 | struct mei_device *dev; |
603 | long open_handle_count; | ||
604 | int id; | 603 | int id; |
605 | 604 | ||
606 | if (WARN_ON(!cl || !cl->dev)) | 605 | if (WARN_ON(!cl || !cl->dev)) |
@@ -614,8 +613,7 @@ int mei_cl_link(struct mei_cl *cl) | |||
614 | return -EMFILE; | 613 | return -EMFILE; |
615 | } | 614 | } |
616 | 615 | ||
617 | open_handle_count = dev->open_handle_count + dev->iamthif_open_count; | 616 | if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) { |
618 | if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) { | ||
619 | dev_err(dev->dev, "open_handle_count exceeded %d", | 617 | dev_err(dev->dev, "open_handle_count exceeded %d", |
620 | MEI_MAX_OPEN_HANDLE_COUNT); | 618 | MEI_MAX_OPEN_HANDLE_COUNT); |
621 | return -EMFILE; | 619 | return -EMFILE; |
@@ -649,8 +647,7 @@ int mei_cl_unlink(struct mei_cl *cl) | |||
649 | if (!cl) | 647 | if (!cl) |
650 | return 0; | 648 | return 0; |
651 | 649 | ||
652 | /* amthif might not be initialized */ | 650 | if (WARN_ON(!cl->dev)) |
653 | if (!cl->dev) | ||
654 | return 0; | 651 | return 0; |
655 | 652 | ||
656 | dev = cl->dev; | 653 | dev = cl->dev; |
@@ -763,7 +760,6 @@ static void mei_cl_set_disconnected(struct mei_cl *cl) | |||
763 | mei_io_list_free_cl(&dev->write_waiting_list, cl); | 760 | mei_io_list_free_cl(&dev->write_waiting_list, cl); |
764 | mei_io_list_flush_cl(&dev->ctrl_rd_list, cl); | 761 | mei_io_list_flush_cl(&dev->ctrl_rd_list, cl); |
765 | mei_io_list_flush_cl(&dev->ctrl_wr_list, cl); | 762 | mei_io_list_flush_cl(&dev->ctrl_wr_list, cl); |
766 | mei_io_list_free_cl(&dev->amthif_cmd_list, cl); | ||
767 | mei_cl_wake_all(cl); | 763 | mei_cl_wake_all(cl); |
768 | cl->rx_flow_ctrl_creds = 0; | 764 | cl->rx_flow_ctrl_creds = 0; |
769 | cl->tx_flow_ctrl_creds = 0; | 765 | 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) | |||
1478 | return -ENOTTY; | 1474 | return -ENOTTY; |
1479 | } | 1475 | } |
1480 | 1476 | ||
1481 | if (mei_cl_is_fixed_address(cl) || cl == &dev->iamthif_cl) | 1477 | if (mei_cl_is_fixed_address(cl)) |
1482 | return 0; | 1478 | return 0; |
1483 | 1479 | ||
1484 | /* HW currently supports only one pending read */ | 1480 | /* 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) | |||
83 | * MEI IO Functions | 83 | * MEI IO Functions |
84 | */ | 84 | */ |
85 | void mei_io_cb_free(struct mei_cl_cb *priv_cb); | 85 | void mei_io_cb_free(struct mei_cl_cb *priv_cb); |
86 | void mei_io_list_free_fp(struct list_head *head, const struct file *fp); | ||
87 | 86 | ||
88 | /* | 87 | /* |
89 | * MEI Host Client Functions | 88 | * MEI Host Client Functions |
90 | */ | 89 | */ |
91 | 90 | ||
92 | struct mei_cl *mei_cl_allocate(struct mei_device *dev); | 91 | struct mei_cl *mei_cl_allocate(struct mei_device *dev); |
93 | void mei_cl_init(struct mei_cl *cl, struct mei_device *dev); | ||
94 | |||
95 | 92 | ||
96 | int mei_cl_link(struct mei_cl *cl); | 93 | int mei_cl_link(struct mei_cl *cl); |
97 | int mei_cl_unlink(struct mei_cl *cl); | 94 | 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, | |||
205 | int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb, | 202 | int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb, |
206 | struct list_head *cmpl_list); | 203 | struct list_head *cmpl_list); |
207 | int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp); | 204 | int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp); |
208 | int mei_cl_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *hdr, | ||
209 | struct list_head *cmpl_list); | ||
210 | int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb); | 205 | int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb); |
211 | int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, | 206 | int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, |
212 | struct list_head *cmpl_list); | 207 | 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) | |||
166 | * | 166 | * |
167 | * Return: 0 on success, <0 on failure. | 167 | * Return: 0 on success, <0 on failure. |
168 | */ | 168 | */ |
169 | static inline | 169 | static inline int mei_hbm_cl_write(struct mei_device *dev, struct mei_cl *cl, |
170 | int mei_hbm_cl_write(struct mei_device *dev, struct mei_cl *cl, | 170 | u8 hbm_cmd, void *buf, size_t len) |
171 | u8 hbm_cmd, u8 *buf, size_t len) | ||
172 | { | 171 | { |
173 | struct mei_msg_hdr mei_hdr; | 172 | struct mei_msg_hdr mei_hdr; |
174 | 173 | ||
@@ -632,11 +631,11 @@ static int mei_hbm_stop_req(struct mei_device *dev) | |||
632 | */ | 631 | */ |
633 | int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl) | 632 | int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl) |
634 | { | 633 | { |
635 | const size_t len = sizeof(struct hbm_flow_control); | 634 | struct hbm_flow_control req; |
636 | u8 buf[len]; | ||
637 | 635 | ||
638 | cl_dbg(dev, cl, "sending flow control\n"); | 636 | cl_dbg(dev, cl, "sending flow control\n"); |
639 | return mei_hbm_cl_write(dev, cl, MEI_FLOW_CONTROL_CMD, buf, len); | 637 | return mei_hbm_cl_write(dev, cl, MEI_FLOW_CONTROL_CMD, |
638 | &req, sizeof(req)); | ||
640 | } | 639 | } |
641 | 640 | ||
642 | /** | 641 | /** |
@@ -710,10 +709,10 @@ static void mei_hbm_cl_tx_flow_ctrl_creds_res(struct mei_device *dev, | |||
710 | */ | 709 | */ |
711 | int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl) | 710 | int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl) |
712 | { | 711 | { |
713 | const size_t len = sizeof(struct hbm_client_connect_request); | 712 | struct hbm_client_connect_request req; |
714 | u8 buf[len]; | ||
715 | 713 | ||
716 | return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_REQ_CMD, buf, len); | 714 | return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_REQ_CMD, |
715 | &req, sizeof(req)); | ||
717 | } | 716 | } |
718 | 717 | ||
719 | /** | 718 | /** |
@@ -726,10 +725,10 @@ int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl) | |||
726 | */ | 725 | */ |
727 | int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl) | 726 | int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl) |
728 | { | 727 | { |
729 | const size_t len = sizeof(struct hbm_client_connect_response); | 728 | struct hbm_client_connect_response resp; |
730 | u8 buf[len]; | ||
731 | 729 | ||
732 | return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_RES_CMD, buf, len); | 730 | return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_RES_CMD, |
731 | &resp, sizeof(resp)); | ||
733 | } | 732 | } |
734 | 733 | ||
735 | /** | 734 | /** |
@@ -763,10 +762,10 @@ static void mei_hbm_cl_disconnect_res(struct mei_device *dev, struct mei_cl *cl, | |||
763 | */ | 762 | */ |
764 | int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl) | 763 | int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl) |
765 | { | 764 | { |
766 | const size_t len = sizeof(struct hbm_client_connect_request); | 765 | struct hbm_client_connect_request req; |
767 | u8 buf[len]; | ||
768 | 766 | ||
769 | return mei_hbm_cl_write(dev, cl, CLIENT_CONNECT_REQ_CMD, buf, len); | 767 | return mei_hbm_cl_write(dev, cl, CLIENT_CONNECT_REQ_CMD, |
768 | &req, sizeof(req)); | ||
770 | } | 769 | } |
771 | 770 | ||
772 | /** | 771 | /** |
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) | |||
146 | /* fall through and remove the sw state even if hw reset has failed */ | 146 | /* fall through and remove the sw state even if hw reset has failed */ |
147 | 147 | ||
148 | /* no need to clean up software state in case of power up */ | 148 | /* no need to clean up software state in case of power up */ |
149 | if (state != MEI_DEV_INITIALIZING && | 149 | if (state != MEI_DEV_INITIALIZING && state != MEI_DEV_POWER_UP) |
150 | state != MEI_DEV_POWER_UP) { | ||
151 | |||
152 | /* remove all waiting requests */ | ||
153 | mei_cl_all_disconnect(dev); | 150 | mei_cl_all_disconnect(dev); |
154 | 151 | ||
155 | /* remove entry if already in list */ | ||
156 | dev_dbg(dev->dev, "remove iamthif from the file list.\n"); | ||
157 | mei_cl_unlink(&dev->iamthif_cl); | ||
158 | mei_amthif_reset_params(dev); | ||
159 | } | ||
160 | |||
161 | mei_hbm_reset(dev); | 152 | mei_hbm_reset(dev); |
162 | 153 | ||
163 | dev->rd_msg_hdr = 0; | 154 | dev->rd_msg_hdr = 0; |
@@ -401,9 +392,6 @@ void mei_device_init(struct mei_device *dev, | |||
401 | INIT_WORK(&dev->reset_work, mei_reset_work); | 392 | INIT_WORK(&dev->reset_work, mei_reset_work); |
402 | INIT_WORK(&dev->bus_rescan_work, mei_cl_bus_rescan_work); | 393 | INIT_WORK(&dev->bus_rescan_work, mei_cl_bus_rescan_work); |
403 | 394 | ||
404 | INIT_LIST_HEAD(&dev->iamthif_cl.link); | ||
405 | INIT_LIST_HEAD(&dev->amthif_cmd_list); | ||
406 | |||
407 | bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); | 395 | bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); |
408 | dev->open_handle_count = 0; | 396 | dev->open_handle_count = 0; |
409 | 397 | ||
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) | |||
47 | list_del_init(&cb->list); | 47 | list_del_init(&cb->list); |
48 | 48 | ||
49 | dev_dbg(dev->dev, "completing call back.\n"); | 49 | dev_dbg(dev->dev, "completing call back.\n"); |
50 | if (cl == &dev->iamthif_cl) | 50 | mei_cl_complete(cl, cb); |
51 | mei_amthif_complete(cl, cb); | ||
52 | else | ||
53 | mei_cl_complete(cl, cb); | ||
54 | } | 51 | } |
55 | } | 52 | } |
56 | EXPORT_SYMBOL_GPL(mei_irq_compl_handler); | 53 | EXPORT_SYMBOL_GPL(mei_irq_compl_handler); |
@@ -76,7 +73,7 @@ static inline int mei_cl_hbm_equal(struct mei_cl *cl, | |||
76 | * @dev: mei device | 73 | * @dev: mei device |
77 | * @hdr: message header | 74 | * @hdr: message header |
78 | */ | 75 | */ |
79 | void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr) | 76 | static void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr) |
80 | { | 77 | { |
81 | /* | 78 | /* |
82 | * no need to check for size as it is guarantied | 79 | * 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) | |||
96 | * | 93 | * |
97 | * Return: always 0 | 94 | * Return: always 0 |
98 | */ | 95 | */ |
99 | int mei_cl_irq_read_msg(struct mei_cl *cl, | 96 | static int mei_cl_irq_read_msg(struct mei_cl *cl, |
100 | struct mei_msg_hdr *mei_hdr, | 97 | struct mei_msg_hdr *mei_hdr, |
101 | struct list_head *cmpl_list) | 98 | struct list_head *cmpl_list) |
102 | { | 99 | { |
103 | struct mei_device *dev = cl->dev; | 100 | struct mei_device *dev = cl->dev; |
104 | struct mei_cl_cb *cb; | 101 | struct mei_cl_cb *cb; |
@@ -313,11 +310,7 @@ int mei_irq_read_handler(struct mei_device *dev, | |||
313 | goto end; | 310 | goto end; |
314 | } | 311 | } |
315 | 312 | ||
316 | if (cl == &dev->iamthif_cl) { | 313 | ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list); |
317 | ret = mei_amthif_irq_read_msg(cl, mei_hdr, cmpl_list); | ||
318 | } else { | ||
319 | ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list); | ||
320 | } | ||
321 | 314 | ||
322 | 315 | ||
323 | reset_slots: | 316 | reset_slots: |
@@ -423,10 +416,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct list_head *cmpl_list) | |||
423 | dev_dbg(dev->dev, "complete write list cb.\n"); | 416 | dev_dbg(dev->dev, "complete write list cb.\n"); |
424 | list_for_each_entry_safe(cb, next, &dev->write_list, list) { | 417 | list_for_each_entry_safe(cb, next, &dev->write_list, list) { |
425 | cl = cb->cl; | 418 | cl = cb->cl; |
426 | if (cl == &dev->iamthif_cl) | 419 | ret = mei_cl_irq_write(cl, cb, cmpl_list); |
427 | ret = mei_amthif_irq_write(cl, cb, cmpl_list); | ||
428 | else | ||
429 | ret = mei_cl_irq_write(cl, cb, cmpl_list); | ||
430 | if (ret) | 420 | if (ret) |
431 | return ret; | 421 | return ret; |
432 | } | 422 | } |
@@ -512,20 +502,6 @@ void mei_timer(struct work_struct *work) | |||
512 | } | 502 | } |
513 | } | 503 | } |
514 | 504 | ||
515 | if (!mei_cl_is_connected(&dev->iamthif_cl)) | ||
516 | goto out; | ||
517 | |||
518 | if (dev->iamthif_stall_timer) { | ||
519 | if (--dev->iamthif_stall_timer == 0) { | ||
520 | dev_err(dev->dev, "timer: amthif hanged.\n"); | ||
521 | mei_reset(dev); | ||
522 | |||
523 | mei_amthif_run_next_cmd(dev); | ||
524 | goto out; | ||
525 | } | ||
526 | reschedule_timer = true; | ||
527 | } | ||
528 | |||
529 | out: | 505 | out: |
530 | if (dev->dev_state != MEI_DEV_DISABLED && reschedule_timer) | 506 | if (dev->dev_state != MEI_DEV_DISABLED && reschedule_timer) |
531 | mei_schedule_stall_timer(dev); | 507 | 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) | |||
103 | dev = cl->dev; | 103 | dev = cl->dev; |
104 | 104 | ||
105 | mutex_lock(&dev->device_lock); | 105 | mutex_lock(&dev->device_lock); |
106 | if (cl == &dev->iamthif_cl) { | 106 | |
107 | rets = mei_amthif_release(dev, file); | ||
108 | goto out; | ||
109 | } | ||
110 | rets = mei_cl_disconnect(cl); | 107 | rets = mei_cl_disconnect(cl); |
111 | 108 | ||
112 | mei_cl_flush_queues(cl, file); | 109 | mei_cl_flush_queues(cl, file); |
@@ -117,7 +114,7 @@ static int mei_release(struct inode *inode, struct file *file) | |||
117 | file->private_data = NULL; | 114 | file->private_data = NULL; |
118 | 115 | ||
119 | kfree(cl); | 116 | kfree(cl); |
120 | out: | 117 | |
121 | mutex_unlock(&dev->device_lock); | 118 | mutex_unlock(&dev->device_lock); |
122 | return rets; | 119 | return rets; |
123 | } | 120 | } |
@@ -182,8 +179,6 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
182 | goto out; | 179 | goto out; |
183 | } | 180 | } |
184 | 181 | ||
185 | |||
186 | again: | ||
187 | mutex_unlock(&dev->device_lock); | 182 | mutex_unlock(&dev->device_lock); |
188 | if (wait_event_interruptible(cl->rx_wait, | 183 | if (wait_event_interruptible(cl->rx_wait, |
189 | !list_empty(&cl->rd_completed) || | 184 | !list_empty(&cl->rd_completed) || |
@@ -201,14 +196,6 @@ again: | |||
201 | 196 | ||
202 | cb = mei_cl_read_cb(cl, file); | 197 | cb = mei_cl_read_cb(cl, file); |
203 | if (!cb) { | 198 | if (!cb) { |
204 | /* | ||
205 | * For amthif all the waiters are woken up, | ||
206 | * but only fp with matching cb->fp get the cb, | ||
207 | * the others have to return to wait on read. | ||
208 | */ | ||
209 | if (cl == &dev->iamthif_cl) | ||
210 | goto again; | ||
211 | |||
212 | rets = 0; | 199 | rets = 0; |
213 | goto out; | 200 | goto out; |
214 | } | 201 | } |
@@ -319,13 +306,6 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
319 | goto out; | 306 | goto out; |
320 | } | 307 | } |
321 | 308 | ||
322 | if (cl == &dev->iamthif_cl) { | ||
323 | rets = mei_amthif_write(cl, cb); | ||
324 | if (!rets) | ||
325 | rets = length; | ||
326 | goto out; | ||
327 | } | ||
328 | |||
329 | rets = mei_cl_write(cl, cb); | 309 | rets = mei_cl_write(cl, cb); |
330 | out: | 310 | out: |
331 | mutex_unlock(&dev->device_lock); | 311 | mutex_unlock(&dev->device_lock); |
@@ -388,30 +368,6 @@ static int mei_ioctl_connect_client(struct file *file, | |||
388 | dev_dbg(dev->dev, "FW Client - Max Msg Len = %d\n", | 368 | dev_dbg(dev->dev, "FW Client - Max Msg Len = %d\n", |
389 | me_cl->props.max_msg_length); | 369 | me_cl->props.max_msg_length); |
390 | 370 | ||
391 | /* if we're connecting to amthif client then we will use the | ||
392 | * existing connection | ||
393 | */ | ||
394 | if (uuid_le_cmp(data->in_client_uuid, mei_amthif_guid) == 0) { | ||
395 | dev_dbg(dev->dev, "FW Client is amthi\n"); | ||
396 | if (!mei_cl_is_connected(&dev->iamthif_cl)) { | ||
397 | rets = -ENODEV; | ||
398 | goto end; | ||
399 | } | ||
400 | mei_cl_unlink(cl); | ||
401 | |||
402 | kfree(cl); | ||
403 | cl = NULL; | ||
404 | dev->iamthif_open_count++; | ||
405 | file->private_data = &dev->iamthif_cl; | ||
406 | |||
407 | client = &data->out_client_properties; | ||
408 | client->max_msg_length = me_cl->props.max_msg_length; | ||
409 | client->protocol_version = me_cl->props.protocol_version; | ||
410 | rets = dev->iamthif_cl.status; | ||
411 | |||
412 | goto end; | ||
413 | } | ||
414 | |||
415 | /* prepare the output buffer */ | 371 | /* prepare the output buffer */ |
416 | client = &data->out_client_properties; | 372 | client = &data->out_client_properties; |
417 | client->max_msg_length = me_cl->props.max_msg_length; | 373 | 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) | |||
615 | mask |= POLLPRI; | 571 | mask |= POLLPRI; |
616 | } | 572 | } |
617 | 573 | ||
618 | if (cl == &dev->iamthif_cl) { | ||
619 | mask |= mei_amthif_poll(file, wait); | ||
620 | goto out; | ||
621 | } | ||
622 | |||
623 | if (req_events & (POLLIN | POLLRDNORM)) { | 574 | if (req_events & (POLLIN | POLLRDNORM)) { |
624 | poll_wait(file, &cl->rx_wait, wait); | 575 | poll_wait(file, &cl->rx_wait, wait); |
625 | 576 | ||
@@ -635,6 +586,77 @@ out: | |||
635 | } | 586 | } |
636 | 587 | ||
637 | /** | 588 | /** |
589 | * mei_cl_is_write_queued - check if the client has pending writes. | ||
590 | * | ||
591 | * @cl: writing host client | ||
592 | * | ||
593 | * Return: true if client is writing, false otherwise. | ||
594 | */ | ||
595 | static bool mei_cl_is_write_queued(struct mei_cl *cl) | ||
596 | { | ||
597 | struct mei_device *dev = cl->dev; | ||
598 | struct mei_cl_cb *cb; | ||
599 | |||
600 | list_for_each_entry(cb, &dev->write_list, list) | ||
601 | if (cb->cl == cl) | ||
602 | return true; | ||
603 | list_for_each_entry(cb, &dev->write_waiting_list, list) | ||
604 | if (cb->cl == cl) | ||
605 | return true; | ||
606 | return false; | ||
607 | } | ||
608 | |||
609 | /** | ||
610 | * mei_fsync - the fsync handler | ||
611 | * | ||
612 | * @fp: pointer to file structure | ||
613 | * @start: unused | ||
614 | * @end: unused | ||
615 | * @datasync: unused | ||
616 | * | ||
617 | * Return: 0 on success, -ENODEV if client is not connected | ||
618 | */ | ||
619 | static int mei_fsync(struct file *fp, loff_t start, loff_t end, int datasync) | ||
620 | { | ||
621 | struct mei_cl *cl = fp->private_data; | ||
622 | struct mei_device *dev; | ||
623 | int rets; | ||
624 | |||
625 | if (WARN_ON(!cl || !cl->dev)) | ||
626 | return -ENODEV; | ||
627 | |||
628 | dev = cl->dev; | ||
629 | |||
630 | mutex_lock(&dev->device_lock); | ||
631 | |||
632 | if (dev->dev_state != MEI_DEV_ENABLED || !mei_cl_is_connected(cl)) { | ||
633 | rets = -ENODEV; | ||
634 | goto out; | ||
635 | } | ||
636 | |||
637 | while (mei_cl_is_write_queued(cl)) { | ||
638 | mutex_unlock(&dev->device_lock); | ||
639 | rets = wait_event_interruptible(cl->tx_wait, | ||
640 | cl->writing_state == MEI_WRITE_COMPLETE || | ||
641 | !mei_cl_is_connected(cl)); | ||
642 | mutex_lock(&dev->device_lock); | ||
643 | if (rets) { | ||
644 | if (signal_pending(current)) | ||
645 | rets = -EINTR; | ||
646 | goto out; | ||
647 | } | ||
648 | if (!mei_cl_is_connected(cl)) { | ||
649 | rets = -ENODEV; | ||
650 | goto out; | ||
651 | } | ||
652 | } | ||
653 | rets = 0; | ||
654 | out: | ||
655 | mutex_unlock(&dev->device_lock); | ||
656 | return rets; | ||
657 | } | ||
658 | |||
659 | /** | ||
638 | * mei_fasync - asynchronous io support | 660 | * mei_fasync - asynchronous io support |
639 | * | 661 | * |
640 | * @fd: file descriptor | 662 | * @fd: file descriptor |
@@ -749,6 +771,7 @@ static const struct file_operations mei_fops = { | |||
749 | .release = mei_release, | 771 | .release = mei_release, |
750 | .write = mei_write, | 772 | .write = mei_write, |
751 | .poll = mei_poll, | 773 | .poll = mei_poll, |
774 | .fsync = mei_fsync, | ||
752 | .fasync = mei_fasync, | 775 | .fasync = mei_fasync, |
753 | .llseek = no_llseek | 776 | .llseek = no_llseek |
754 | }; | 777 | }; |
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 @@ | |||
26 | #include "hw.h" | 26 | #include "hw.h" |
27 | #include "hbm.h" | 27 | #include "hbm.h" |
28 | 28 | ||
29 | |||
30 | /* | ||
31 | * AMTHI Client UUID | ||
32 | */ | ||
33 | extern const uuid_le mei_amthif_guid; | ||
34 | |||
35 | #define MEI_RD_MSG_BUF_SIZE (128 * sizeof(u32)) | 29 | #define MEI_RD_MSG_BUF_SIZE (128 * sizeof(u32)) |
36 | 30 | ||
37 | /* | 31 | /* |
@@ -78,12 +72,6 @@ enum mei_dev_state { | |||
78 | 72 | ||
79 | const char *mei_dev_state_str(int state); | 73 | const char *mei_dev_state_str(int state); |
80 | 74 | ||
81 | enum iamthif_states { | ||
82 | MEI_IAMTHIF_IDLE, | ||
83 | MEI_IAMTHIF_WRITING, | ||
84 | MEI_IAMTHIF_READING, | ||
85 | }; | ||
86 | |||
87 | enum mei_file_transaction_states { | 75 | enum mei_file_transaction_states { |
88 | MEI_IDLE, | 76 | MEI_IDLE, |
89 | MEI_WRITING, | 77 | MEI_WRITING, |
@@ -418,13 +406,6 @@ const char *mei_pg_state_str(enum mei_pg_state state); | |||
418 | * @allow_fixed_address: allow user space to connect a fixed client | 406 | * @allow_fixed_address: allow user space to connect a fixed client |
419 | * @override_fixed_address: force allow fixed address behavior | 407 | * @override_fixed_address: force allow fixed address behavior |
420 | * | 408 | * |
421 | * @amthif_cmd_list : amthif list for cmd waiting | ||
422 | * @iamthif_cl : amthif host client | ||
423 | * @iamthif_open_count : number of opened amthif connections | ||
424 | * @iamthif_stall_timer : timer to detect amthif hang | ||
425 | * @iamthif_state : amthif processor state | ||
426 | * @iamthif_canceled : current amthif command is canceled | ||
427 | * | ||
428 | * @reset_work : work item for the device reset | 409 | * @reset_work : work item for the device reset |
429 | * @bus_rescan_work : work item for the bus rescan | 410 | * @bus_rescan_work : work item for the bus rescan |
430 | * | 411 | * |
@@ -500,14 +481,6 @@ struct mei_device { | |||
500 | bool allow_fixed_address; | 481 | bool allow_fixed_address; |
501 | bool override_fixed_address; | 482 | bool override_fixed_address; |
502 | 483 | ||
503 | /* amthif list for cmd waiting */ | ||
504 | struct list_head amthif_cmd_list; | ||
505 | struct mei_cl iamthif_cl; | ||
506 | long iamthif_open_count; | ||
507 | u32 iamthif_stall_timer; | ||
508 | enum iamthif_states iamthif_state; | ||
509 | bool iamthif_canceled; | ||
510 | |||
511 | struct work_struct reset_work; | 484 | struct work_struct reset_work; |
512 | struct work_struct bus_rescan_work; | 485 | struct work_struct bus_rescan_work; |
513 | 486 | ||
@@ -579,28 +552,6 @@ int mei_irq_write_handler(struct mei_device *dev, struct list_head *cmpl_list); | |||
579 | void mei_irq_compl_handler(struct mei_device *dev, struct list_head *cmpl_list); | 552 | void mei_irq_compl_handler(struct mei_device *dev, struct list_head *cmpl_list); |
580 | 553 | ||
581 | /* | 554 | /* |
582 | * AMTHIF - AMT Host Interface Functions | ||
583 | */ | ||
584 | void mei_amthif_reset_params(struct mei_device *dev); | ||
585 | |||
586 | int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl); | ||
587 | |||
588 | unsigned int mei_amthif_poll(struct file *file, poll_table *wait); | ||
589 | |||
590 | int mei_amthif_release(struct mei_device *dev, struct file *file); | ||
591 | |||
592 | int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb); | ||
593 | int mei_amthif_run_next_cmd(struct mei_device *dev); | ||
594 | int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, | ||
595 | struct list_head *cmpl_list); | ||
596 | |||
597 | void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb); | ||
598 | int mei_amthif_irq_read_msg(struct mei_cl *cl, | ||
599 | struct mei_msg_hdr *mei_hdr, | ||
600 | struct list_head *cmpl_list); | ||
601 | int mei_amthif_irq_read(struct mei_device *dev, s32 *slots); | ||
602 | |||
603 | /* | ||
604 | * Register Access Function | 555 | * Register Access Function |
605 | */ | 556 | */ |
606 | 557 | ||
@@ -711,8 +662,6 @@ bool mei_hbuf_acquire(struct mei_device *dev); | |||
711 | 662 | ||
712 | bool mei_write_is_idle(struct mei_device *dev); | 663 | bool mei_write_is_idle(struct mei_device *dev); |
713 | 664 | ||
714 | void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr); | ||
715 | |||
716 | #if IS_ENABLED(CONFIG_DEBUG_FS) | 665 | #if IS_ENABLED(CONFIG_DEBUG_FS) |
717 | int mei_dbgfs_register(struct mei_device *dev, const char *name); | 666 | int mei_dbgfs_register(struct mei_device *dev, const char *name); |
718 | void mei_dbgfs_deregister(struct mei_device *dev); | 667 | 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: | |||
242 | } | 242 | } |
243 | 243 | ||
244 | /** | 244 | /** |
245 | * mei_me_shutdown - Device Removal Routine | ||
246 | * | ||
247 | * @pdev: PCI device structure | ||
248 | * | ||
249 | * mei_me_shutdown is called from the reboot notifier | ||
250 | * it's a simplified version of remove so we go down | ||
251 | * faster. | ||
252 | */ | ||
253 | static void mei_me_shutdown(struct pci_dev *pdev) | ||
254 | { | ||
255 | struct mei_device *dev; | ||
256 | |||
257 | dev = pci_get_drvdata(pdev); | ||
258 | if (!dev) | ||
259 | return; | ||
260 | |||
261 | dev_dbg(&pdev->dev, "shutdown\n"); | ||
262 | mei_stop(dev); | ||
263 | |||
264 | if (!pci_dev_run_wake(pdev)) | ||
265 | mei_me_unset_pm_domain(dev); | ||
266 | |||
267 | mei_disable_interrupts(dev); | ||
268 | free_irq(pdev->irq, dev); | ||
269 | } | ||
270 | |||
271 | /** | ||
245 | * mei_me_remove - Device Removal Routine | 272 | * mei_me_remove - Device Removal Routine |
246 | * | 273 | * |
247 | * @pdev: PCI device structure | 274 | * @pdev: PCI device structure |
248 | * | 275 | * |
249 | * mei_remove is called by the PCI subsystem to alert the driver | 276 | * mei_me_remove is called by the PCI subsystem to alert the driver |
250 | * that it should release a PCI device. | 277 | * that it should release a PCI device. |
251 | */ | 278 | */ |
252 | static void mei_me_remove(struct pci_dev *pdev) | 279 | static void mei_me_remove(struct pci_dev *pdev) |
@@ -456,7 +483,7 @@ static struct pci_driver mei_me_driver = { | |||
456 | .id_table = mei_me_pci_tbl, | 483 | .id_table = mei_me_pci_tbl, |
457 | .probe = mei_me_probe, | 484 | .probe = mei_me_probe, |
458 | .remove = mei_me_remove, | 485 | .remove = mei_me_remove, |
459 | .shutdown = mei_me_remove, | 486 | .shutdown = mei_me_shutdown, |
460 | .driver.pm = MEI_ME_PM_OPS, | 487 | .driver.pm = MEI_ME_PM_OPS, |
461 | }; | 488 | }; |
462 | 489 | ||
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: | |||
161 | } | 161 | } |
162 | 162 | ||
163 | /** | 163 | /** |
164 | * mei_txe_remove - Device Shutdown Routine | ||
165 | * | ||
166 | * @pdev: PCI device structure | ||
167 | * | ||
168 | * mei_txe_shutdown is called from the reboot notifier | ||
169 | * it's a simplified version of remove so we go down | ||
170 | * faster. | ||
171 | */ | ||
172 | static void mei_txe_shutdown(struct pci_dev *pdev) | ||
173 | { | ||
174 | struct mei_device *dev; | ||
175 | |||
176 | dev = pci_get_drvdata(pdev); | ||
177 | if (!dev) | ||
178 | return; | ||
179 | |||
180 | dev_dbg(&pdev->dev, "shutdown\n"); | ||
181 | mei_stop(dev); | ||
182 | |||
183 | if (!pci_dev_run_wake(pdev)) | ||
184 | mei_txe_unset_pm_domain(dev); | ||
185 | |||
186 | mei_disable_interrupts(dev); | ||
187 | free_irq(pdev->irq, dev); | ||
188 | } | ||
189 | |||
190 | /** | ||
164 | * mei_txe_remove - Device Removal Routine | 191 | * mei_txe_remove - Device Removal Routine |
165 | * | 192 | * |
166 | * @pdev: PCI device structure | 193 | * @pdev: PCI device structure |
@@ -386,7 +413,7 @@ static struct pci_driver mei_txe_driver = { | |||
386 | .id_table = mei_txe_pci_tbl, | 413 | .id_table = mei_txe_pci_tbl, |
387 | .probe = mei_txe_probe, | 414 | .probe = mei_txe_probe, |
388 | .remove = mei_txe_remove, | 415 | .remove = mei_txe_remove, |
389 | .shutdown = mei_txe_remove, | 416 | .shutdown = mei_txe_shutdown, |
390 | .driver.pm = MEI_TXE_PM_OPS, | 417 | .driver.pm = MEI_TXE_PM_OPS, |
391 | }; | 418 | }; |
392 | 419 | ||
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[] = { | |||
443 | }; | 443 | }; |
444 | MODULE_DEVICE_TABLE(i2c, tsl2550_id); | 444 | MODULE_DEVICE_TABLE(i2c, tsl2550_id); |
445 | 445 | ||
446 | static const struct of_device_id tsl2550_of_match[] = { | ||
447 | { .compatible = "taos,tsl2550" }, | ||
448 | { } | ||
449 | }; | ||
450 | MODULE_DEVICE_TABLE(of, tsl2550_of_match); | ||
451 | |||
446 | static struct i2c_driver tsl2550_driver = { | 452 | static struct i2c_driver tsl2550_driver = { |
447 | .driver = { | 453 | .driver = { |
448 | .name = TSL2550_DRV_NAME, | 454 | .name = TSL2550_DRV_NAME, |
455 | .of_match_table = tsl2550_of_match, | ||
449 | .pm = TSL2550_PM_OPS, | 456 | .pm = TSL2550_PM_OPS, |
450 | }, | 457 | }, |
451 | .probe = tsl2550_probe, | 458 | .probe = tsl2550_probe, |
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 77513195f50e..8bae3731d039 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c | |||
@@ -421,41 +421,6 @@ static void dev_release(struct device *dev) | |||
421 | } | 421 | } |
422 | 422 | ||
423 | /** | 423 | /** |
424 | * ubi_sysfs_init - initialize sysfs for an UBI device. | ||
425 | * @ubi: UBI device description object | ||
426 | * @ref: set to %1 on exit in case of failure if a reference to @ubi->dev was | ||
427 | * taken | ||
428 | * | ||
429 | * This function returns zero in case of success and a negative error code in | ||
430 | * case of failure. | ||
431 | */ | ||
432 | static int ubi_sysfs_init(struct ubi_device *ubi, int *ref) | ||
433 | { | ||
434 | int err; | ||
435 | |||
436 | ubi->dev.release = dev_release; | ||
437 | ubi->dev.devt = ubi->cdev.dev; | ||
438 | ubi->dev.class = &ubi_class; | ||
439 | ubi->dev.groups = ubi_dev_groups; | ||
440 | dev_set_name(&ubi->dev, UBI_NAME_STR"%d", ubi->ubi_num); | ||
441 | err = device_register(&ubi->dev); | ||
442 | if (err) | ||
443 | return err; | ||
444 | |||
445 | *ref = 1; | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | /** | ||
450 | * ubi_sysfs_close - close sysfs for an UBI device. | ||
451 | * @ubi: UBI device description object | ||
452 | */ | ||
453 | static void ubi_sysfs_close(struct ubi_device *ubi) | ||
454 | { | ||
455 | device_unregister(&ubi->dev); | ||
456 | } | ||
457 | |||
458 | /** | ||
459 | * kill_volumes - destroy all user volumes. | 424 | * kill_volumes - destroy all user volumes. |
460 | * @ubi: UBI device description object | 425 | * @ubi: UBI device description object |
461 | */ | 426 | */ |
@@ -471,27 +436,19 @@ static void kill_volumes(struct ubi_device *ubi) | |||
471 | /** | 436 | /** |
472 | * uif_init - initialize user interfaces for an UBI device. | 437 | * uif_init - initialize user interfaces for an UBI device. |
473 | * @ubi: UBI device description object | 438 | * @ubi: UBI device description object |
474 | * @ref: set to %1 on exit in case of failure if a reference to @ubi->dev was | ||
475 | * taken, otherwise set to %0 | ||
476 | * | 439 | * |
477 | * This function initializes various user interfaces for an UBI device. If the | 440 | * This function initializes various user interfaces for an UBI device. If the |
478 | * initialization fails at an early stage, this function frees all the | 441 | * initialization fails at an early stage, this function frees all the |
479 | * resources it allocated, returns an error, and @ref is set to %0. However, | 442 | * resources it allocated, returns an error. |
480 | * if the initialization fails after the UBI device was registered in the | ||
481 | * driver core subsystem, this function takes a reference to @ubi->dev, because | ||
482 | * otherwise the release function ('dev_release()') would free whole @ubi | ||
483 | * object. The @ref argument is set to %1 in this case. The caller has to put | ||
484 | * this reference. | ||
485 | * | 443 | * |
486 | * This function returns zero in case of success and a negative error code in | 444 | * This function returns zero in case of success and a negative error code in |
487 | * case of failure. | 445 | * case of failure. |
488 | */ | 446 | */ |
489 | static int uif_init(struct ubi_device *ubi, int *ref) | 447 | static int uif_init(struct ubi_device *ubi) |
490 | { | 448 | { |
491 | int i, err; | 449 | int i, err; |
492 | dev_t dev; | 450 | dev_t dev; |
493 | 451 | ||
494 | *ref = 0; | ||
495 | sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); | 452 | sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); |
496 | 453 | ||
497 | /* | 454 | /* |
@@ -508,20 +465,17 @@ static int uif_init(struct ubi_device *ubi, int *ref) | |||
508 | return err; | 465 | return err; |
509 | } | 466 | } |
510 | 467 | ||
468 | ubi->dev.devt = dev; | ||
469 | |||
511 | ubi_assert(MINOR(dev) == 0); | 470 | ubi_assert(MINOR(dev) == 0); |
512 | cdev_init(&ubi->cdev, &ubi_cdev_operations); | 471 | cdev_init(&ubi->cdev, &ubi_cdev_operations); |
513 | dbg_gen("%s major is %u", ubi->ubi_name, MAJOR(dev)); | 472 | dbg_gen("%s major is %u", ubi->ubi_name, MAJOR(dev)); |
514 | ubi->cdev.owner = THIS_MODULE; | 473 | ubi->cdev.owner = THIS_MODULE; |
515 | 474 | ||
516 | err = cdev_add(&ubi->cdev, dev, 1); | 475 | dev_set_name(&ubi->dev, UBI_NAME_STR "%d", ubi->ubi_num); |
517 | if (err) { | 476 | err = cdev_device_add(&ubi->cdev, &ubi->dev); |
518 | ubi_err(ubi, "cannot add character device"); | ||
519 | goto out_unreg; | ||
520 | } | ||
521 | |||
522 | err = ubi_sysfs_init(ubi, ref); | ||
523 | if (err) | 477 | if (err) |
524 | goto out_sysfs; | 478 | goto out_unreg; |
525 | 479 | ||
526 | for (i = 0; i < ubi->vtbl_slots; i++) | 480 | for (i = 0; i < ubi->vtbl_slots; i++) |
527 | if (ubi->volumes[i]) { | 481 | if (ubi->volumes[i]) { |
@@ -536,11 +490,7 @@ static int uif_init(struct ubi_device *ubi, int *ref) | |||
536 | 490 | ||
537 | out_volumes: | 491 | out_volumes: |
538 | kill_volumes(ubi); | 492 | kill_volumes(ubi); |
539 | out_sysfs: | 493 | cdev_device_del(&ubi->cdev, &ubi->dev); |
540 | if (*ref) | ||
541 | get_device(&ubi->dev); | ||
542 | ubi_sysfs_close(ubi); | ||
543 | cdev_del(&ubi->cdev); | ||
544 | out_unreg: | 494 | out_unreg: |
545 | unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); | 495 | unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); |
546 | ubi_err(ubi, "cannot initialize UBI %s, error %d", | 496 | ubi_err(ubi, "cannot initialize UBI %s, error %d", |
@@ -559,8 +509,7 @@ out_unreg: | |||
559 | static void uif_close(struct ubi_device *ubi) | 509 | static void uif_close(struct ubi_device *ubi) |
560 | { | 510 | { |
561 | kill_volumes(ubi); | 511 | kill_volumes(ubi); |
562 | ubi_sysfs_close(ubi); | 512 | cdev_device_del(&ubi->cdev, &ubi->dev); |
563 | cdev_del(&ubi->cdev); | ||
564 | unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); | 513 | unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); |
565 | } | 514 | } |
566 | 515 | ||
@@ -857,7 +806,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, | |||
857 | int vid_hdr_offset, int max_beb_per1024) | 806 | int vid_hdr_offset, int max_beb_per1024) |
858 | { | 807 | { |
859 | struct ubi_device *ubi; | 808 | struct ubi_device *ubi; |
860 | int i, err, ref = 0; | 809 | int i, err; |
861 | 810 | ||
862 | if (max_beb_per1024 < 0 || max_beb_per1024 > MAX_MTD_UBI_BEB_LIMIT) | 811 | if (max_beb_per1024 < 0 || max_beb_per1024 > MAX_MTD_UBI_BEB_LIMIT) |
863 | return -EINVAL; | 812 | return -EINVAL; |
@@ -919,6 +868,11 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, | |||
919 | if (!ubi) | 868 | if (!ubi) |
920 | return -ENOMEM; | 869 | return -ENOMEM; |
921 | 870 | ||
871 | device_initialize(&ubi->dev); | ||
872 | ubi->dev.release = dev_release; | ||
873 | ubi->dev.class = &ubi_class; | ||
874 | ubi->dev.groups = ubi_dev_groups; | ||
875 | |||
922 | ubi->mtd = mtd; | 876 | ubi->mtd = mtd; |
923 | ubi->ubi_num = ubi_num; | 877 | ubi->ubi_num = ubi_num; |
924 | ubi->vid_hdr_offset = vid_hdr_offset; | 878 | ubi->vid_hdr_offset = vid_hdr_offset; |
@@ -995,7 +949,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, | |||
995 | /* Make device "available" before it becomes accessible via sysfs */ | 949 | /* Make device "available" before it becomes accessible via sysfs */ |
996 | ubi_devices[ubi_num] = ubi; | 950 | ubi_devices[ubi_num] = ubi; |
997 | 951 | ||
998 | err = uif_init(ubi, &ref); | 952 | err = uif_init(ubi); |
999 | if (err) | 953 | if (err) |
1000 | goto out_detach; | 954 | goto out_detach; |
1001 | 955 | ||
@@ -1045,8 +999,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, | |||
1045 | out_debugfs: | 999 | out_debugfs: |
1046 | ubi_debugfs_exit_dev(ubi); | 1000 | ubi_debugfs_exit_dev(ubi); |
1047 | out_uif: | 1001 | out_uif: |
1048 | get_device(&ubi->dev); | ||
1049 | ubi_assert(ref); | ||
1050 | uif_close(ubi); | 1002 | uif_close(ubi); |
1051 | out_detach: | 1003 | out_detach: |
1052 | ubi_devices[ubi_num] = NULL; | 1004 | ubi_devices[ubi_num] = NULL; |
@@ -1056,10 +1008,7 @@ out_detach: | |||
1056 | out_free: | 1008 | out_free: |
1057 | vfree(ubi->peb_buf); | 1009 | vfree(ubi->peb_buf); |
1058 | vfree(ubi->fm_buf); | 1010 | vfree(ubi->fm_buf); |
1059 | if (ref) | 1011 | put_device(&ubi->dev); |
1060 | put_device(&ubi->dev); | ||
1061 | else | ||
1062 | kfree(ubi); | ||
1063 | return err; | 1012 | return err; |
1064 | } | 1013 | } |
1065 | 1014 | ||
@@ -1120,12 +1069,6 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) | |||
1120 | if (ubi->bgt_thread) | 1069 | if (ubi->bgt_thread) |
1121 | kthread_stop(ubi->bgt_thread); | 1070 | kthread_stop(ubi->bgt_thread); |
1122 | 1071 | ||
1123 | /* | ||
1124 | * Get a reference to the device in order to prevent 'dev_release()' | ||
1125 | * from freeing the @ubi object. | ||
1126 | */ | ||
1127 | get_device(&ubi->dev); | ||
1128 | |||
1129 | ubi_debugfs_exit_dev(ubi); | 1072 | ubi_debugfs_exit_dev(ubi); |
1130 | uif_close(ubi); | 1073 | uif_close(ubi); |
1131 | 1074 | ||
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 7ac78c13dd1c..85237cf661f9 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c | |||
@@ -155,11 +155,10 @@ static void vol_release(struct device *dev) | |||
155 | */ | 155 | */ |
156 | int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) | 156 | int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) |
157 | { | 157 | { |
158 | int i, err, vol_id = req->vol_id, do_free = 1; | 158 | int i, err, vol_id = req->vol_id; |
159 | struct ubi_volume *vol; | 159 | struct ubi_volume *vol; |
160 | struct ubi_vtbl_record vtbl_rec; | 160 | struct ubi_vtbl_record vtbl_rec; |
161 | struct ubi_eba_table *eba_tbl = NULL; | 161 | struct ubi_eba_table *eba_tbl = NULL; |
162 | dev_t dev; | ||
163 | 162 | ||
164 | if (ubi->ro_mode) | 163 | if (ubi->ro_mode) |
165 | return -EROFS; | 164 | return -EROFS; |
@@ -168,6 +167,12 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) | |||
168 | if (!vol) | 167 | if (!vol) |
169 | return -ENOMEM; | 168 | return -ENOMEM; |
170 | 169 | ||
170 | device_initialize(&vol->dev); | ||
171 | vol->dev.release = vol_release; | ||
172 | vol->dev.parent = &ubi->dev; | ||
173 | vol->dev.class = &ubi_class; | ||
174 | vol->dev.groups = volume_dev_groups; | ||
175 | |||
171 | spin_lock(&ubi->volumes_lock); | 176 | spin_lock(&ubi->volumes_lock); |
172 | if (vol_id == UBI_VOL_NUM_AUTO) { | 177 | if (vol_id == UBI_VOL_NUM_AUTO) { |
173 | /* Find unused volume ID */ | 178 | /* Find unused volume ID */ |
@@ -268,24 +273,13 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) | |||
268 | /* Register character device for the volume */ | 273 | /* Register character device for the volume */ |
269 | cdev_init(&vol->cdev, &ubi_vol_cdev_operations); | 274 | cdev_init(&vol->cdev, &ubi_vol_cdev_operations); |
270 | vol->cdev.owner = THIS_MODULE; | 275 | vol->cdev.owner = THIS_MODULE; |
271 | dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1); | ||
272 | err = cdev_add(&vol->cdev, dev, 1); | ||
273 | if (err) { | ||
274 | ubi_err(ubi, "cannot add character device"); | ||
275 | goto out_mapping; | ||
276 | } | ||
277 | |||
278 | vol->dev.release = vol_release; | ||
279 | vol->dev.parent = &ubi->dev; | ||
280 | vol->dev.devt = dev; | ||
281 | vol->dev.class = &ubi_class; | ||
282 | vol->dev.groups = volume_dev_groups; | ||
283 | 276 | ||
277 | vol->dev.devt = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1); | ||
284 | dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id); | 278 | dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id); |
285 | err = device_register(&vol->dev); | 279 | err = cdev_device_add(&vol->cdev, &vol->dev); |
286 | if (err) { | 280 | if (err) { |
287 | ubi_err(ubi, "cannot register device"); | 281 | ubi_err(ubi, "cannot add device"); |
288 | goto out_cdev; | 282 | goto out_mapping; |
289 | } | 283 | } |
290 | 284 | ||
291 | /* Fill volume table record */ | 285 | /* Fill volume table record */ |
@@ -318,28 +312,17 @@ out_sysfs: | |||
318 | * We have registered our device, we should not free the volume | 312 | * We have registered our device, we should not free the volume |
319 | * description object in this function in case of an error - it is | 313 | * description object in this function in case of an error - it is |
320 | * freed by the release function. | 314 | * freed by the release function. |
321 | * | ||
322 | * Get device reference to prevent the release function from being | ||
323 | * called just after sysfs has been closed. | ||
324 | */ | 315 | */ |
325 | do_free = 0; | 316 | cdev_device_del(&vol->cdev, &vol->dev); |
326 | get_device(&vol->dev); | ||
327 | device_unregister(&vol->dev); | ||
328 | out_cdev: | ||
329 | cdev_del(&vol->cdev); | ||
330 | out_mapping: | 317 | out_mapping: |
331 | if (do_free) | 318 | ubi_eba_destroy_table(eba_tbl); |
332 | ubi_eba_destroy_table(eba_tbl); | ||
333 | out_acc: | 319 | out_acc: |
334 | spin_lock(&ubi->volumes_lock); | 320 | spin_lock(&ubi->volumes_lock); |
335 | ubi->rsvd_pebs -= vol->reserved_pebs; | 321 | ubi->rsvd_pebs -= vol->reserved_pebs; |
336 | ubi->avail_pebs += vol->reserved_pebs; | 322 | ubi->avail_pebs += vol->reserved_pebs; |
337 | out_unlock: | 323 | out_unlock: |
338 | spin_unlock(&ubi->volumes_lock); | 324 | spin_unlock(&ubi->volumes_lock); |
339 | if (do_free) | 325 | put_device(&vol->dev); |
340 | kfree(vol); | ||
341 | else | ||
342 | put_device(&vol->dev); | ||
343 | ubi_err(ubi, "cannot create volume %d, error %d", vol_id, err); | 326 | ubi_err(ubi, "cannot create volume %d, error %d", vol_id, err); |
344 | return err; | 327 | return err; |
345 | } | 328 | } |
@@ -391,8 +374,8 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl) | |||
391 | goto out_err; | 374 | goto out_err; |
392 | } | 375 | } |
393 | 376 | ||
394 | cdev_del(&vol->cdev); | 377 | cdev_device_del(&vol->cdev, &vol->dev); |
395 | device_unregister(&vol->dev); | 378 | put_device(&vol->dev); |
396 | 379 | ||
397 | spin_lock(&ubi->volumes_lock); | 380 | spin_lock(&ubi->volumes_lock); |
398 | ubi->rsvd_pebs -= reserved_pebs; | 381 | ubi->rsvd_pebs -= reserved_pebs; |
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index 650f1b1797ad..101ced4c84be 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig | |||
@@ -13,6 +13,17 @@ menuconfig NVMEM | |||
13 | 13 | ||
14 | if NVMEM | 14 | if NVMEM |
15 | 15 | ||
16 | config NVMEM_IMX_IIM | ||
17 | tristate "i.MX IC Identification Module support" | ||
18 | depends on ARCH_MXC || COMPILE_TEST | ||
19 | help | ||
20 | This is a driver for the IC Identification Module (IIM) available on | ||
21 | i.MX SoCs, providing access to 4 Kbits of programmable | ||
22 | eFuses. | ||
23 | |||
24 | This driver can also be built as a module. If so, the module | ||
25 | will be called nvmem-imx-iim. | ||
26 | |||
16 | config NVMEM_IMX_OCOTP | 27 | config NVMEM_IMX_OCOTP |
17 | tristate "i.MX6 On-Chip OTP Controller support" | 28 | tristate "i.MX6 On-Chip OTP Controller support" |
18 | depends on SOC_IMX6 || COMPILE_TEST | 29 | depends on SOC_IMX6 || COMPILE_TEST |
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 86e45995fdad..173140658693 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile | |||
@@ -8,6 +8,8 @@ nvmem_core-y := core.o | |||
8 | # Devices | 8 | # Devices |
9 | obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o | 9 | obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o |
10 | nvmem-bcm-ocotp-y := bcm-ocotp.o | 10 | nvmem-bcm-ocotp-y := bcm-ocotp.o |
11 | obj-$(CONFIG_NVMEM_IMX_IIM) += nvmem-imx-iim.o | ||
12 | nvmem-imx-iim-y := imx-iim.o | ||
11 | obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o | 13 | obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o |
12 | nvmem-imx-ocotp-y := imx-ocotp.o | 14 | nvmem-imx-ocotp-y := imx-ocotp.o |
13 | obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o | 15 | obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o |
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 408b521ee520..8c830a80a648 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c | |||
@@ -468,7 +468,8 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) | |||
468 | np = config->dev->of_node; | 468 | np = config->dev->of_node; |
469 | nvmem->dev.of_node = np; | 469 | nvmem->dev.of_node = np; |
470 | dev_set_name(&nvmem->dev, "%s%d", | 470 | dev_set_name(&nvmem->dev, "%s%d", |
471 | config->name ? : "nvmem", config->id); | 471 | config->name ? : "nvmem", |
472 | config->name ? config->id : nvmem->id); | ||
472 | 473 | ||
473 | nvmem->read_only = of_property_read_bool(np, "read-only") | | 474 | nvmem->read_only = of_property_read_bool(np, "read-only") | |
474 | config->read_only; | 475 | config->read_only; |
diff --git a/drivers/nvmem/imx-iim.c b/drivers/nvmem/imx-iim.c new file mode 100644 index 000000000000..52ff65e0673f --- /dev/null +++ b/drivers/nvmem/imx-iim.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * i.MX IIM driver | ||
3 | * | ||
4 | * Copyright (c) 2017 Pengutronix, Michael Grzeschik <m.grzeschik@pengutronix.de> | ||
5 | * | ||
6 | * Based on the barebox iim driver, | ||
7 | * Copyright (c) 2010 Baruch Siach <baruch@tkos.co.il>, | ||
8 | * Orex Computed Radiography | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 | ||
12 | * as published by the Free Software Foundation. | ||
13 | * | ||
14 | * http://www.opensource.org/licenses/gpl-license.html | ||
15 | * http://www.gnu.org/copyleft/gpl.html | ||
16 | */ | ||
17 | |||
18 | #include <linux/device.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/nvmem-provider.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/of_device.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/clk.h> | ||
27 | |||
28 | #define IIM_BANK_BASE(n) (0x800 + 0x400 * (n)) | ||
29 | |||
30 | struct imx_iim_drvdata { | ||
31 | unsigned int nregs; | ||
32 | }; | ||
33 | |||
34 | struct iim_priv { | ||
35 | void __iomem *base; | ||
36 | struct clk *clk; | ||
37 | struct nvmem_config nvmem; | ||
38 | }; | ||
39 | |||
40 | static int imx_iim_read(void *context, unsigned int offset, | ||
41 | void *buf, size_t bytes) | ||
42 | { | ||
43 | struct iim_priv *iim = context; | ||
44 | int i, ret; | ||
45 | u8 *buf8 = buf; | ||
46 | |||
47 | ret = clk_prepare_enable(iim->clk); | ||
48 | if (ret) | ||
49 | return ret; | ||
50 | |||
51 | for (i = offset; i < offset + bytes; i++) { | ||
52 | int bank = i >> 5; | ||
53 | int reg = i & 0x1f; | ||
54 | |||
55 | *buf8++ = readl(iim->base + IIM_BANK_BASE(bank) + reg * 4); | ||
56 | } | ||
57 | |||
58 | clk_disable_unprepare(iim->clk); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static struct imx_iim_drvdata imx27_drvdata = { | ||
64 | .nregs = 2 * 32, | ||
65 | }; | ||
66 | |||
67 | static struct imx_iim_drvdata imx25_imx31_imx35_drvdata = { | ||
68 | .nregs = 3 * 32, | ||
69 | }; | ||
70 | |||
71 | static struct imx_iim_drvdata imx51_drvdata = { | ||
72 | .nregs = 4 * 32, | ||
73 | }; | ||
74 | |||
75 | static struct imx_iim_drvdata imx53_drvdata = { | ||
76 | .nregs = 4 * 32 + 16, | ||
77 | }; | ||
78 | |||
79 | static const struct of_device_id imx_iim_dt_ids[] = { | ||
80 | { | ||
81 | .compatible = "fsl,imx25-iim", | ||
82 | .data = &imx25_imx31_imx35_drvdata, | ||
83 | }, { | ||
84 | .compatible = "fsl,imx27-iim", | ||
85 | .data = &imx27_drvdata, | ||
86 | }, { | ||
87 | .compatible = "fsl,imx31-iim", | ||
88 | .data = &imx25_imx31_imx35_drvdata, | ||
89 | }, { | ||
90 | .compatible = "fsl,imx35-iim", | ||
91 | .data = &imx25_imx31_imx35_drvdata, | ||
92 | }, { | ||
93 | .compatible = "fsl,imx51-iim", | ||
94 | .data = &imx51_drvdata, | ||
95 | }, { | ||
96 | .compatible = "fsl,imx53-iim", | ||
97 | .data = &imx53_drvdata, | ||
98 | }, { | ||
99 | /* sentinel */ | ||
100 | }, | ||
101 | }; | ||
102 | MODULE_DEVICE_TABLE(of, imx_iim_dt_ids); | ||
103 | |||
104 | static int imx_iim_probe(struct platform_device *pdev) | ||
105 | { | ||
106 | const struct of_device_id *of_id; | ||
107 | struct device *dev = &pdev->dev; | ||
108 | struct resource *res; | ||
109 | struct iim_priv *iim; | ||
110 | struct nvmem_device *nvmem; | ||
111 | struct nvmem_config *cfg; | ||
112 | const struct imx_iim_drvdata *drvdata = NULL; | ||
113 | |||
114 | iim = devm_kzalloc(dev, sizeof(*iim), GFP_KERNEL); | ||
115 | if (!iim) | ||
116 | return -ENOMEM; | ||
117 | |||
118 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
119 | iim->base = devm_ioremap_resource(dev, res); | ||
120 | if (IS_ERR(iim->base)) | ||
121 | return PTR_ERR(iim->base); | ||
122 | |||
123 | of_id = of_match_device(imx_iim_dt_ids, dev); | ||
124 | if (!of_id) | ||
125 | return -ENODEV; | ||
126 | |||
127 | drvdata = of_id->data; | ||
128 | |||
129 | iim->clk = devm_clk_get(&pdev->dev, NULL); | ||
130 | if (IS_ERR(iim->clk)) | ||
131 | return PTR_ERR(iim->clk); | ||
132 | |||
133 | cfg = &iim->nvmem; | ||
134 | |||
135 | cfg->name = "imx-iim", | ||
136 | cfg->read_only = true, | ||
137 | cfg->word_size = 1, | ||
138 | cfg->stride = 1, | ||
139 | cfg->owner = THIS_MODULE, | ||
140 | cfg->reg_read = imx_iim_read, | ||
141 | cfg->dev = dev; | ||
142 | cfg->size = drvdata->nregs; | ||
143 | cfg->priv = iim; | ||
144 | |||
145 | nvmem = nvmem_register(cfg); | ||
146 | if (IS_ERR(nvmem)) | ||
147 | return PTR_ERR(nvmem); | ||
148 | |||
149 | platform_set_drvdata(pdev, nvmem); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int imx_iim_remove(struct platform_device *pdev) | ||
155 | { | ||
156 | struct nvmem_device *nvmem = platform_get_drvdata(pdev); | ||
157 | |||
158 | return nvmem_unregister(nvmem); | ||
159 | } | ||
160 | |||
161 | static struct platform_driver imx_iim_driver = { | ||
162 | .probe = imx_iim_probe, | ||
163 | .remove = imx_iim_remove, | ||
164 | .driver = { | ||
165 | .name = "imx-iim", | ||
166 | .of_match_table = imx_iim_dt_ids, | ||
167 | }, | ||
168 | }; | ||
169 | module_platform_driver(imx_iim_driver); | ||
170 | |||
171 | MODULE_AUTHOR("Michael Grzeschik <m.grzeschik@pengutronix.de>"); | ||
172 | MODULE_DESCRIPTION("i.MX IIM driver"); | ||
173 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c index b8ca1e677b01..193ca8fd350a 100644 --- a/drivers/nvmem/imx-ocotp.c +++ b/drivers/nvmem/imx-ocotp.c | |||
@@ -7,6 +7,9 @@ | |||
7 | * Copyright (c) 2010 Baruch Siach <baruch@tkos.co.il>, | 7 | * Copyright (c) 2010 Baruch Siach <baruch@tkos.co.il>, |
8 | * Orex Computed Radiography | 8 | * Orex Computed Radiography |
9 | * | 9 | * |
10 | * Write support based on the fsl_otp driver, | ||
11 | * Copyright (C) 2010-2013 Freescale Semiconductor, Inc | ||
12 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License version 2 | 14 | * it under the terms of the GNU General Public License version 2 |
12 | * as published by the Free Software Foundation. | 15 | * as published by the Free Software Foundation. |
@@ -24,14 +27,88 @@ | |||
24 | #include <linux/of_device.h> | 27 | #include <linux/of_device.h> |
25 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
26 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/delay.h> | ||
31 | |||
32 | #define IMX_OCOTP_OFFSET_B0W0 0x400 /* Offset from base address of the | ||
33 | * OTP Bank0 Word0 | ||
34 | */ | ||
35 | #define IMX_OCOTP_OFFSET_PER_WORD 0x10 /* Offset between the start addr | ||
36 | * of two consecutive OTP words. | ||
37 | */ | ||
38 | |||
39 | #define IMX_OCOTP_ADDR_CTRL 0x0000 | ||
40 | #define IMX_OCOTP_ADDR_CTRL_SET 0x0004 | ||
41 | #define IMX_OCOTP_ADDR_CTRL_CLR 0x0008 | ||
42 | #define IMX_OCOTP_ADDR_TIMING 0x0010 | ||
43 | #define IMX_OCOTP_ADDR_DATA 0x0020 | ||
44 | |||
45 | #define IMX_OCOTP_BM_CTRL_ADDR 0x0000007F | ||
46 | #define IMX_OCOTP_BM_CTRL_BUSY 0x00000100 | ||
47 | #define IMX_OCOTP_BM_CTRL_ERROR 0x00000200 | ||
48 | #define IMX_OCOTP_BM_CTRL_REL_SHADOWS 0x00000400 | ||
49 | |||
50 | #define DEF_RELAX 20 /* > 16.5ns */ | ||
51 | #define IMX_OCOTP_WR_UNLOCK 0x3E770000 | ||
52 | #define IMX_OCOTP_READ_LOCKED_VAL 0xBADABADA | ||
53 | |||
54 | static DEFINE_MUTEX(ocotp_mutex); | ||
27 | 55 | ||
28 | struct ocotp_priv { | 56 | struct ocotp_priv { |
29 | struct device *dev; | 57 | struct device *dev; |
30 | struct clk *clk; | 58 | struct clk *clk; |
31 | void __iomem *base; | 59 | void __iomem *base; |
32 | unsigned int nregs; | 60 | unsigned int nregs; |
61 | struct nvmem_config *config; | ||
33 | }; | 62 | }; |
34 | 63 | ||
64 | static int imx_ocotp_wait_for_busy(void __iomem *base, u32 flags) | ||
65 | { | ||
66 | int count; | ||
67 | u32 c, mask; | ||
68 | |||
69 | mask = IMX_OCOTP_BM_CTRL_BUSY | IMX_OCOTP_BM_CTRL_ERROR | flags; | ||
70 | |||
71 | for (count = 10000; count >= 0; count--) { | ||
72 | c = readl(base + IMX_OCOTP_ADDR_CTRL); | ||
73 | if (!(c & mask)) | ||
74 | break; | ||
75 | cpu_relax(); | ||
76 | } | ||
77 | |||
78 | if (count < 0) { | ||
79 | /* HW_OCOTP_CTRL[ERROR] will be set under the following | ||
80 | * conditions: | ||
81 | * - A write is performed to a shadow register during a shadow | ||
82 | * reload (essentially, while HW_OCOTP_CTRL[RELOAD_SHADOWS] is | ||
83 | * set. In addition, the contents of the shadow register shall | ||
84 | * not be updated. | ||
85 | * - A write is performed to a shadow register which has been | ||
86 | * locked. | ||
87 | * - A read is performed to from a shadow register which has | ||
88 | * been read locked. | ||
89 | * - A program is performed to a fuse word which has been locked | ||
90 | * - A read is performed to from a fuse word which has been read | ||
91 | * locked. | ||
92 | */ | ||
93 | if (c & IMX_OCOTP_BM_CTRL_ERROR) | ||
94 | return -EPERM; | ||
95 | return -ETIMEDOUT; | ||
96 | } | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static void imx_ocotp_clr_err_if_set(void __iomem *base) | ||
102 | { | ||
103 | u32 c; | ||
104 | |||
105 | c = readl(base + IMX_OCOTP_ADDR_CTRL); | ||
106 | if (!(c & IMX_OCOTP_BM_CTRL_ERROR)) | ||
107 | return; | ||
108 | |||
109 | writel(IMX_OCOTP_BM_CTRL_ERROR, base + IMX_OCOTP_ADDR_CTRL_CLR); | ||
110 | } | ||
111 | |||
35 | static int imx_ocotp_read(void *context, unsigned int offset, | 112 | static int imx_ocotp_read(void *context, unsigned int offset, |
36 | void *val, size_t bytes) | 113 | void *val, size_t bytes) |
37 | { | 114 | { |
@@ -47,26 +124,188 @@ static int imx_ocotp_read(void *context, unsigned int offset, | |||
47 | if (count > (priv->nregs - index)) | 124 | if (count > (priv->nregs - index)) |
48 | count = priv->nregs - index; | 125 | count = priv->nregs - index; |
49 | 126 | ||
127 | mutex_lock(&ocotp_mutex); | ||
128 | |||
50 | ret = clk_prepare_enable(priv->clk); | 129 | ret = clk_prepare_enable(priv->clk); |
51 | if (ret < 0) { | 130 | if (ret < 0) { |
131 | mutex_unlock(&ocotp_mutex); | ||
52 | dev_err(priv->dev, "failed to prepare/enable ocotp clk\n"); | 132 | dev_err(priv->dev, "failed to prepare/enable ocotp clk\n"); |
53 | return ret; | 133 | return ret; |
54 | } | 134 | } |
55 | for (i = index; i < (index + count); i++) | ||
56 | *buf++ = readl(priv->base + 0x400 + i * 0x10); | ||
57 | 135 | ||
136 | ret = imx_ocotp_wait_for_busy(priv->base, 0); | ||
137 | if (ret < 0) { | ||
138 | dev_err(priv->dev, "timeout during read setup\n"); | ||
139 | goto read_end; | ||
140 | } | ||
141 | |||
142 | for (i = index; i < (index + count); i++) { | ||
143 | *buf++ = readl(priv->base + IMX_OCOTP_OFFSET_B0W0 + | ||
144 | i * IMX_OCOTP_OFFSET_PER_WORD); | ||
145 | |||
146 | /* 47.3.1.2 | ||
147 | * For "read locked" registers 0xBADABADA will be returned and | ||
148 | * HW_OCOTP_CTRL[ERROR] will be set. It must be cleared by | ||
149 | * software before any new write, read or reload access can be | ||
150 | * issued | ||
151 | */ | ||
152 | if (*(buf - 1) == IMX_OCOTP_READ_LOCKED_VAL) | ||
153 | imx_ocotp_clr_err_if_set(priv->base); | ||
154 | } | ||
155 | ret = 0; | ||
156 | |||
157 | read_end: | ||
58 | clk_disable_unprepare(priv->clk); | 158 | clk_disable_unprepare(priv->clk); |
159 | mutex_unlock(&ocotp_mutex); | ||
160 | return ret; | ||
161 | } | ||
59 | 162 | ||
60 | return 0; | 163 | static int imx_ocotp_write(void *context, unsigned int offset, void *val, |
164 | size_t bytes) | ||
165 | { | ||
166 | struct ocotp_priv *priv = context; | ||
167 | u32 *buf = val; | ||
168 | int ret; | ||
169 | |||
170 | unsigned long clk_rate = 0; | ||
171 | unsigned long strobe_read, relax, strobe_prog; | ||
172 | u32 timing = 0; | ||
173 | u32 ctrl; | ||
174 | u8 waddr; | ||
175 | |||
176 | /* allow only writing one complete OTP word at a time */ | ||
177 | if ((bytes != priv->config->word_size) || | ||
178 | (offset % priv->config->word_size)) | ||
179 | return -EINVAL; | ||
180 | |||
181 | mutex_lock(&ocotp_mutex); | ||
182 | |||
183 | ret = clk_prepare_enable(priv->clk); | ||
184 | if (ret < 0) { | ||
185 | mutex_unlock(&ocotp_mutex); | ||
186 | dev_err(priv->dev, "failed to prepare/enable ocotp clk\n"); | ||
187 | return ret; | ||
188 | } | ||
189 | |||
190 | /* 47.3.1.3.1 | ||
191 | * Program HW_OCOTP_TIMING[STROBE_PROG] and HW_OCOTP_TIMING[RELAX] | ||
192 | * fields with timing values to match the current frequency of the | ||
193 | * ipg_clk. OTP writes will work at maximum bus frequencies as long | ||
194 | * as the HW_OCOTP_TIMING parameters are set correctly. | ||
195 | */ | ||
196 | clk_rate = clk_get_rate(priv->clk); | ||
197 | |||
198 | relax = clk_rate / (1000000000 / DEF_RELAX) - 1; | ||
199 | strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1; | ||
200 | strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1; | ||
201 | |||
202 | timing = strobe_prog & 0x00000FFF; | ||
203 | timing |= (relax << 12) & 0x0000F000; | ||
204 | timing |= (strobe_read << 16) & 0x003F0000; | ||
205 | |||
206 | writel(timing, priv->base + IMX_OCOTP_ADDR_TIMING); | ||
207 | |||
208 | /* 47.3.1.3.2 | ||
209 | * Check that HW_OCOTP_CTRL[BUSY] and HW_OCOTP_CTRL[ERROR] are clear. | ||
210 | * Overlapped accesses are not supported by the controller. Any pending | ||
211 | * write or reload must be completed before a write access can be | ||
212 | * requested. | ||
213 | */ | ||
214 | ret = imx_ocotp_wait_for_busy(priv->base, 0); | ||
215 | if (ret < 0) { | ||
216 | dev_err(priv->dev, "timeout during timing setup\n"); | ||
217 | goto write_end; | ||
218 | } | ||
219 | |||
220 | /* 47.3.1.3.3 | ||
221 | * Write the requested address to HW_OCOTP_CTRL[ADDR] and program the | ||
222 | * unlock code into HW_OCOTP_CTRL[WR_UNLOCK]. This must be programmed | ||
223 | * for each write access. The lock code is documented in the register | ||
224 | * description. Both the unlock code and address can be written in the | ||
225 | * same operation. | ||
226 | */ | ||
227 | /* OTP write/read address specifies one of 128 word address locations */ | ||
228 | waddr = offset / 4; | ||
229 | |||
230 | ctrl = readl(priv->base + IMX_OCOTP_ADDR_CTRL); | ||
231 | ctrl &= ~IMX_OCOTP_BM_CTRL_ADDR; | ||
232 | ctrl |= waddr & IMX_OCOTP_BM_CTRL_ADDR; | ||
233 | ctrl |= IMX_OCOTP_WR_UNLOCK; | ||
234 | |||
235 | writel(ctrl, priv->base + IMX_OCOTP_ADDR_CTRL); | ||
236 | |||
237 | /* 47.3.1.3.4 | ||
238 | * Write the data to the HW_OCOTP_DATA register. This will automatically | ||
239 | * set HW_OCOTP_CTRL[BUSY] and clear HW_OCOTP_CTRL[WR_UNLOCK]. To | ||
240 | * protect programming same OTP bit twice, before program OCOTP will | ||
241 | * automatically read fuse value in OTP and use read value to mask | ||
242 | * program data. The controller will use masked program data to program | ||
243 | * a 32-bit word in the OTP per the address in HW_OCOTP_CTRL[ADDR]. Bit | ||
244 | * fields with 1's will result in that OTP bit being programmed. Bit | ||
245 | * fields with 0's will be ignored. At the same time that the write is | ||
246 | * accepted, the controller makes an internal copy of | ||
247 | * HW_OCOTP_CTRL[ADDR] which cannot be updated until the next write | ||
248 | * sequence is initiated. This copy guarantees that erroneous writes to | ||
249 | * HW_OCOTP_CTRL[ADDR] will not affect an active write operation. It | ||
250 | * should also be noted that during the programming HW_OCOTP_DATA will | ||
251 | * shift right (with zero fill). This shifting is required to program | ||
252 | * the OTP serially. During the write operation, HW_OCOTP_DATA cannot be | ||
253 | * modified. | ||
254 | */ | ||
255 | writel(*buf, priv->base + IMX_OCOTP_ADDR_DATA); | ||
256 | |||
257 | /* 47.4.1.4.5 | ||
258 | * Once complete, the controller will clear BUSY. A write request to a | ||
259 | * protected or locked region will result in no OTP access and no | ||
260 | * setting of HW_OCOTP_CTRL[BUSY]. In addition HW_OCOTP_CTRL[ERROR] will | ||
261 | * be set. It must be cleared by software before any new write access | ||
262 | * can be issued. | ||
263 | */ | ||
264 | ret = imx_ocotp_wait_for_busy(priv->base, 0); | ||
265 | if (ret < 0) { | ||
266 | if (ret == -EPERM) { | ||
267 | dev_err(priv->dev, "failed write to locked region"); | ||
268 | imx_ocotp_clr_err_if_set(priv->base); | ||
269 | } else { | ||
270 | dev_err(priv->dev, "timeout during data write\n"); | ||
271 | } | ||
272 | goto write_end; | ||
273 | } | ||
274 | |||
275 | /* 47.3.1.4 | ||
276 | * Write Postamble: Due to internal electrical characteristics of the | ||
277 | * OTP during writes, all OTP operations following a write must be | ||
278 | * separated by 2 us after the clearing of HW_OCOTP_CTRL_BUSY following | ||
279 | * the write. | ||
280 | */ | ||
281 | udelay(2); | ||
282 | |||
283 | /* reload all shadow registers */ | ||
284 | writel(IMX_OCOTP_BM_CTRL_REL_SHADOWS, | ||
285 | priv->base + IMX_OCOTP_ADDR_CTRL_SET); | ||
286 | ret = imx_ocotp_wait_for_busy(priv->base, | ||
287 | IMX_OCOTP_BM_CTRL_REL_SHADOWS); | ||
288 | if (ret < 0) { | ||
289 | dev_err(priv->dev, "timeout during shadow register reload\n"); | ||
290 | goto write_end; | ||
291 | } | ||
292 | |||
293 | write_end: | ||
294 | clk_disable_unprepare(priv->clk); | ||
295 | mutex_unlock(&ocotp_mutex); | ||
296 | if (ret < 0) | ||
297 | return ret; | ||
298 | return bytes; | ||
61 | } | 299 | } |
62 | 300 | ||
63 | static struct nvmem_config imx_ocotp_nvmem_config = { | 301 | static struct nvmem_config imx_ocotp_nvmem_config = { |
64 | .name = "imx-ocotp", | 302 | .name = "imx-ocotp", |
65 | .read_only = true, | 303 | .read_only = false, |
66 | .word_size = 4, | 304 | .word_size = 4, |
67 | .stride = 4, | 305 | .stride = 4, |
68 | .owner = THIS_MODULE, | 306 | .owner = THIS_MODULE, |
69 | .reg_read = imx_ocotp_read, | 307 | .reg_read = imx_ocotp_read, |
308 | .reg_write = imx_ocotp_write, | ||
70 | }; | 309 | }; |
71 | 310 | ||
72 | static const struct of_device_id imx_ocotp_dt_ids[] = { | 311 | static const struct of_device_id imx_ocotp_dt_ids[] = { |
@@ -74,6 +313,7 @@ static const struct of_device_id imx_ocotp_dt_ids[] = { | |||
74 | { .compatible = "fsl,imx6sl-ocotp", (void *)64 }, | 313 | { .compatible = "fsl,imx6sl-ocotp", (void *)64 }, |
75 | { .compatible = "fsl,imx6sx-ocotp", (void *)128 }, | 314 | { .compatible = "fsl,imx6sx-ocotp", (void *)128 }, |
76 | { .compatible = "fsl,imx6ul-ocotp", (void *)128 }, | 315 | { .compatible = "fsl,imx6ul-ocotp", (void *)128 }, |
316 | { .compatible = "fsl,imx7d-ocotp", (void *)64 }, | ||
77 | { }, | 317 | { }, |
78 | }; | 318 | }; |
79 | MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids); | 319 | MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids); |
@@ -90,12 +330,14 @@ static int imx_ocotp_probe(struct platform_device *pdev) | |||
90 | if (!priv) | 330 | if (!priv) |
91 | return -ENOMEM; | 331 | return -ENOMEM; |
92 | 332 | ||
333 | priv->dev = dev; | ||
334 | |||
93 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 335 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
94 | priv->base = devm_ioremap_resource(dev, res); | 336 | priv->base = devm_ioremap_resource(dev, res); |
95 | if (IS_ERR(priv->base)) | 337 | if (IS_ERR(priv->base)) |
96 | return PTR_ERR(priv->base); | 338 | return PTR_ERR(priv->base); |
97 | 339 | ||
98 | priv->clk = devm_clk_get(&pdev->dev, NULL); | 340 | priv->clk = devm_clk_get(dev, NULL); |
99 | if (IS_ERR(priv->clk)) | 341 | if (IS_ERR(priv->clk)) |
100 | return PTR_ERR(priv->clk); | 342 | return PTR_ERR(priv->clk); |
101 | 343 | ||
@@ -104,7 +346,9 @@ static int imx_ocotp_probe(struct platform_device *pdev) | |||
104 | imx_ocotp_nvmem_config.size = 4 * priv->nregs; | 346 | imx_ocotp_nvmem_config.size = 4 * priv->nregs; |
105 | imx_ocotp_nvmem_config.dev = dev; | 347 | imx_ocotp_nvmem_config.dev = dev; |
106 | imx_ocotp_nvmem_config.priv = priv; | 348 | imx_ocotp_nvmem_config.priv = priv; |
349 | priv->config = &imx_ocotp_nvmem_config; | ||
107 | nvmem = nvmem_register(&imx_ocotp_nvmem_config); | 350 | nvmem = nvmem_register(&imx_ocotp_nvmem_config); |
351 | |||
108 | if (IS_ERR(nvmem)) | 352 | if (IS_ERR(nvmem)) |
109 | return PTR_ERR(nvmem); | 353 | return PTR_ERR(nvmem); |
110 | 354 | ||
diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c index 1567ccca8de3..0d6648be93b8 100644 --- a/drivers/nvmem/sunxi_sid.c +++ b/drivers/nvmem/sunxi_sid.c | |||
@@ -17,13 +17,24 @@ | |||
17 | 17 | ||
18 | #include <linux/device.h> | 18 | #include <linux/device.h> |
19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | #include <linux/iopoll.h> | ||
20 | #include <linux/module.h> | 21 | #include <linux/module.h> |
21 | #include <linux/nvmem-provider.h> | 22 | #include <linux/nvmem-provider.h> |
22 | #include <linux/of.h> | 23 | #include <linux/of.h> |
24 | #include <linux/of_device.h> | ||
23 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
24 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
25 | #include <linux/random.h> | 27 | #include <linux/random.h> |
26 | 28 | ||
29 | /* Registers and special values for doing register-based SID readout on H3 */ | ||
30 | #define SUN8I_SID_PRCTL 0x40 | ||
31 | #define SUN8I_SID_RDKEY 0x60 | ||
32 | |||
33 | #define SUN8I_SID_OFFSET_MASK 0x1FF | ||
34 | #define SUN8I_SID_OFFSET_SHIFT 16 | ||
35 | #define SUN8I_SID_OP_LOCK (0xAC << 8) | ||
36 | #define SUN8I_SID_READ BIT(1) | ||
37 | |||
27 | static struct nvmem_config econfig = { | 38 | static struct nvmem_config econfig = { |
28 | .name = "sunxi-sid", | 39 | .name = "sunxi-sid", |
29 | .read_only = true, | 40 | .read_only = true, |
@@ -32,8 +43,15 @@ static struct nvmem_config econfig = { | |||
32 | .owner = THIS_MODULE, | 43 | .owner = THIS_MODULE, |
33 | }; | 44 | }; |
34 | 45 | ||
46 | struct sunxi_sid_cfg { | ||
47 | u32 value_offset; | ||
48 | u32 size; | ||
49 | bool need_register_readout; | ||
50 | }; | ||
51 | |||
35 | struct sunxi_sid { | 52 | struct sunxi_sid { |
36 | void __iomem *base; | 53 | void __iomem *base; |
54 | u32 value_offset; | ||
37 | }; | 55 | }; |
38 | 56 | ||
39 | /* We read the entire key, due to a 32 bit read alignment requirement. Since we | 57 | /* We read the entire key, due to a 32 bit read alignment requirement. Since we |
@@ -58,12 +76,36 @@ static int sunxi_sid_read(void *context, unsigned int offset, | |||
58 | struct sunxi_sid *sid = context; | 76 | struct sunxi_sid *sid = context; |
59 | u8 *buf = val; | 77 | u8 *buf = val; |
60 | 78 | ||
79 | /* Offset the read operation to the real position of SID */ | ||
80 | offset += sid->value_offset; | ||
81 | |||
61 | while (bytes--) | 82 | while (bytes--) |
62 | *buf++ = sunxi_sid_read_byte(sid, offset++); | 83 | *buf++ = sunxi_sid_read_byte(sid, offset++); |
63 | 84 | ||
64 | return 0; | 85 | return 0; |
65 | } | 86 | } |
66 | 87 | ||
88 | static int sun8i_sid_register_readout(const struct sunxi_sid *sid, | ||
89 | const unsigned int word) | ||
90 | { | ||
91 | u32 reg_val; | ||
92 | int ret; | ||
93 | |||
94 | /* Set word, lock access, and set read command */ | ||
95 | reg_val = (word & SUN8I_SID_OFFSET_MASK) | ||
96 | << SUN8I_SID_OFFSET_SHIFT; | ||
97 | reg_val |= SUN8I_SID_OP_LOCK | SUN8I_SID_READ; | ||
98 | writel(reg_val, sid->base + SUN8I_SID_PRCTL); | ||
99 | |||
100 | ret = readl_poll_timeout(sid->base + SUN8I_SID_PRCTL, reg_val, | ||
101 | !(reg_val & SUN8I_SID_READ), 100, 250000); | ||
102 | if (ret) | ||
103 | return ret; | ||
104 | |||
105 | writel(0, sid->base + SUN8I_SID_PRCTL); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
67 | static int sunxi_sid_probe(struct platform_device *pdev) | 109 | static int sunxi_sid_probe(struct platform_device *pdev) |
68 | { | 110 | { |
69 | struct device *dev = &pdev->dev; | 111 | struct device *dev = &pdev->dev; |
@@ -72,18 +114,42 @@ static int sunxi_sid_probe(struct platform_device *pdev) | |||
72 | struct sunxi_sid *sid; | 114 | struct sunxi_sid *sid; |
73 | int ret, i, size; | 115 | int ret, i, size; |
74 | char *randomness; | 116 | char *randomness; |
117 | const struct sunxi_sid_cfg *cfg; | ||
75 | 118 | ||
76 | sid = devm_kzalloc(dev, sizeof(*sid), GFP_KERNEL); | 119 | sid = devm_kzalloc(dev, sizeof(*sid), GFP_KERNEL); |
77 | if (!sid) | 120 | if (!sid) |
78 | return -ENOMEM; | 121 | return -ENOMEM; |
79 | 122 | ||
123 | cfg = of_device_get_match_data(dev); | ||
124 | if (!cfg) | ||
125 | return -EINVAL; | ||
126 | sid->value_offset = cfg->value_offset; | ||
127 | |||
80 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 128 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
81 | sid->base = devm_ioremap_resource(dev, res); | 129 | sid->base = devm_ioremap_resource(dev, res); |
82 | if (IS_ERR(sid->base)) | 130 | if (IS_ERR(sid->base)) |
83 | return PTR_ERR(sid->base); | 131 | return PTR_ERR(sid->base); |
84 | 132 | ||
85 | size = resource_size(res) - 1; | 133 | size = cfg->size; |
86 | econfig.size = resource_size(res); | 134 | |
135 | if (cfg->need_register_readout) { | ||
136 | /* | ||
137 | * H3's SID controller have a bug that the value at 0x200 | ||
138 | * offset is not the correct value when the hardware is reseted. | ||
139 | * However, after doing a register-based read operation, the | ||
140 | * value become right. | ||
141 | * Do a full read operation here, but ignore its value | ||
142 | * (as it's more fast to read by direct MMIO value than | ||
143 | * with registers) | ||
144 | */ | ||
145 | for (i = 0; i < (size >> 2); i++) { | ||
146 | ret = sun8i_sid_register_readout(sid, i); | ||
147 | if (ret) | ||
148 | return ret; | ||
149 | } | ||
150 | } | ||
151 | |||
152 | econfig.size = size; | ||
87 | econfig.dev = dev; | 153 | econfig.dev = dev; |
88 | econfig.reg_read = sunxi_sid_read; | 154 | econfig.reg_read = sunxi_sid_read; |
89 | econfig.priv = sid; | 155 | econfig.priv = sid; |
@@ -119,9 +185,24 @@ static int sunxi_sid_remove(struct platform_device *pdev) | |||
119 | return nvmem_unregister(nvmem); | 185 | return nvmem_unregister(nvmem); |
120 | } | 186 | } |
121 | 187 | ||
188 | static const struct sunxi_sid_cfg sun4i_a10_cfg = { | ||
189 | .size = 0x10, | ||
190 | }; | ||
191 | |||
192 | static const struct sunxi_sid_cfg sun7i_a20_cfg = { | ||
193 | .size = 0x200, | ||
194 | }; | ||
195 | |||
196 | static const struct sunxi_sid_cfg sun8i_h3_cfg = { | ||
197 | .value_offset = 0x200, | ||
198 | .size = 0x100, | ||
199 | .need_register_readout = true, | ||
200 | }; | ||
201 | |||
122 | static const struct of_device_id sunxi_sid_of_match[] = { | 202 | static const struct of_device_id sunxi_sid_of_match[] = { |
123 | { .compatible = "allwinner,sun4i-a10-sid" }, | 203 | { .compatible = "allwinner,sun4i-a10-sid", .data = &sun4i_a10_cfg }, |
124 | { .compatible = "allwinner,sun7i-a20-sid" }, | 204 | { .compatible = "allwinner,sun7i-a20-sid", .data = &sun7i_a20_cfg }, |
205 | { .compatible = "allwinner,sun8i-h3-sid", .data = &sun8i_h3_cfg }, | ||
125 | {/* sentinel */}, | 206 | {/* sentinel */}, |
126 | }; | 207 | }; |
127 | MODULE_DEVICE_TABLE(of, sunxi_sid_of_match); | 208 | MODULE_DEVICE_TABLE(of, sunxi_sid_of_match); |
diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c index 6f09da4dadb8..6aa120cd0574 100644 --- a/drivers/platform/chrome/cros_ec_dev.c +++ b/drivers/platform/chrome/cros_ec_dev.c | |||
@@ -391,7 +391,6 @@ static int ec_device_probe(struct platform_device *pdev) | |||
391 | int retval = -ENOMEM; | 391 | int retval = -ENOMEM; |
392 | struct device *dev = &pdev->dev; | 392 | struct device *dev = &pdev->dev; |
393 | struct cros_ec_platform *ec_platform = dev_get_platdata(dev); | 393 | struct cros_ec_platform *ec_platform = dev_get_platdata(dev); |
394 | dev_t devno = MKDEV(ec_major, pdev->id); | ||
395 | struct cros_ec_dev *ec = kzalloc(sizeof(*ec), GFP_KERNEL); | 394 | struct cros_ec_dev *ec = kzalloc(sizeof(*ec), GFP_KERNEL); |
396 | 395 | ||
397 | if (!ec) | 396 | if (!ec) |
@@ -407,23 +406,11 @@ static int ec_device_probe(struct platform_device *pdev) | |||
407 | cdev_init(&ec->cdev, &fops); | 406 | cdev_init(&ec->cdev, &fops); |
408 | 407 | ||
409 | /* | 408 | /* |
410 | * Add the character device | ||
411 | * Link cdev to the class device to be sure device is not used | ||
412 | * before unbinding it. | ||
413 | */ | ||
414 | ec->cdev.kobj.parent = &ec->class_dev.kobj; | ||
415 | retval = cdev_add(&ec->cdev, devno, 1); | ||
416 | if (retval) { | ||
417 | dev_err(dev, ": failed to add character device\n"); | ||
418 | goto cdev_add_failed; | ||
419 | } | ||
420 | |||
421 | /* | ||
422 | * Add the class device | 409 | * Add the class device |
423 | * Link to the character device for creating the /dev entry | 410 | * Link to the character device for creating the /dev entry |
424 | * in devtmpfs. | 411 | * in devtmpfs. |
425 | */ | 412 | */ |
426 | ec->class_dev.devt = ec->cdev.dev; | 413 | ec->class_dev.devt = MKDEV(ec_major, pdev->id); |
427 | ec->class_dev.class = &cros_class; | 414 | ec->class_dev.class = &cros_class; |
428 | ec->class_dev.parent = dev; | 415 | ec->class_dev.parent = dev; |
429 | ec->class_dev.release = __remove; | 416 | ec->class_dev.release = __remove; |
@@ -431,13 +418,13 @@ static int ec_device_probe(struct platform_device *pdev) | |||
431 | retval = dev_set_name(&ec->class_dev, "%s", ec_platform->ec_name); | 418 | retval = dev_set_name(&ec->class_dev, "%s", ec_platform->ec_name); |
432 | if (retval) { | 419 | if (retval) { |
433 | dev_err(dev, "dev_set_name failed => %d\n", retval); | 420 | dev_err(dev, "dev_set_name failed => %d\n", retval); |
434 | goto set_named_failed; | 421 | goto failed; |
435 | } | 422 | } |
436 | 423 | ||
437 | retval = device_add(&ec->class_dev); | 424 | retval = cdev_device_add(&ec->cdev, &ec->class_dev); |
438 | if (retval) { | 425 | if (retval) { |
439 | dev_err(dev, "device_register failed => %d\n", retval); | 426 | dev_err(dev, "cdev_device_add failed => %d\n", retval); |
440 | goto dev_reg_failed; | 427 | goto failed; |
441 | } | 428 | } |
442 | 429 | ||
443 | /* check whether this EC is a sensor hub. */ | 430 | /* check whether this EC is a sensor hub. */ |
@@ -446,12 +433,8 @@ static int ec_device_probe(struct platform_device *pdev) | |||
446 | 433 | ||
447 | return 0; | 434 | return 0; |
448 | 435 | ||
449 | dev_reg_failed: | 436 | failed: |
450 | set_named_failed: | 437 | put_device(&ec->class_dev); |
451 | dev_set_drvdata(dev, NULL); | ||
452 | cdev_del(&ec->cdev); | ||
453 | cdev_add_failed: | ||
454 | kfree(ec); | ||
455 | return retval; | 438 | return retval; |
456 | } | 439 | } |
457 | 440 | ||
diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 2b21033f11f0..2de1e603bd2b 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2011 Google, Inc. | ||
3 | * Copyright (C) 2012 Intel, Inc. | 2 | * Copyright (C) 2012 Intel, Inc. |
4 | * Copyright (C) 2013 Intel, Inc. | 3 | * Copyright (C) 2013 Intel, Inc. |
5 | * Copyright (C) 2014 Linaro Limited | 4 | * Copyright (C) 2014 Linaro Limited |
5 | * Copyright (C) 2011-2016 Google, Inc. | ||
6 | * | 6 | * |
7 | * This software is licensed under the terms of the GNU General Public | 7 | * This software is licensed under the terms of the GNU General Public |
8 | * License version 2, as published by the Free Software Foundation, and | 8 | * License version 2, as published by the Free Software Foundation, and |
@@ -46,6 +46,7 @@ | |||
46 | * exchange is properly mapped during a transfer. | 46 | * exchange is properly mapped during a transfer. |
47 | */ | 47 | */ |
48 | 48 | ||
49 | |||
49 | #include <linux/module.h> | 50 | #include <linux/module.h> |
50 | #include <linux/interrupt.h> | 51 | #include <linux/interrupt.h> |
51 | #include <linux/kernel.h> | 52 | #include <linux/kernel.h> |
@@ -63,122 +64,232 @@ | |||
63 | #include <linux/acpi.h> | 64 | #include <linux/acpi.h> |
64 | 65 | ||
65 | /* | 66 | /* |
67 | * Update this when something changes in the driver's behavior so the host | ||
68 | * can benefit from knowing it | ||
69 | */ | ||
70 | enum { | ||
71 | PIPE_DRIVER_VERSION = 2, | ||
72 | PIPE_CURRENT_DEVICE_VERSION = 2 | ||
73 | }; | ||
74 | |||
75 | /* | ||
66 | * IMPORTANT: The following constants must match the ones used and defined | 76 | * IMPORTANT: The following constants must match the ones used and defined |
67 | * in external/qemu/hw/goldfish_pipe.c in the Android source tree. | 77 | * in external/qemu/hw/goldfish_pipe.c in the Android source tree. |
68 | */ | 78 | */ |
69 | 79 | ||
70 | /* pipe device registers */ | ||
71 | #define PIPE_REG_COMMAND 0x00 /* write: value = command */ | ||
72 | #define PIPE_REG_STATUS 0x04 /* read */ | ||
73 | #define PIPE_REG_CHANNEL 0x08 /* read/write: channel id */ | ||
74 | #define PIPE_REG_CHANNEL_HIGH 0x30 /* read/write: channel id */ | ||
75 | #define PIPE_REG_SIZE 0x0c /* read/write: buffer size */ | ||
76 | #define PIPE_REG_ADDRESS 0x10 /* write: physical address */ | ||
77 | #define PIPE_REG_ADDRESS_HIGH 0x34 /* write: physical address */ | ||
78 | #define PIPE_REG_WAKES 0x14 /* read: wake flags */ | ||
79 | #define PIPE_REG_PARAMS_ADDR_LOW 0x18 /* read/write: batch data address */ | ||
80 | #define PIPE_REG_PARAMS_ADDR_HIGH 0x1c /* read/write: batch data address */ | ||
81 | #define PIPE_REG_ACCESS_PARAMS 0x20 /* write: batch access */ | ||
82 | #define PIPE_REG_VERSION 0x24 /* read: device version */ | ||
83 | |||
84 | /* list of commands for PIPE_REG_COMMAND */ | ||
85 | #define CMD_OPEN 1 /* open new channel */ | ||
86 | #define CMD_CLOSE 2 /* close channel (from guest) */ | ||
87 | #define CMD_POLL 3 /* poll read/write status */ | ||
88 | |||
89 | /* List of bitflags returned in status of CMD_POLL command */ | 80 | /* List of bitflags returned in status of CMD_POLL command */ |
90 | #define PIPE_POLL_IN (1 << 0) | 81 | enum PipePollFlags { |
91 | #define PIPE_POLL_OUT (1 << 1) | 82 | PIPE_POLL_IN = 1 << 0, |
92 | #define PIPE_POLL_HUP (1 << 2) | 83 | PIPE_POLL_OUT = 1 << 1, |
93 | 84 | PIPE_POLL_HUP = 1 << 2 | |
94 | /* The following commands are related to write operations */ | 85 | }; |
95 | #define CMD_WRITE_BUFFER 4 /* send a user buffer to the emulator */ | ||
96 | #define CMD_WAKE_ON_WRITE 5 /* tell the emulator to wake us when writing | ||
97 | is possible */ | ||
98 | #define CMD_READ_BUFFER 6 /* receive a user buffer from the emulator */ | ||
99 | #define CMD_WAKE_ON_READ 7 /* tell the emulator to wake us when reading | ||
100 | * is possible */ | ||
101 | 86 | ||
102 | /* Possible status values used to signal errors - see goldfish_pipe_error_convert */ | 87 | /* Possible status values used to signal errors - see goldfish_pipe_error_convert */ |
103 | #define PIPE_ERROR_INVAL -1 | 88 | enum PipeErrors { |
104 | #define PIPE_ERROR_AGAIN -2 | 89 | PIPE_ERROR_INVAL = -1, |
105 | #define PIPE_ERROR_NOMEM -3 | 90 | PIPE_ERROR_AGAIN = -2, |
106 | #define PIPE_ERROR_IO -4 | 91 | PIPE_ERROR_NOMEM = -3, |
92 | PIPE_ERROR_IO = -4 | ||
93 | }; | ||
107 | 94 | ||
108 | /* Bit-flags used to signal events from the emulator */ | 95 | /* Bit-flags used to signal events from the emulator */ |
109 | #define PIPE_WAKE_CLOSED (1 << 0) /* emulator closed pipe */ | 96 | enum PipeWakeFlags { |
110 | #define PIPE_WAKE_READ (1 << 1) /* pipe can now be read from */ | 97 | PIPE_WAKE_CLOSED = 1 << 0, /* emulator closed pipe */ |
111 | #define PIPE_WAKE_WRITE (1 << 2) /* pipe can now be written to */ | 98 | PIPE_WAKE_READ = 1 << 1, /* pipe can now be read from */ |
112 | 99 | PIPE_WAKE_WRITE = 1 << 2 /* pipe can now be written to */ | |
113 | struct access_params { | 100 | }; |
114 | unsigned long channel; | 101 | |
115 | u32 size; | 102 | /* Bit flags for the 'flags' field */ |
116 | unsigned long address; | 103 | enum PipeFlagsBits { |
117 | u32 cmd; | 104 | BIT_CLOSED_ON_HOST = 0, /* pipe closed by host */ |
118 | u32 result; | 105 | BIT_WAKE_ON_WRITE = 1, /* want to be woken on writes */ |
119 | /* reserved for future extension */ | 106 | BIT_WAKE_ON_READ = 2, /* want to be woken on reads */ |
107 | }; | ||
108 | |||
109 | enum PipeRegs { | ||
110 | PIPE_REG_CMD = 0, | ||
111 | |||
112 | PIPE_REG_SIGNAL_BUFFER_HIGH = 4, | ||
113 | PIPE_REG_SIGNAL_BUFFER = 8, | ||
114 | PIPE_REG_SIGNAL_BUFFER_COUNT = 12, | ||
115 | |||
116 | PIPE_REG_OPEN_BUFFER_HIGH = 20, | ||
117 | PIPE_REG_OPEN_BUFFER = 24, | ||
118 | |||
119 | PIPE_REG_VERSION = 36, | ||
120 | |||
121 | PIPE_REG_GET_SIGNALLED = 48, | ||
122 | }; | ||
123 | |||
124 | enum PipeCmdCode { | ||
125 | PIPE_CMD_OPEN = 1, /* to be used by the pipe device itself */ | ||
126 | PIPE_CMD_CLOSE, | ||
127 | PIPE_CMD_POLL, | ||
128 | PIPE_CMD_WRITE, | ||
129 | PIPE_CMD_WAKE_ON_WRITE, | ||
130 | PIPE_CMD_READ, | ||
131 | PIPE_CMD_WAKE_ON_READ, | ||
132 | |||
133 | /* | ||
134 | * TODO(zyy): implement a deferred read/write execution to allow | ||
135 | * parallel processing of pipe operations on the host. | ||
136 | */ | ||
137 | PIPE_CMD_WAKE_ON_DONE_IO, | ||
138 | }; | ||
139 | |||
140 | enum { | ||
141 | MAX_BUFFERS_PER_COMMAND = 336, | ||
142 | MAX_SIGNALLED_PIPES = 64, | ||
143 | INITIAL_PIPES_CAPACITY = 64 | ||
144 | }; | ||
145 | |||
146 | struct goldfish_pipe_dev; | ||
147 | struct goldfish_pipe; | ||
148 | struct goldfish_pipe_command; | ||
149 | |||
150 | /* A per-pipe command structure, shared with the host */ | ||
151 | struct goldfish_pipe_command { | ||
152 | s32 cmd; /* PipeCmdCode, guest -> host */ | ||
153 | s32 id; /* pipe id, guest -> host */ | ||
154 | s32 status; /* command execution status, host -> guest */ | ||
155 | s32 reserved; /* to pad to 64-bit boundary */ | ||
156 | union { | ||
157 | /* Parameters for PIPE_CMD_{READ,WRITE} */ | ||
158 | struct { | ||
159 | /* number of buffers, guest -> host */ | ||
160 | u32 buffers_count; | ||
161 | /* number of consumed bytes, host -> guest */ | ||
162 | s32 consumed_size; | ||
163 | /* buffer pointers, guest -> host */ | ||
164 | u64 ptrs[MAX_BUFFERS_PER_COMMAND]; | ||
165 | /* buffer sizes, guest -> host */ | ||
166 | u32 sizes[MAX_BUFFERS_PER_COMMAND]; | ||
167 | } rw_params; | ||
168 | }; | ||
169 | }; | ||
170 | |||
171 | /* A single signalled pipe information */ | ||
172 | struct signalled_pipe_buffer { | ||
173 | u32 id; | ||
120 | u32 flags; | 174 | u32 flags; |
121 | }; | 175 | }; |
122 | 176 | ||
123 | /* The global driver data. Holds a reference to the i/o page used to | 177 | /* Parameters for the PIPE_CMD_OPEN command */ |
124 | * communicate with the emulator, and a wake queue for blocked tasks | 178 | struct open_command_param { |
125 | * waiting to be awoken. | 179 | u64 command_buffer_ptr; |
126 | */ | 180 | u32 rw_params_max_count; |
127 | struct goldfish_pipe_dev { | ||
128 | spinlock_t lock; | ||
129 | unsigned char __iomem *base; | ||
130 | struct access_params *aps; | ||
131 | int irq; | ||
132 | u32 version; | ||
133 | }; | 181 | }; |
134 | 182 | ||
135 | static struct goldfish_pipe_dev pipe_dev[1]; | 183 | /* Device-level set of buffers shared with the host */ |
184 | struct goldfish_pipe_dev_buffers { | ||
185 | struct open_command_param open_command_params; | ||
186 | struct signalled_pipe_buffer signalled_pipe_buffers[ | ||
187 | MAX_SIGNALLED_PIPES]; | ||
188 | }; | ||
136 | 189 | ||
137 | /* This data type models a given pipe instance */ | 190 | /* This data type models a given pipe instance */ |
138 | struct goldfish_pipe { | 191 | struct goldfish_pipe { |
139 | struct goldfish_pipe_dev *dev; | 192 | /* pipe ID - index into goldfish_pipe_dev::pipes array */ |
140 | struct mutex lock; | 193 | u32 id; |
194 | /* The wake flags pipe is waiting for | ||
195 | * Note: not protected with any lock, uses atomic operations | ||
196 | * and barriers to make it thread-safe. | ||
197 | */ | ||
141 | unsigned long flags; | 198 | unsigned long flags; |
199 | /* wake flags host have signalled, | ||
200 | * - protected by goldfish_pipe_dev::lock | ||
201 | */ | ||
202 | unsigned long signalled_flags; | ||
203 | |||
204 | /* A pointer to command buffer */ | ||
205 | struct goldfish_pipe_command *command_buffer; | ||
206 | |||
207 | /* doubly linked list of signalled pipes, protected by | ||
208 | * goldfish_pipe_dev::lock | ||
209 | */ | ||
210 | struct goldfish_pipe *prev_signalled; | ||
211 | struct goldfish_pipe *next_signalled; | ||
212 | |||
213 | /* | ||
214 | * A pipe's own lock. Protects the following: | ||
215 | * - *command_buffer - makes sure a command can safely write its | ||
216 | * parameters to the host and read the results back. | ||
217 | */ | ||
218 | struct mutex lock; | ||
219 | |||
220 | /* A wake queue for sleeping until host signals an event */ | ||
142 | wait_queue_head_t wake_queue; | 221 | wait_queue_head_t wake_queue; |
222 | /* Pointer to the parent goldfish_pipe_dev instance */ | ||
223 | struct goldfish_pipe_dev *dev; | ||
143 | }; | 224 | }; |
144 | 225 | ||
226 | /* The global driver data. Holds a reference to the i/o page used to | ||
227 | * communicate with the emulator, and a wake queue for blocked tasks | ||
228 | * waiting to be awoken. | ||
229 | */ | ||
230 | struct goldfish_pipe_dev { | ||
231 | /* | ||
232 | * Global device spinlock. Protects the following members: | ||
233 | * - pipes, pipes_capacity | ||
234 | * - [*pipes, *pipes + pipes_capacity) - array data | ||
235 | * - first_signalled_pipe, | ||
236 | * goldfish_pipe::prev_signalled, | ||
237 | * goldfish_pipe::next_signalled, | ||
238 | * goldfish_pipe::signalled_flags - all singnalled-related fields, | ||
239 | * in all allocated pipes | ||
240 | * - open_command_params - PIPE_CMD_OPEN-related buffers | ||
241 | * | ||
242 | * It looks like a lot of different fields, but the trick is that | ||
243 | * the only operation that happens often is the signalled pipes array | ||
244 | * manipulation. That's why it's OK for now to keep the rest of the | ||
245 | * fields under the same lock. If we notice too much contention because | ||
246 | * of PIPE_CMD_OPEN, then we should add a separate lock there. | ||
247 | */ | ||
248 | spinlock_t lock; | ||
145 | 249 | ||
146 | /* Bit flags for the 'flags' field */ | 250 | /* |
147 | enum { | 251 | * Array of the pipes of |pipes_capacity| elements, |
148 | BIT_CLOSED_ON_HOST = 0, /* pipe closed by host */ | 252 | * indexed by goldfish_pipe::id |
149 | BIT_WAKE_ON_WRITE = 1, /* want to be woken on writes */ | 253 | */ |
150 | BIT_WAKE_ON_READ = 2, /* want to be woken on reads */ | 254 | struct goldfish_pipe **pipes; |
255 | u32 pipes_capacity; | ||
256 | |||
257 | /* Pointers to the buffers host uses for interaction with this driver */ | ||
258 | struct goldfish_pipe_dev_buffers *buffers; | ||
259 | |||
260 | /* Head of a doubly linked list of signalled pipes */ | ||
261 | struct goldfish_pipe *first_signalled_pipe; | ||
262 | |||
263 | /* Some device-specific data */ | ||
264 | int irq; | ||
265 | int version; | ||
266 | unsigned char __iomem *base; | ||
151 | }; | 267 | }; |
152 | 268 | ||
269 | struct goldfish_pipe_dev pipe_dev[1] = {}; | ||
153 | 270 | ||
154 | static u32 goldfish_cmd_status(struct goldfish_pipe *pipe, u32 cmd) | 271 | static int goldfish_cmd_locked(struct goldfish_pipe *pipe, enum PipeCmdCode cmd) |
155 | { | 272 | { |
156 | unsigned long flags; | 273 | pipe->command_buffer->cmd = cmd; |
157 | u32 status; | 274 | /* failure by default */ |
158 | struct goldfish_pipe_dev *dev = pipe->dev; | 275 | pipe->command_buffer->status = PIPE_ERROR_INVAL; |
159 | 276 | writel(pipe->id, pipe->dev->base + PIPE_REG_CMD); | |
160 | spin_lock_irqsave(&dev->lock, flags); | 277 | return pipe->command_buffer->status; |
161 | gf_write_ptr(pipe, dev->base + PIPE_REG_CHANNEL, | ||
162 | dev->base + PIPE_REG_CHANNEL_HIGH); | ||
163 | writel(cmd, dev->base + PIPE_REG_COMMAND); | ||
164 | status = readl(dev->base + PIPE_REG_STATUS); | ||
165 | spin_unlock_irqrestore(&dev->lock, flags); | ||
166 | return status; | ||
167 | } | 278 | } |
168 | 279 | ||
169 | static void goldfish_cmd(struct goldfish_pipe *pipe, u32 cmd) | 280 | static int goldfish_cmd(struct goldfish_pipe *pipe, enum PipeCmdCode cmd) |
170 | { | 281 | { |
171 | unsigned long flags; | 282 | int status; |
172 | struct goldfish_pipe_dev *dev = pipe->dev; | ||
173 | 283 | ||
174 | spin_lock_irqsave(&dev->lock, flags); | 284 | if (mutex_lock_interruptible(&pipe->lock)) |
175 | gf_write_ptr(pipe, dev->base + PIPE_REG_CHANNEL, | 285 | return PIPE_ERROR_IO; |
176 | dev->base + PIPE_REG_CHANNEL_HIGH); | 286 | status = goldfish_cmd_locked(pipe, cmd); |
177 | writel(cmd, dev->base + PIPE_REG_COMMAND); | 287 | mutex_unlock(&pipe->lock); |
178 | spin_unlock_irqrestore(&dev->lock, flags); | 288 | return status; |
179 | } | 289 | } |
180 | 290 | ||
181 | /* This function converts an error code returned by the emulator through | 291 | /* |
292 | * This function converts an error code returned by the emulator through | ||
182 | * the PIPE_REG_STATUS i/o register into a valid negative errno value. | 293 | * the PIPE_REG_STATUS i/o register into a valid negative errno value. |
183 | */ | 294 | */ |
184 | static int goldfish_pipe_error_convert(int status) | 295 | static int goldfish_pipe_error_convert(int status) |
@@ -195,184 +306,202 @@ static int goldfish_pipe_error_convert(int status) | |||
195 | } | 306 | } |
196 | } | 307 | } |
197 | 308 | ||
198 | /* | 309 | static int pin_user_pages(unsigned long first_page, unsigned long last_page, |
199 | * Notice: QEMU will return 0 for un-known register access, indicating | 310 | unsigned int last_page_size, int is_write, |
200 | * param_acess is supported or not | 311 | struct page *pages[MAX_BUFFERS_PER_COMMAND], |
201 | */ | 312 | unsigned int *iter_last_page_size) |
202 | static int valid_batchbuffer_addr(struct goldfish_pipe_dev *dev, | ||
203 | struct access_params *aps) | ||
204 | { | 313 | { |
205 | u32 aph, apl; | 314 | int ret; |
206 | u64 paddr; | 315 | int requested_pages = ((last_page - first_page) >> PAGE_SHIFT) + 1; |
207 | aph = readl(dev->base + PIPE_REG_PARAMS_ADDR_HIGH); | 316 | |
208 | apl = readl(dev->base + PIPE_REG_PARAMS_ADDR_LOW); | 317 | if (requested_pages > MAX_BUFFERS_PER_COMMAND) { |
318 | requested_pages = MAX_BUFFERS_PER_COMMAND; | ||
319 | *iter_last_page_size = PAGE_SIZE; | ||
320 | } else { | ||
321 | *iter_last_page_size = last_page_size; | ||
322 | } | ||
323 | |||
324 | ret = get_user_pages_fast( | ||
325 | first_page, requested_pages, !is_write, pages); | ||
326 | if (ret <= 0) | ||
327 | return -EFAULT; | ||
328 | if (ret < requested_pages) | ||
329 | *iter_last_page_size = PAGE_SIZE; | ||
330 | return ret; | ||
209 | 331 | ||
210 | paddr = ((u64)aph << 32) | apl; | ||
211 | if (paddr != (__pa(aps))) | ||
212 | return 0; | ||
213 | return 1; | ||
214 | } | 332 | } |
215 | 333 | ||
216 | /* 0 on success */ | 334 | static void release_user_pages(struct page **pages, int pages_count, |
217 | static int setup_access_params_addr(struct platform_device *pdev, | 335 | int is_write, s32 consumed_size) |
218 | struct goldfish_pipe_dev *dev) | ||
219 | { | 336 | { |
220 | dma_addr_t dma_handle; | 337 | int i; |
221 | struct access_params *aps; | ||
222 | 338 | ||
223 | aps = dmam_alloc_coherent(&pdev->dev, sizeof(struct access_params), | 339 | for (i = 0; i < pages_count; i++) { |
224 | &dma_handle, GFP_KERNEL); | 340 | if (!is_write && consumed_size > 0) |
225 | if (!aps) | 341 | set_page_dirty(pages[i]); |
226 | return -ENOMEM; | 342 | put_page(pages[i]); |
343 | } | ||
344 | } | ||
345 | |||
346 | /* Populate the call parameters, merging adjacent pages together */ | ||
347 | static void populate_rw_params( | ||
348 | struct page **pages, int pages_count, | ||
349 | unsigned long address, unsigned long address_end, | ||
350 | unsigned long first_page, unsigned long last_page, | ||
351 | unsigned int iter_last_page_size, int is_write, | ||
352 | struct goldfish_pipe_command *command) | ||
353 | { | ||
354 | /* | ||
355 | * Process the first page separately - it's the only page that | ||
356 | * needs special handling for its start address. | ||
357 | */ | ||
358 | unsigned long xaddr = page_to_phys(pages[0]); | ||
359 | unsigned long xaddr_prev = xaddr; | ||
360 | int buffer_idx = 0; | ||
361 | int i = 1; | ||
362 | int size_on_page = first_page == last_page | ||
363 | ? (int)(address_end - address) | ||
364 | : (PAGE_SIZE - (address & ~PAGE_MASK)); | ||
365 | command->rw_params.ptrs[0] = (u64)(xaddr | (address & ~PAGE_MASK)); | ||
366 | command->rw_params.sizes[0] = size_on_page; | ||
367 | for (; i < pages_count; ++i) { | ||
368 | xaddr = page_to_phys(pages[i]); | ||
369 | size_on_page = (i == pages_count - 1) ? | ||
370 | iter_last_page_size : PAGE_SIZE; | ||
371 | if (xaddr == xaddr_prev + PAGE_SIZE) { | ||
372 | command->rw_params.sizes[buffer_idx] += size_on_page; | ||
373 | } else { | ||
374 | ++buffer_idx; | ||
375 | command->rw_params.ptrs[buffer_idx] = (u64)xaddr; | ||
376 | command->rw_params.sizes[buffer_idx] = size_on_page; | ||
377 | } | ||
378 | xaddr_prev = xaddr; | ||
379 | } | ||
380 | command->rw_params.buffers_count = buffer_idx + 1; | ||
381 | } | ||
227 | 382 | ||
228 | writel(upper_32_bits(dma_handle), dev->base + PIPE_REG_PARAMS_ADDR_HIGH); | 383 | static int transfer_max_buffers(struct goldfish_pipe *pipe, |
229 | writel(lower_32_bits(dma_handle), dev->base + PIPE_REG_PARAMS_ADDR_LOW); | 384 | unsigned long address, unsigned long address_end, int is_write, |
385 | unsigned long last_page, unsigned int last_page_size, | ||
386 | s32 *consumed_size, int *status) | ||
387 | { | ||
388 | static struct page *pages[MAX_BUFFERS_PER_COMMAND]; | ||
389 | unsigned long first_page = address & PAGE_MASK; | ||
390 | unsigned int iter_last_page_size; | ||
391 | int pages_count = pin_user_pages(first_page, last_page, | ||
392 | last_page_size, is_write, | ||
393 | pages, &iter_last_page_size); | ||
230 | 394 | ||
231 | if (valid_batchbuffer_addr(dev, aps)) { | 395 | if (pages_count < 0) |
232 | dev->aps = aps; | 396 | return pages_count; |
233 | return 0; | 397 | |
234 | } else | 398 | /* Serialize access to the pipe command buffers */ |
235 | return -1; | 399 | if (mutex_lock_interruptible(&pipe->lock)) |
400 | return -ERESTARTSYS; | ||
401 | |||
402 | populate_rw_params(pages, pages_count, address, address_end, | ||
403 | first_page, last_page, iter_last_page_size, is_write, | ||
404 | pipe->command_buffer); | ||
405 | |||
406 | /* Transfer the data */ | ||
407 | *status = goldfish_cmd_locked(pipe, | ||
408 | is_write ? PIPE_CMD_WRITE : PIPE_CMD_READ); | ||
409 | |||
410 | *consumed_size = pipe->command_buffer->rw_params.consumed_size; | ||
411 | |||
412 | release_user_pages(pages, pages_count, is_write, *consumed_size); | ||
413 | |||
414 | mutex_unlock(&pipe->lock); | ||
415 | |||
416 | return 0; | ||
236 | } | 417 | } |
237 | 418 | ||
238 | /* A value that will not be set by qemu emulator */ | 419 | static int wait_for_host_signal(struct goldfish_pipe *pipe, int is_write) |
239 | #define INITIAL_BATCH_RESULT (0xdeadbeaf) | ||
240 | static int access_with_param(struct goldfish_pipe_dev *dev, const int cmd, | ||
241 | unsigned long address, unsigned long avail, | ||
242 | struct goldfish_pipe *pipe, int *status) | ||
243 | { | 420 | { |
244 | struct access_params *aps = dev->aps; | 421 | u32 wakeBit = is_write ? BIT_WAKE_ON_WRITE : BIT_WAKE_ON_READ; |
245 | 422 | ||
246 | if (aps == NULL) | 423 | set_bit(wakeBit, &pipe->flags); |
247 | return -1; | 424 | |
425 | /* Tell the emulator we're going to wait for a wake event */ | ||
426 | (void)goldfish_cmd(pipe, | ||
427 | is_write ? PIPE_CMD_WAKE_ON_WRITE : PIPE_CMD_WAKE_ON_READ); | ||
428 | |||
429 | while (test_bit(wakeBit, &pipe->flags)) { | ||
430 | if (wait_event_interruptible( | ||
431 | pipe->wake_queue, | ||
432 | !test_bit(wakeBit, &pipe->flags))) | ||
433 | return -ERESTARTSYS; | ||
434 | |||
435 | if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags)) | ||
436 | return -EIO; | ||
437 | } | ||
248 | 438 | ||
249 | aps->result = INITIAL_BATCH_RESULT; | ||
250 | aps->channel = (unsigned long)pipe; | ||
251 | aps->size = avail; | ||
252 | aps->address = address; | ||
253 | aps->cmd = cmd; | ||
254 | writel(cmd, dev->base + PIPE_REG_ACCESS_PARAMS); | ||
255 | /* | ||
256 | * If the aps->result has not changed, that means | ||
257 | * that the batch command failed | ||
258 | */ | ||
259 | if (aps->result == INITIAL_BATCH_RESULT) | ||
260 | return -1; | ||
261 | *status = aps->result; | ||
262 | return 0; | 439 | return 0; |
263 | } | 440 | } |
264 | 441 | ||
265 | static ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer, | 442 | static ssize_t goldfish_pipe_read_write(struct file *filp, |
266 | size_t bufflen, int is_write) | 443 | char __user *buffer, size_t bufflen, int is_write) |
267 | { | 444 | { |
268 | unsigned long irq_flags; | ||
269 | struct goldfish_pipe *pipe = filp->private_data; | 445 | struct goldfish_pipe *pipe = filp->private_data; |
270 | struct goldfish_pipe_dev *dev = pipe->dev; | ||
271 | unsigned long address, address_end; | ||
272 | int count = 0, ret = -EINVAL; | 446 | int count = 0, ret = -EINVAL; |
447 | unsigned long address, address_end, last_page; | ||
448 | unsigned int last_page_size; | ||
273 | 449 | ||
274 | /* If the emulator already closed the pipe, no need to go further */ | 450 | /* If the emulator already closed the pipe, no need to go further */ |
275 | if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags)) | 451 | if (unlikely(test_bit(BIT_CLOSED_ON_HOST, &pipe->flags))) |
276 | return -EIO; | 452 | return -EIO; |
277 | |||
278 | /* Null reads or writes succeeds */ | 453 | /* Null reads or writes succeeds */ |
279 | if (unlikely(bufflen == 0)) | 454 | if (unlikely(bufflen == 0)) |
280 | return 0; | 455 | return 0; |
281 | |||
282 | /* Check the buffer range for access */ | 456 | /* Check the buffer range for access */ |
283 | if (!access_ok(is_write ? VERIFY_WRITE : VERIFY_READ, | 457 | if (unlikely(!access_ok(is_write ? VERIFY_WRITE : VERIFY_READ, |
284 | buffer, bufflen)) | 458 | buffer, bufflen))) |
285 | return -EFAULT; | 459 | return -EFAULT; |
286 | 460 | ||
287 | /* Serialize access to the pipe */ | 461 | address = (unsigned long)buffer; |
288 | if (mutex_lock_interruptible(&pipe->lock)) | ||
289 | return -ERESTARTSYS; | ||
290 | |||
291 | address = (unsigned long)(void *)buffer; | ||
292 | address_end = address + bufflen; | 462 | address_end = address + bufflen; |
463 | last_page = (address_end - 1) & PAGE_MASK; | ||
464 | last_page_size = ((address_end - 1) & ~PAGE_MASK) + 1; | ||
293 | 465 | ||
294 | while (address < address_end) { | 466 | while (address < address_end) { |
295 | unsigned long page_end = (address & PAGE_MASK) + PAGE_SIZE; | 467 | s32 consumed_size; |
296 | unsigned long next = page_end < address_end ? page_end | 468 | int status; |
297 | : address_end; | ||
298 | unsigned long avail = next - address; | ||
299 | int status, wakeBit; | ||
300 | struct page *page; | ||
301 | |||
302 | /* Either vaddr or paddr depending on the device version */ | ||
303 | unsigned long xaddr; | ||
304 | 469 | ||
305 | /* | 470 | ret = transfer_max_buffers(pipe, address, address_end, is_write, |
306 | * We grab the pages on a page-by-page basis in case user | 471 | last_page, last_page_size, &consumed_size, |
307 | * space gives us a potentially huge buffer but the read only | 472 | &status); |
308 | * returns a small amount, then there's no need to pin that | ||
309 | * much memory to the process. | ||
310 | */ | ||
311 | ret = get_user_pages_unlocked(address, 1, &page, | ||
312 | is_write ? 0 : FOLL_WRITE); | ||
313 | if (ret < 0) | 473 | if (ret < 0) |
314 | break; | 474 | break; |
315 | 475 | ||
316 | if (dev->version) { | 476 | if (consumed_size > 0) { |
317 | /* Device version 1 or newer (qemu-android) expects the | 477 | /* No matter what's the status, we've transferred |
318 | * physical address. | 478 | * something. |
319 | */ | 479 | */ |
320 | xaddr = page_to_phys(page) | (address & ~PAGE_MASK); | 480 | count += consumed_size; |
321 | } else { | 481 | address += consumed_size; |
322 | /* Device version 0 (classic emulator) expects the | ||
323 | * virtual address. | ||
324 | */ | ||
325 | xaddr = address; | ||
326 | } | 482 | } |
327 | 483 | if (status > 0) | |
328 | /* Now, try to transfer the bytes in the current page */ | ||
329 | spin_lock_irqsave(&dev->lock, irq_flags); | ||
330 | if (access_with_param(dev, | ||
331 | is_write ? CMD_WRITE_BUFFER : CMD_READ_BUFFER, | ||
332 | xaddr, avail, pipe, &status)) { | ||
333 | gf_write_ptr(pipe, dev->base + PIPE_REG_CHANNEL, | ||
334 | dev->base + PIPE_REG_CHANNEL_HIGH); | ||
335 | writel(avail, dev->base + PIPE_REG_SIZE); | ||
336 | gf_write_ptr((void *)xaddr, | ||
337 | dev->base + PIPE_REG_ADDRESS, | ||
338 | dev->base + PIPE_REG_ADDRESS_HIGH); | ||
339 | writel(is_write ? CMD_WRITE_BUFFER : CMD_READ_BUFFER, | ||
340 | dev->base + PIPE_REG_COMMAND); | ||
341 | status = readl(dev->base + PIPE_REG_STATUS); | ||
342 | } | ||
343 | spin_unlock_irqrestore(&dev->lock, irq_flags); | ||
344 | |||
345 | if (status > 0 && !is_write) | ||
346 | set_page_dirty(page); | ||
347 | put_page(page); | ||
348 | |||
349 | if (status > 0) { /* Correct transfer */ | ||
350 | count += status; | ||
351 | address += status; | ||
352 | continue; | 484 | continue; |
353 | } else if (status == 0) { /* EOF */ | 485 | if (status == 0) { |
486 | /* EOF */ | ||
354 | ret = 0; | 487 | ret = 0; |
355 | break; | 488 | break; |
356 | } else if (status < 0 && count > 0) { | 489 | } |
490 | if (count > 0) { | ||
357 | /* | 491 | /* |
358 | * An error occurred and we already transferred | 492 | * An error occurred, but we already transferred |
359 | * something on one of the previous pages. | 493 | * something on one of the previous iterations. |
360 | * Just return what we already copied and log this | 494 | * Just return what we already copied and log this |
361 | * err. | 495 | * err. |
362 | * | ||
363 | * Note: This seems like an incorrect approach but | ||
364 | * cannot change it until we check if any user space | ||
365 | * ABI relies on this behavior. | ||
366 | */ | 496 | */ |
367 | if (status != PIPE_ERROR_AGAIN) | 497 | if (status != PIPE_ERROR_AGAIN) |
368 | pr_info_ratelimited("goldfish_pipe: backend returned error %d on %s\n", | 498 | pr_info_ratelimited("goldfish_pipe: backend error %d on %s\n", |
369 | status, is_write ? "write" : "read"); | 499 | status, is_write ? "write" : "read"); |
370 | ret = 0; | ||
371 | break; | 500 | break; |
372 | } | 501 | } |
373 | 502 | ||
374 | /* | 503 | /* |
375 | * If the error is not PIPE_ERROR_AGAIN, or if we are not in | 504 | * If the error is not PIPE_ERROR_AGAIN, or if we are in |
376 | * non-blocking mode, just return the error code. | 505 | * non-blocking mode, just return the error code. |
377 | */ | 506 | */ |
378 | if (status != PIPE_ERROR_AGAIN || | 507 | if (status != PIPE_ERROR_AGAIN || |
@@ -381,139 +510,214 @@ static ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer, | |||
381 | break; | 510 | break; |
382 | } | 511 | } |
383 | 512 | ||
384 | /* | 513 | status = wait_for_host_signal(pipe, is_write); |
385 | * The backend blocked the read/write, wait until the backend | 514 | if (status < 0) |
386 | * tells us it's ready to process more data. | 515 | return status; |
387 | */ | ||
388 | wakeBit = is_write ? BIT_WAKE_ON_WRITE : BIT_WAKE_ON_READ; | ||
389 | set_bit(wakeBit, &pipe->flags); | ||
390 | |||
391 | /* Tell the emulator we're going to wait for a wake event */ | ||
392 | goldfish_cmd(pipe, | ||
393 | is_write ? CMD_WAKE_ON_WRITE : CMD_WAKE_ON_READ); | ||
394 | |||
395 | /* Unlock the pipe, then wait for the wake signal */ | ||
396 | mutex_unlock(&pipe->lock); | ||
397 | |||
398 | while (test_bit(wakeBit, &pipe->flags)) { | ||
399 | if (wait_event_interruptible( | ||
400 | pipe->wake_queue, | ||
401 | !test_bit(wakeBit, &pipe->flags))) | ||
402 | return -ERESTARTSYS; | ||
403 | |||
404 | if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags)) | ||
405 | return -EIO; | ||
406 | } | ||
407 | |||
408 | /* Try to re-acquire the lock */ | ||
409 | if (mutex_lock_interruptible(&pipe->lock)) | ||
410 | return -ERESTARTSYS; | ||
411 | } | 516 | } |
412 | mutex_unlock(&pipe->lock); | ||
413 | 517 | ||
414 | if (ret < 0) | 518 | if (count > 0) |
415 | return ret; | ||
416 | else | ||
417 | return count; | 519 | return count; |
520 | return ret; | ||
418 | } | 521 | } |
419 | 522 | ||
420 | static ssize_t goldfish_pipe_read(struct file *filp, char __user *buffer, | 523 | static ssize_t goldfish_pipe_read(struct file *filp, char __user *buffer, |
421 | size_t bufflen, loff_t *ppos) | 524 | size_t bufflen, loff_t *ppos) |
422 | { | 525 | { |
423 | return goldfish_pipe_read_write(filp, buffer, bufflen, 0); | 526 | return goldfish_pipe_read_write(filp, buffer, bufflen, |
527 | /* is_write */ 0); | ||
424 | } | 528 | } |
425 | 529 | ||
426 | static ssize_t goldfish_pipe_write(struct file *filp, | 530 | static ssize_t goldfish_pipe_write(struct file *filp, |
427 | const char __user *buffer, size_t bufflen, | 531 | const char __user *buffer, size_t bufflen, |
428 | loff_t *ppos) | 532 | loff_t *ppos) |
429 | { | 533 | { |
430 | return goldfish_pipe_read_write(filp, (char __user *)buffer, | 534 | return goldfish_pipe_read_write(filp, |
431 | bufflen, 1); | 535 | /* cast away the const */(char __user *)buffer, bufflen, |
536 | /* is_write */ 1); | ||
432 | } | 537 | } |
433 | 538 | ||
434 | |||
435 | static unsigned int goldfish_pipe_poll(struct file *filp, poll_table *wait) | 539 | static unsigned int goldfish_pipe_poll(struct file *filp, poll_table *wait) |
436 | { | 540 | { |
437 | struct goldfish_pipe *pipe = filp->private_data; | 541 | struct goldfish_pipe *pipe = filp->private_data; |
438 | unsigned int mask = 0; | 542 | unsigned int mask = 0; |
439 | int status; | 543 | int status; |
440 | 544 | ||
441 | mutex_lock(&pipe->lock); | ||
442 | |||
443 | poll_wait(filp, &pipe->wake_queue, wait); | 545 | poll_wait(filp, &pipe->wake_queue, wait); |
444 | 546 | ||
445 | status = goldfish_cmd_status(pipe, CMD_POLL); | 547 | status = goldfish_cmd(pipe, PIPE_CMD_POLL); |
446 | 548 | if (status < 0) | |
447 | mutex_unlock(&pipe->lock); | 549 | return -ERESTARTSYS; |
448 | 550 | ||
449 | if (status & PIPE_POLL_IN) | 551 | if (status & PIPE_POLL_IN) |
450 | mask |= POLLIN | POLLRDNORM; | 552 | mask |= POLLIN | POLLRDNORM; |
451 | |||
452 | if (status & PIPE_POLL_OUT) | 553 | if (status & PIPE_POLL_OUT) |
453 | mask |= POLLOUT | POLLWRNORM; | 554 | mask |= POLLOUT | POLLWRNORM; |
454 | |||
455 | if (status & PIPE_POLL_HUP) | 555 | if (status & PIPE_POLL_HUP) |
456 | mask |= POLLHUP; | 556 | mask |= POLLHUP; |
457 | |||
458 | if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags)) | 557 | if (test_bit(BIT_CLOSED_ON_HOST, &pipe->flags)) |
459 | mask |= POLLERR; | 558 | mask |= POLLERR; |
460 | 559 | ||
461 | return mask; | 560 | return mask; |
462 | } | 561 | } |
463 | 562 | ||
464 | static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id) | 563 | static void signalled_pipes_add_locked(struct goldfish_pipe_dev *dev, |
564 | u32 id, u32 flags) | ||
465 | { | 565 | { |
466 | struct goldfish_pipe_dev *dev = dev_id; | 566 | struct goldfish_pipe *pipe; |
467 | unsigned long irq_flags; | ||
468 | int count = 0; | ||
469 | 567 | ||
470 | /* | 568 | if (WARN_ON(id >= dev->pipes_capacity)) |
471 | * We're going to read from the emulator a list of (channel,flags) | 569 | return; |
472 | * pairs corresponding to the wake events that occurred on each | 570 | |
473 | * blocked pipe (i.e. channel). | 571 | pipe = dev->pipes[id]; |
474 | */ | 572 | if (!pipe) |
475 | spin_lock_irqsave(&dev->lock, irq_flags); | 573 | return; |
476 | for (;;) { | 574 | pipe->signalled_flags |= flags; |
477 | /* First read the channel, 0 means the end of the list */ | 575 | |
478 | struct goldfish_pipe *pipe; | 576 | if (pipe->prev_signalled || pipe->next_signalled |
479 | unsigned long wakes; | 577 | || dev->first_signalled_pipe == pipe) |
480 | unsigned long channel = 0; | 578 | return; /* already in the list */ |
579 | pipe->next_signalled = dev->first_signalled_pipe; | ||
580 | if (dev->first_signalled_pipe) | ||
581 | dev->first_signalled_pipe->prev_signalled = pipe; | ||
582 | dev->first_signalled_pipe = pipe; | ||
583 | } | ||
481 | 584 | ||
482 | #ifdef CONFIG_64BIT | 585 | static void signalled_pipes_remove_locked(struct goldfish_pipe_dev *dev, |
483 | channel = (u64)readl(dev->base + PIPE_REG_CHANNEL_HIGH) << 32; | 586 | struct goldfish_pipe *pipe) { |
587 | if (pipe->prev_signalled) | ||
588 | pipe->prev_signalled->next_signalled = pipe->next_signalled; | ||
589 | if (pipe->next_signalled) | ||
590 | pipe->next_signalled->prev_signalled = pipe->prev_signalled; | ||
591 | if (pipe == dev->first_signalled_pipe) | ||
592 | dev->first_signalled_pipe = pipe->next_signalled; | ||
593 | pipe->prev_signalled = NULL; | ||
594 | pipe->next_signalled = NULL; | ||
595 | } | ||
484 | 596 | ||
485 | if (channel == 0) | 597 | static struct goldfish_pipe *signalled_pipes_pop_front( |
486 | break; | 598 | struct goldfish_pipe_dev *dev, int *wakes) |
487 | #endif | 599 | { |
488 | channel |= readl(dev->base + PIPE_REG_CHANNEL); | 600 | struct goldfish_pipe *pipe; |
601 | unsigned long flags; | ||
489 | 602 | ||
490 | if (channel == 0) | 603 | spin_lock_irqsave(&dev->lock, flags); |
491 | break; | ||
492 | 604 | ||
493 | /* Convert channel to struct pipe pointer + read wake flags */ | 605 | pipe = dev->first_signalled_pipe; |
494 | wakes = readl(dev->base + PIPE_REG_WAKES); | 606 | if (pipe) { |
495 | pipe = (struct goldfish_pipe *)(ptrdiff_t)channel; | 607 | *wakes = pipe->signalled_flags; |
608 | pipe->signalled_flags = 0; | ||
609 | /* | ||
610 | * This is an optimized version of | ||
611 | * signalled_pipes_remove_locked() | ||
612 | * - We want to make it as fast as possible to | ||
613 | * wake the sleeping pipe operations faster. | ||
614 | */ | ||
615 | dev->first_signalled_pipe = pipe->next_signalled; | ||
616 | if (dev->first_signalled_pipe) | ||
617 | dev->first_signalled_pipe->prev_signalled = NULL; | ||
618 | pipe->next_signalled = NULL; | ||
619 | } | ||
496 | 620 | ||
497 | /* Did the emulator just closed a pipe? */ | 621 | spin_unlock_irqrestore(&dev->lock, flags); |
622 | return pipe; | ||
623 | } | ||
624 | |||
625 | static void goldfish_interrupt_task(unsigned long unused) | ||
626 | { | ||
627 | struct goldfish_pipe_dev *dev = pipe_dev; | ||
628 | /* Iterate over the signalled pipes and wake them one by one */ | ||
629 | struct goldfish_pipe *pipe; | ||
630 | int wakes; | ||
631 | |||
632 | while ((pipe = signalled_pipes_pop_front(dev, &wakes)) != NULL) { | ||
498 | if (wakes & PIPE_WAKE_CLOSED) { | 633 | if (wakes & PIPE_WAKE_CLOSED) { |
499 | set_bit(BIT_CLOSED_ON_HOST, &pipe->flags); | 634 | pipe->flags = 1 << BIT_CLOSED_ON_HOST; |
500 | wakes |= PIPE_WAKE_READ | PIPE_WAKE_WRITE; | 635 | } else { |
636 | if (wakes & PIPE_WAKE_READ) | ||
637 | clear_bit(BIT_WAKE_ON_READ, &pipe->flags); | ||
638 | if (wakes & PIPE_WAKE_WRITE) | ||
639 | clear_bit(BIT_WAKE_ON_WRITE, &pipe->flags); | ||
501 | } | 640 | } |
502 | if (wakes & PIPE_WAKE_READ) | 641 | /* |
503 | clear_bit(BIT_WAKE_ON_READ, &pipe->flags); | 642 | * wake_up_interruptible() implies a write barrier, so don't |
504 | if (wakes & PIPE_WAKE_WRITE) | 643 | * explicitly add another one here. |
505 | clear_bit(BIT_WAKE_ON_WRITE, &pipe->flags); | 644 | */ |
506 | |||
507 | wake_up_interruptible(&pipe->wake_queue); | 645 | wake_up_interruptible(&pipe->wake_queue); |
508 | count++; | ||
509 | } | 646 | } |
510 | spin_unlock_irqrestore(&dev->lock, irq_flags); | 647 | } |
648 | DECLARE_TASKLET(goldfish_interrupt_tasklet, goldfish_interrupt_task, 0); | ||
511 | 649 | ||
512 | return (count == 0) ? IRQ_NONE : IRQ_HANDLED; | 650 | /* |
651 | * The general idea of the interrupt handling: | ||
652 | * | ||
653 | * 1. device raises an interrupt if there's at least one signalled pipe | ||
654 | * 2. IRQ handler reads the signalled pipes and their count from the device | ||
655 | * 3. device writes them into a shared buffer and returns the count | ||
656 | * it only resets the IRQ if it has returned all signalled pipes, | ||
657 | * otherwise it leaves it raised, so IRQ handler will be called | ||
658 | * again for the next chunk | ||
659 | * 4. IRQ handler adds all returned pipes to the device's signalled pipes list | ||
660 | * 5. IRQ handler launches a tasklet to process the signalled pipes from the | ||
661 | * list in a separate context | ||
662 | */ | ||
663 | static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id) | ||
664 | { | ||
665 | u32 count; | ||
666 | u32 i; | ||
667 | unsigned long flags; | ||
668 | struct goldfish_pipe_dev *dev = dev_id; | ||
669 | |||
670 | if (dev != pipe_dev) | ||
671 | return IRQ_NONE; | ||
672 | |||
673 | /* Request the signalled pipes from the device */ | ||
674 | spin_lock_irqsave(&dev->lock, flags); | ||
675 | |||
676 | count = readl(dev->base + PIPE_REG_GET_SIGNALLED); | ||
677 | if (count == 0) { | ||
678 | spin_unlock_irqrestore(&dev->lock, flags); | ||
679 | return IRQ_NONE; | ||
680 | } | ||
681 | if (count > MAX_SIGNALLED_PIPES) | ||
682 | count = MAX_SIGNALLED_PIPES; | ||
683 | |||
684 | for (i = 0; i < count; ++i) | ||
685 | signalled_pipes_add_locked(dev, | ||
686 | dev->buffers->signalled_pipe_buffers[i].id, | ||
687 | dev->buffers->signalled_pipe_buffers[i].flags); | ||
688 | |||
689 | spin_unlock_irqrestore(&dev->lock, flags); | ||
690 | |||
691 | tasklet_schedule(&goldfish_interrupt_tasklet); | ||
692 | return IRQ_HANDLED; | ||
693 | } | ||
694 | |||
695 | static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev) | ||
696 | { | ||
697 | int id; | ||
698 | |||
699 | for (id = 0; id < dev->pipes_capacity; ++id) | ||
700 | if (!dev->pipes[id]) | ||
701 | return id; | ||
702 | |||
703 | { | ||
704 | /* Reallocate the array */ | ||
705 | u32 new_capacity = 2 * dev->pipes_capacity; | ||
706 | struct goldfish_pipe **pipes = | ||
707 | kcalloc(new_capacity, sizeof(*pipes), GFP_KERNEL); | ||
708 | if (!pipes) | ||
709 | return -ENOMEM; | ||
710 | memcpy(pipes, dev->pipes, sizeof(*pipes) * dev->pipes_capacity); | ||
711 | kfree(dev->pipes); | ||
712 | dev->pipes = pipes; | ||
713 | id = dev->pipes_capacity; | ||
714 | dev->pipes_capacity = new_capacity; | ||
715 | } | ||
716 | return id; | ||
513 | } | 717 | } |
514 | 718 | ||
515 | /** | 719 | /** |
516 | * goldfish_pipe_open - open a channel to the AVD | 720 | * goldfish_pipe_open - open a channel to the AVD |
517 | * @inode: inode of device | 721 | * @inode: inode of device |
518 | * @file: file struct of opener | 722 | * @file: file struct of opener |
519 | * | 723 | * |
@@ -525,12 +729,13 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id) | |||
525 | */ | 729 | */ |
526 | static int goldfish_pipe_open(struct inode *inode, struct file *file) | 730 | static int goldfish_pipe_open(struct inode *inode, struct file *file) |
527 | { | 731 | { |
528 | struct goldfish_pipe *pipe; | ||
529 | struct goldfish_pipe_dev *dev = pipe_dev; | 732 | struct goldfish_pipe_dev *dev = pipe_dev; |
530 | int32_t status; | 733 | unsigned long flags; |
734 | int id; | ||
735 | int status; | ||
531 | 736 | ||
532 | /* Allocate new pipe kernel object */ | 737 | /* Allocate new pipe kernel object */ |
533 | pipe = kzalloc(sizeof(*pipe), GFP_KERNEL); | 738 | struct goldfish_pipe *pipe = kzalloc(sizeof(*pipe), GFP_KERNEL); |
534 | if (pipe == NULL) | 739 | if (pipe == NULL) |
535 | return -ENOMEM; | 740 | return -ENOMEM; |
536 | 741 | ||
@@ -539,29 +744,69 @@ static int goldfish_pipe_open(struct inode *inode, struct file *file) | |||
539 | init_waitqueue_head(&pipe->wake_queue); | 744 | init_waitqueue_head(&pipe->wake_queue); |
540 | 745 | ||
541 | /* | 746 | /* |
542 | * Now, tell the emulator we're opening a new pipe. We use the | 747 | * Command buffer needs to be allocated on its own page to make sure |
543 | * pipe object's address as the channel identifier for simplicity. | 748 | * it is physically contiguous in host's address space. |
544 | */ | 749 | */ |
750 | pipe->command_buffer = | ||
751 | (struct goldfish_pipe_command *)__get_free_page(GFP_KERNEL); | ||
752 | if (!pipe->command_buffer) { | ||
753 | status = -ENOMEM; | ||
754 | goto err_pipe; | ||
755 | } | ||
545 | 756 | ||
546 | status = goldfish_cmd_status(pipe, CMD_OPEN); | 757 | spin_lock_irqsave(&dev->lock, flags); |
547 | if (status < 0) { | 758 | |
548 | kfree(pipe); | 759 | id = get_free_pipe_id_locked(dev); |
549 | return status; | 760 | if (id < 0) { |
761 | status = id; | ||
762 | goto err_id_locked; | ||
550 | } | 763 | } |
551 | 764 | ||
765 | dev->pipes[id] = pipe; | ||
766 | pipe->id = id; | ||
767 | pipe->command_buffer->id = id; | ||
768 | |||
769 | /* Now tell the emulator we're opening a new pipe. */ | ||
770 | dev->buffers->open_command_params.rw_params_max_count = | ||
771 | MAX_BUFFERS_PER_COMMAND; | ||
772 | dev->buffers->open_command_params.command_buffer_ptr = | ||
773 | (u64)(unsigned long)__pa(pipe->command_buffer); | ||
774 | status = goldfish_cmd_locked(pipe, PIPE_CMD_OPEN); | ||
775 | spin_unlock_irqrestore(&dev->lock, flags); | ||
776 | if (status < 0) | ||
777 | goto err_cmd; | ||
552 | /* All is done, save the pipe into the file's private data field */ | 778 | /* All is done, save the pipe into the file's private data field */ |
553 | file->private_data = pipe; | 779 | file->private_data = pipe; |
554 | return 0; | 780 | return 0; |
781 | |||
782 | err_cmd: | ||
783 | spin_lock_irqsave(&dev->lock, flags); | ||
784 | dev->pipes[id] = NULL; | ||
785 | err_id_locked: | ||
786 | spin_unlock_irqrestore(&dev->lock, flags); | ||
787 | free_page((unsigned long)pipe->command_buffer); | ||
788 | err_pipe: | ||
789 | kfree(pipe); | ||
790 | return status; | ||
555 | } | 791 | } |
556 | 792 | ||
557 | static int goldfish_pipe_release(struct inode *inode, struct file *filp) | 793 | static int goldfish_pipe_release(struct inode *inode, struct file *filp) |
558 | { | 794 | { |
795 | unsigned long flags; | ||
559 | struct goldfish_pipe *pipe = filp->private_data; | 796 | struct goldfish_pipe *pipe = filp->private_data; |
797 | struct goldfish_pipe_dev *dev = pipe->dev; | ||
560 | 798 | ||
561 | /* The guest is closing the channel, so tell the emulator right now */ | 799 | /* The guest is closing the channel, so tell the emulator right now */ |
562 | goldfish_cmd(pipe, CMD_CLOSE); | 800 | (void)goldfish_cmd(pipe, PIPE_CMD_CLOSE); |
563 | kfree(pipe); | 801 | |
802 | spin_lock_irqsave(&dev->lock, flags); | ||
803 | dev->pipes[pipe->id] = NULL; | ||
804 | signalled_pipes_remove_locked(dev, pipe); | ||
805 | spin_unlock_irqrestore(&dev->lock, flags); | ||
806 | |||
564 | filp->private_data = NULL; | 807 | filp->private_data = NULL; |
808 | free_page((unsigned long)pipe->command_buffer); | ||
809 | kfree(pipe); | ||
565 | return 0; | 810 | return 0; |
566 | } | 811 | } |
567 | 812 | ||
@@ -574,18 +819,91 @@ static const struct file_operations goldfish_pipe_fops = { | |||
574 | .release = goldfish_pipe_release, | 819 | .release = goldfish_pipe_release, |
575 | }; | 820 | }; |
576 | 821 | ||
577 | static struct miscdevice goldfish_pipe_device = { | 822 | static struct miscdevice goldfish_pipe_dev = { |
578 | .minor = MISC_DYNAMIC_MINOR, | 823 | .minor = MISC_DYNAMIC_MINOR, |
579 | .name = "goldfish_pipe", | 824 | .name = "goldfish_pipe", |
580 | .fops = &goldfish_pipe_fops, | 825 | .fops = &goldfish_pipe_fops, |
581 | }; | 826 | }; |
582 | 827 | ||
828 | static int goldfish_pipe_device_init(struct platform_device *pdev) | ||
829 | { | ||
830 | char *page; | ||
831 | struct goldfish_pipe_dev *dev = pipe_dev; | ||
832 | int err = devm_request_irq(&pdev->dev, dev->irq, | ||
833 | goldfish_pipe_interrupt, | ||
834 | IRQF_SHARED, "goldfish_pipe", dev); | ||
835 | if (err) { | ||
836 | dev_err(&pdev->dev, "unable to allocate IRQ for v2\n"); | ||
837 | return err; | ||
838 | } | ||
839 | |||
840 | err = misc_register(&goldfish_pipe_dev); | ||
841 | if (err) { | ||
842 | dev_err(&pdev->dev, "unable to register v2 device\n"); | ||
843 | return err; | ||
844 | } | ||
845 | |||
846 | dev->first_signalled_pipe = NULL; | ||
847 | dev->pipes_capacity = INITIAL_PIPES_CAPACITY; | ||
848 | dev->pipes = kcalloc(dev->pipes_capacity, sizeof(*dev->pipes), | ||
849 | GFP_KERNEL); | ||
850 | if (!dev->pipes) | ||
851 | return -ENOMEM; | ||
852 | |||
853 | /* | ||
854 | * We're going to pass two buffers, open_command_params and | ||
855 | * signalled_pipe_buffers, to the host. This means each of those buffers | ||
856 | * needs to be contained in a single physical page. The easiest choice | ||
857 | * is to just allocate a page and place the buffers in it. | ||
858 | */ | ||
859 | if (WARN_ON(sizeof(*dev->buffers) > PAGE_SIZE)) | ||
860 | return -ENOMEM; | ||
861 | |||
862 | page = (char *)__get_free_page(GFP_KERNEL); | ||
863 | if (!page) { | ||
864 | kfree(dev->pipes); | ||
865 | return -ENOMEM; | ||
866 | } | ||
867 | dev->buffers = (struct goldfish_pipe_dev_buffers *)page; | ||
868 | |||
869 | /* Send the buffer addresses to the host */ | ||
870 | { | ||
871 | u64 paddr = __pa(&dev->buffers->signalled_pipe_buffers); | ||
872 | |||
873 | writel((u32)(unsigned long)(paddr >> 32), | ||
874 | dev->base + PIPE_REG_SIGNAL_BUFFER_HIGH); | ||
875 | writel((u32)(unsigned long)paddr, | ||
876 | dev->base + PIPE_REG_SIGNAL_BUFFER); | ||
877 | writel((u32)MAX_SIGNALLED_PIPES, | ||
878 | dev->base + PIPE_REG_SIGNAL_BUFFER_COUNT); | ||
879 | |||
880 | paddr = __pa(&dev->buffers->open_command_params); | ||
881 | writel((u32)(unsigned long)(paddr >> 32), | ||
882 | dev->base + PIPE_REG_OPEN_BUFFER_HIGH); | ||
883 | writel((u32)(unsigned long)paddr, | ||
884 | dev->base + PIPE_REG_OPEN_BUFFER); | ||
885 | } | ||
886 | return 0; | ||
887 | } | ||
888 | |||
889 | static void goldfish_pipe_device_deinit(struct platform_device *pdev) | ||
890 | { | ||
891 | struct goldfish_pipe_dev *dev = pipe_dev; | ||
892 | |||
893 | misc_deregister(&goldfish_pipe_dev); | ||
894 | kfree(dev->pipes); | ||
895 | free_page((unsigned long)dev->buffers); | ||
896 | } | ||
897 | |||
583 | static int goldfish_pipe_probe(struct platform_device *pdev) | 898 | static int goldfish_pipe_probe(struct platform_device *pdev) |
584 | { | 899 | { |
585 | int err; | 900 | int err; |
586 | struct resource *r; | 901 | struct resource *r; |
587 | struct goldfish_pipe_dev *dev = pipe_dev; | 902 | struct goldfish_pipe_dev *dev = pipe_dev; |
588 | 903 | ||
904 | if (WARN_ON(sizeof(struct goldfish_pipe_command) > PAGE_SIZE)) | ||
905 | return -ENOMEM; | ||
906 | |||
589 | /* not thread safe, but this should not happen */ | 907 | /* not thread safe, but this should not happen */ |
590 | WARN_ON(dev->base != NULL); | 908 | WARN_ON(dev->base != NULL); |
591 | 909 | ||
@@ -609,26 +927,21 @@ static int goldfish_pipe_probe(struct platform_device *pdev) | |||
609 | } | 927 | } |
610 | dev->irq = r->start; | 928 | dev->irq = r->start; |
611 | 929 | ||
612 | err = devm_request_irq(&pdev->dev, dev->irq, goldfish_pipe_interrupt, | 930 | /* |
613 | IRQF_SHARED, "goldfish_pipe", dev); | 931 | * Exchange the versions with the host device |
614 | if (err) { | 932 | * |
615 | dev_err(&pdev->dev, "unable to allocate IRQ\n"); | 933 | * Note: v1 driver used to not report its version, so we write it before |
616 | goto error; | 934 | * reading device version back: this allows the host implementation to |
617 | } | 935 | * detect the old driver (if there was no version write before read). |
618 | |||
619 | err = misc_register(&goldfish_pipe_device); | ||
620 | if (err) { | ||
621 | dev_err(&pdev->dev, "unable to register device\n"); | ||
622 | goto error; | ||
623 | } | ||
624 | setup_access_params_addr(pdev, dev); | ||
625 | |||
626 | /* Although the pipe device in the classic Android emulator does not | ||
627 | * recognize the 'version' register, it won't treat this as an error | ||
628 | * either and will simply return 0, which is fine. | ||
629 | */ | 936 | */ |
937 | writel((u32)PIPE_DRIVER_VERSION, dev->base + PIPE_REG_VERSION); | ||
630 | dev->version = readl(dev->base + PIPE_REG_VERSION); | 938 | dev->version = readl(dev->base + PIPE_REG_VERSION); |
631 | return 0; | 939 | if (WARN_ON(dev->version < PIPE_CURRENT_DEVICE_VERSION)) |
940 | return -EINVAL; | ||
941 | |||
942 | err = goldfish_pipe_device_init(pdev); | ||
943 | if (!err) | ||
944 | return 0; | ||
632 | 945 | ||
633 | error: | 946 | error: |
634 | dev->base = NULL; | 947 | dev->base = NULL; |
@@ -638,7 +951,7 @@ error: | |||
638 | static int goldfish_pipe_remove(struct platform_device *pdev) | 951 | static int goldfish_pipe_remove(struct platform_device *pdev) |
639 | { | 952 | { |
640 | struct goldfish_pipe_dev *dev = pipe_dev; | 953 | struct goldfish_pipe_dev *dev = pipe_dev; |
641 | misc_deregister(&goldfish_pipe_device); | 954 | goldfish_pipe_device_deinit(pdev); |
642 | dev->base = NULL; | 955 | dev->base = NULL; |
643 | return 0; | 956 | return 0; |
644 | } | 957 | } |
@@ -655,17 +968,16 @@ static const struct of_device_id goldfish_pipe_of_match[] = { | |||
655 | }; | 968 | }; |
656 | MODULE_DEVICE_TABLE(of, goldfish_pipe_of_match); | 969 | MODULE_DEVICE_TABLE(of, goldfish_pipe_of_match); |
657 | 970 | ||
658 | static struct platform_driver goldfish_pipe = { | 971 | static struct platform_driver goldfish_pipe_driver = { |
659 | .probe = goldfish_pipe_probe, | 972 | .probe = goldfish_pipe_probe, |
660 | .remove = goldfish_pipe_remove, | 973 | .remove = goldfish_pipe_remove, |
661 | .driver = { | 974 | .driver = { |
662 | .name = "goldfish_pipe", | 975 | .name = "goldfish_pipe", |
663 | .owner = THIS_MODULE, | ||
664 | .of_match_table = goldfish_pipe_of_match, | 976 | .of_match_table = goldfish_pipe_of_match, |
665 | .acpi_match_table = ACPI_PTR(goldfish_pipe_acpi_match), | 977 | .acpi_match_table = ACPI_PTR(goldfish_pipe_acpi_match), |
666 | } | 978 | } |
667 | }; | 979 | }; |
668 | 980 | ||
669 | module_platform_driver(goldfish_pipe); | 981 | module_platform_driver(goldfish_pipe_driver); |
670 | MODULE_AUTHOR("David Turner <digit@google.com>"); | 982 | MODULE_AUTHOR("David Turner <digit@google.com>"); |
671 | MODULE_LICENSE("GPL"); | 983 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index 2f07cd615665..6eb0db37dd88 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c | |||
@@ -64,6 +64,43 @@ static int pps_cdev_fasync(int fd, struct file *file, int on) | |||
64 | return fasync_helper(fd, file, on, &pps->async_queue); | 64 | return fasync_helper(fd, file, on, &pps->async_queue); |
65 | } | 65 | } |
66 | 66 | ||
67 | static int pps_cdev_pps_fetch(struct pps_device *pps, struct pps_fdata *fdata) | ||
68 | { | ||
69 | unsigned int ev = pps->last_ev; | ||
70 | int err = 0; | ||
71 | |||
72 | /* Manage the timeout */ | ||
73 | if (fdata->timeout.flags & PPS_TIME_INVALID) | ||
74 | err = wait_event_interruptible(pps->queue, | ||
75 | ev != pps->last_ev); | ||
76 | else { | ||
77 | unsigned long ticks; | ||
78 | |||
79 | dev_dbg(pps->dev, "timeout %lld.%09d\n", | ||
80 | (long long) fdata->timeout.sec, | ||
81 | fdata->timeout.nsec); | ||
82 | ticks = fdata->timeout.sec * HZ; | ||
83 | ticks += fdata->timeout.nsec / (NSEC_PER_SEC / HZ); | ||
84 | |||
85 | if (ticks != 0) { | ||
86 | err = wait_event_interruptible_timeout( | ||
87 | pps->queue, | ||
88 | ev != pps->last_ev, | ||
89 | ticks); | ||
90 | if (err == 0) | ||
91 | return -ETIMEDOUT; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | /* Check for pending signals */ | ||
96 | if (err == -ERESTARTSYS) { | ||
97 | dev_dbg(pps->dev, "pending signal caught\n"); | ||
98 | return -EINTR; | ||
99 | } | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
67 | static long pps_cdev_ioctl(struct file *file, | 104 | static long pps_cdev_ioctl(struct file *file, |
68 | unsigned int cmd, unsigned long arg) | 105 | unsigned int cmd, unsigned long arg) |
69 | { | 106 | { |
@@ -144,7 +181,6 @@ static long pps_cdev_ioctl(struct file *file, | |||
144 | 181 | ||
145 | case PPS_FETCH: { | 182 | case PPS_FETCH: { |
146 | struct pps_fdata fdata; | 183 | struct pps_fdata fdata; |
147 | unsigned int ev; | ||
148 | 184 | ||
149 | dev_dbg(pps->dev, "PPS_FETCH\n"); | 185 | dev_dbg(pps->dev, "PPS_FETCH\n"); |
150 | 186 | ||
@@ -152,36 +188,9 @@ static long pps_cdev_ioctl(struct file *file, | |||
152 | if (err) | 188 | if (err) |
153 | return -EFAULT; | 189 | return -EFAULT; |
154 | 190 | ||
155 | ev = pps->last_ev; | 191 | err = pps_cdev_pps_fetch(pps, &fdata); |
156 | 192 | if (err) | |
157 | /* Manage the timeout */ | 193 | return err; |
158 | if (fdata.timeout.flags & PPS_TIME_INVALID) | ||
159 | err = wait_event_interruptible(pps->queue, | ||
160 | ev != pps->last_ev); | ||
161 | else { | ||
162 | unsigned long ticks; | ||
163 | |||
164 | dev_dbg(pps->dev, "timeout %lld.%09d\n", | ||
165 | (long long) fdata.timeout.sec, | ||
166 | fdata.timeout.nsec); | ||
167 | ticks = fdata.timeout.sec * HZ; | ||
168 | ticks += fdata.timeout.nsec / (NSEC_PER_SEC / HZ); | ||
169 | |||
170 | if (ticks != 0) { | ||
171 | err = wait_event_interruptible_timeout( | ||
172 | pps->queue, | ||
173 | ev != pps->last_ev, | ||
174 | ticks); | ||
175 | if (err == 0) | ||
176 | return -ETIMEDOUT; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | /* Check for pending signals */ | ||
181 | if (err == -ERESTARTSYS) { | ||
182 | dev_dbg(pps->dev, "pending signal caught\n"); | ||
183 | return -EINTR; | ||
184 | } | ||
185 | 194 | ||
186 | /* Return the fetched timestamp */ | 195 | /* Return the fetched timestamp */ |
187 | spin_lock_irq(&pps->lock); | 196 | spin_lock_irq(&pps->lock); |
@@ -242,6 +251,57 @@ static long pps_cdev_ioctl(struct file *file, | |||
242 | return 0; | 251 | return 0; |
243 | } | 252 | } |
244 | 253 | ||
254 | #ifdef CONFIG_COMPAT | ||
255 | static long pps_cdev_compat_ioctl(struct file *file, | ||
256 | unsigned int cmd, unsigned long arg) | ||
257 | { | ||
258 | struct pps_device *pps = file->private_data; | ||
259 | void __user *uarg = (void __user *) arg; | ||
260 | |||
261 | cmd = _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(void *)); | ||
262 | |||
263 | if (cmd == PPS_FETCH) { | ||
264 | struct pps_fdata_compat compat; | ||
265 | struct pps_fdata fdata; | ||
266 | int err; | ||
267 | |||
268 | dev_dbg(pps->dev, "PPS_FETCH\n"); | ||
269 | |||
270 | err = copy_from_user(&compat, uarg, sizeof(struct pps_fdata_compat)); | ||
271 | if (err) | ||
272 | return -EFAULT; | ||
273 | |||
274 | memcpy(&fdata.timeout, &compat.timeout, | ||
275 | sizeof(struct pps_ktime_compat)); | ||
276 | |||
277 | err = pps_cdev_pps_fetch(pps, &fdata); | ||
278 | if (err) | ||
279 | return err; | ||
280 | |||
281 | /* Return the fetched timestamp */ | ||
282 | spin_lock_irq(&pps->lock); | ||
283 | |||
284 | compat.info.assert_sequence = pps->assert_sequence; | ||
285 | compat.info.clear_sequence = pps->clear_sequence; | ||
286 | compat.info.current_mode = pps->current_mode; | ||
287 | |||
288 | memcpy(&compat.info.assert_tu, &pps->assert_tu, | ||
289 | sizeof(struct pps_ktime_compat)); | ||
290 | memcpy(&compat.info.clear_tu, &pps->clear_tu, | ||
291 | sizeof(struct pps_ktime_compat)); | ||
292 | |||
293 | spin_unlock_irq(&pps->lock); | ||
294 | |||
295 | return copy_to_user(uarg, &compat, | ||
296 | sizeof(struct pps_fdata_compat)) ? -EFAULT : 0; | ||
297 | } | ||
298 | |||
299 | return pps_cdev_ioctl(file, cmd, arg); | ||
300 | } | ||
301 | #else | ||
302 | #define pps_cdev_compat_ioctl NULL | ||
303 | #endif | ||
304 | |||
245 | static int pps_cdev_open(struct inode *inode, struct file *file) | 305 | static int pps_cdev_open(struct inode *inode, struct file *file) |
246 | { | 306 | { |
247 | struct pps_device *pps = container_of(inode->i_cdev, | 307 | struct pps_device *pps = container_of(inode->i_cdev, |
@@ -268,6 +328,7 @@ static const struct file_operations pps_cdev_fops = { | |||
268 | .llseek = no_llseek, | 328 | .llseek = no_llseek, |
269 | .poll = pps_cdev_poll, | 329 | .poll = pps_cdev_poll, |
270 | .fasync = pps_cdev_fasync, | 330 | .fasync = pps_cdev_fasync, |
331 | .compat_ioctl = pps_cdev_compat_ioctl, | ||
271 | .unlocked_ioctl = pps_cdev_ioctl, | 332 | .unlocked_ioctl = pps_cdev_ioctl, |
272 | .open = pps_cdev_open, | 333 | .open = pps_cdev_open, |
273 | .release = pps_cdev_release, | 334 | .release = pps_cdev_release, |
diff --git a/drivers/rapidio/devices/rio_mport_cdev.c b/drivers/rapidio/devices/rio_mport_cdev.c index 50b617af81bd..5beb0c361076 100644 --- a/drivers/rapidio/devices/rio_mport_cdev.c +++ b/drivers/rapidio/devices/rio_mport_cdev.c | |||
@@ -2444,31 +2444,25 @@ static struct mport_dev *mport_cdev_add(struct rio_mport *mport) | |||
2444 | mutex_init(&md->buf_mutex); | 2444 | mutex_init(&md->buf_mutex); |
2445 | mutex_init(&md->file_mutex); | 2445 | mutex_init(&md->file_mutex); |
2446 | INIT_LIST_HEAD(&md->file_list); | 2446 | INIT_LIST_HEAD(&md->file_list); |
2447 | cdev_init(&md->cdev, &mport_fops); | ||
2448 | md->cdev.owner = THIS_MODULE; | ||
2449 | ret = cdev_add(&md->cdev, MKDEV(MAJOR(dev_number), mport->id), 1); | ||
2450 | if (ret < 0) { | ||
2451 | kfree(md); | ||
2452 | rmcd_error("Unable to register a device, err=%d", ret); | ||
2453 | return NULL; | ||
2454 | } | ||
2455 | 2447 | ||
2456 | md->dev.devt = md->cdev.dev; | 2448 | device_initialize(&md->dev); |
2449 | md->dev.devt = MKDEV(MAJOR(dev_number), mport->id); | ||
2457 | md->dev.class = dev_class; | 2450 | md->dev.class = dev_class; |
2458 | md->dev.parent = &mport->dev; | 2451 | md->dev.parent = &mport->dev; |
2459 | md->dev.release = mport_device_release; | 2452 | md->dev.release = mport_device_release; |
2460 | dev_set_name(&md->dev, DEV_NAME "%d", mport->id); | 2453 | dev_set_name(&md->dev, DEV_NAME "%d", mport->id); |
2461 | atomic_set(&md->active, 1); | 2454 | atomic_set(&md->active, 1); |
2462 | 2455 | ||
2463 | ret = device_register(&md->dev); | 2456 | cdev_init(&md->cdev, &mport_fops); |
2457 | md->cdev.owner = THIS_MODULE; | ||
2458 | |||
2459 | ret = cdev_device_add(&md->cdev, &md->dev); | ||
2464 | if (ret) { | 2460 | if (ret) { |
2465 | rmcd_error("Failed to register mport %d (err=%d)", | 2461 | rmcd_error("Failed to register mport %d (err=%d)", |
2466 | mport->id, ret); | 2462 | mport->id, ret); |
2467 | goto err_cdev; | 2463 | goto err_cdev; |
2468 | } | 2464 | } |
2469 | 2465 | ||
2470 | get_device(&md->dev); | ||
2471 | |||
2472 | INIT_LIST_HEAD(&md->doorbells); | 2466 | INIT_LIST_HEAD(&md->doorbells); |
2473 | spin_lock_init(&md->db_lock); | 2467 | spin_lock_init(&md->db_lock); |
2474 | INIT_LIST_HEAD(&md->portwrites); | 2468 | INIT_LIST_HEAD(&md->portwrites); |
@@ -2513,8 +2507,7 @@ static struct mport_dev *mport_cdev_add(struct rio_mport *mport) | |||
2513 | return md; | 2507 | return md; |
2514 | 2508 | ||
2515 | err_cdev: | 2509 | err_cdev: |
2516 | cdev_del(&md->cdev); | 2510 | put_device(&md->dev); |
2517 | kfree(md); | ||
2518 | return NULL; | 2511 | return NULL; |
2519 | } | 2512 | } |
2520 | 2513 | ||
@@ -2578,7 +2571,7 @@ static void mport_cdev_remove(struct mport_dev *md) | |||
2578 | atomic_set(&md->active, 0); | 2571 | atomic_set(&md->active, 0); |
2579 | mport_cdev_terminate_dma(md); | 2572 | mport_cdev_terminate_dma(md); |
2580 | rio_del_mport_pw_handler(md->mport, md, rio_mport_pw_handler); | 2573 | rio_del_mport_pw_handler(md->mport, md, rio_mport_pw_handler); |
2581 | cdev_del(&(md->cdev)); | 2574 | cdev_device_del(&md->cdev, &md->dev); |
2582 | mport_cdev_kill_fasync(md); | 2575 | mport_cdev_kill_fasync(md); |
2583 | 2576 | ||
2584 | flush_workqueue(dma_wq); | 2577 | flush_workqueue(dma_wq); |
@@ -2603,7 +2596,6 @@ static void mport_cdev_remove(struct mport_dev *md) | |||
2603 | 2596 | ||
2604 | rio_release_inb_dbell(md->mport, 0, 0x0fff); | 2597 | rio_release_inb_dbell(md->mport, 0, 0x0fff); |
2605 | 2598 | ||
2606 | device_unregister(&md->dev); | ||
2607 | put_device(&md->dev); | 2599 | put_device(&md->dev); |
2608 | } | 2600 | } |
2609 | 2601 | ||
diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index eda41563d06d..73e4b407f162 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c | |||
@@ -108,15 +108,11 @@ static struct attribute *rio_dev_attrs[] = { | |||
108 | &dev_attr_lprev.attr, | 108 | &dev_attr_lprev.attr, |
109 | &dev_attr_destid.attr, | 109 | &dev_attr_destid.attr, |
110 | &dev_attr_modalias.attr, | 110 | &dev_attr_modalias.attr, |
111 | NULL, | ||
112 | }; | ||
113 | 111 | ||
114 | static const struct attribute_group rio_dev_group = { | 112 | /* Switch-only attributes */ |
115 | .attrs = rio_dev_attrs, | 113 | &dev_attr_routes.attr, |
116 | }; | 114 | &dev_attr_lnext.attr, |
117 | 115 | &dev_attr_hopcount.attr, | |
118 | const struct attribute_group *rio_dev_groups[] = { | ||
119 | &rio_dev_group, | ||
120 | NULL, | 116 | NULL, |
121 | }; | 117 | }; |
122 | 118 | ||
@@ -259,46 +255,40 @@ static struct bin_attribute rio_config_attr = { | |||
259 | .write = rio_write_config, | 255 | .write = rio_write_config, |
260 | }; | 256 | }; |
261 | 257 | ||
262 | /** | 258 | static struct bin_attribute *rio_dev_bin_attrs[] = { |
263 | * rio_create_sysfs_dev_files - create RIO specific sysfs files | 259 | &rio_config_attr, |
264 | * @rdev: device whose entries should be created | 260 | NULL, |
265 | * | 261 | }; |
266 | * Create files when @rdev is added to sysfs. | ||
267 | */ | ||
268 | int rio_create_sysfs_dev_files(struct rio_dev *rdev) | ||
269 | { | ||
270 | int err = 0; | ||
271 | |||
272 | err = device_create_bin_file(&rdev->dev, &rio_config_attr); | ||
273 | 262 | ||
274 | if (!err && (rdev->pef & RIO_PEF_SWITCH)) { | 263 | static umode_t rio_dev_is_attr_visible(struct kobject *kobj, |
275 | err |= device_create_file(&rdev->dev, &dev_attr_routes); | 264 | struct attribute *attr, int n) |
276 | err |= device_create_file(&rdev->dev, &dev_attr_lnext); | 265 | { |
277 | err |= device_create_file(&rdev->dev, &dev_attr_hopcount); | 266 | struct rio_dev *rdev = to_rio_dev(kobj_to_dev(kobj)); |
267 | umode_t mode = attr->mode; | ||
268 | |||
269 | if (!(rdev->pef & RIO_PEF_SWITCH) && | ||
270 | (attr == &dev_attr_routes.attr || | ||
271 | attr == &dev_attr_lnext.attr || | ||
272 | attr == &dev_attr_hopcount.attr)) { | ||
273 | /* | ||
274 | * Hide switch-specific attributes for a non-switch device. | ||
275 | */ | ||
276 | mode = 0; | ||
278 | } | 277 | } |
279 | 278 | ||
280 | if (err) | 279 | return mode; |
281 | pr_warning("RIO: Failed to create attribute file(s) for %s\n", | ||
282 | rio_name(rdev)); | ||
283 | |||
284 | return err; | ||
285 | } | 280 | } |
286 | 281 | ||
287 | /** | 282 | static const struct attribute_group rio_dev_group = { |
288 | * rio_remove_sysfs_dev_files - cleanup RIO specific sysfs files | 283 | .attrs = rio_dev_attrs, |
289 | * @rdev: device whose entries we should free | 284 | .is_visible = rio_dev_is_attr_visible, |
290 | * | 285 | .bin_attrs = rio_dev_bin_attrs, |
291 | * Cleanup when @rdev is removed from sysfs. | 286 | }; |
292 | */ | 287 | |
293 | void rio_remove_sysfs_dev_files(struct rio_dev *rdev) | 288 | const struct attribute_group *rio_dev_groups[] = { |
294 | { | 289 | &rio_dev_group, |
295 | device_remove_bin_file(&rdev->dev, &rio_config_attr); | 290 | NULL, |
296 | if (rdev->pef & RIO_PEF_SWITCH) { | 291 | }; |
297 | device_remove_file(&rdev->dev, &dev_attr_routes); | ||
298 | device_remove_file(&rdev->dev, &dev_attr_lnext); | ||
299 | device_remove_file(&rdev->dev, &dev_attr_hopcount); | ||
300 | } | ||
301 | } | ||
302 | 292 | ||
303 | static ssize_t bus_scan_store(struct bus_type *bus, const char *buf, | 293 | static ssize_t bus_scan_store(struct bus_type *bus, const char *buf, |
304 | size_t count) | 294 | size_t count) |
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 37042858c2db..38d949405618 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c | |||
@@ -192,8 +192,6 @@ int rio_add_device(struct rio_dev *rdev) | |||
192 | } | 192 | } |
193 | spin_unlock(&rio_global_list_lock); | 193 | spin_unlock(&rio_global_list_lock); |
194 | 194 | ||
195 | rio_create_sysfs_dev_files(rdev); | ||
196 | |||
197 | return 0; | 195 | return 0; |
198 | } | 196 | } |
199 | EXPORT_SYMBOL_GPL(rio_add_device); | 197 | EXPORT_SYMBOL_GPL(rio_add_device); |
@@ -220,7 +218,6 @@ void rio_del_device(struct rio_dev *rdev, enum rio_device_state state) | |||
220 | } | 218 | } |
221 | } | 219 | } |
222 | spin_unlock(&rio_global_list_lock); | 220 | spin_unlock(&rio_global_list_lock); |
223 | rio_remove_sysfs_dev_files(rdev); | ||
224 | device_unregister(&rdev->dev); | 221 | device_unregister(&rdev->dev); |
225 | } | 222 | } |
226 | EXPORT_SYMBOL_GPL(rio_del_device); | 223 | EXPORT_SYMBOL_GPL(rio_del_device); |
diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h index 9796b3fee70d..b2abf8576397 100644 --- a/drivers/rapidio/rio.h +++ b/drivers/rapidio/rio.h | |||
@@ -27,8 +27,6 @@ extern u32 rio_mport_get_efb(struct rio_mport *port, int local, u16 destid, | |||
27 | u8 hopcount, u32 from); | 27 | u8 hopcount, u32 from); |
28 | extern int rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, | 28 | extern int rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, |
29 | u8 hopcount); | 29 | u8 hopcount); |
30 | extern int rio_create_sysfs_dev_files(struct rio_dev *rdev); | ||
31 | extern void rio_remove_sysfs_dev_files(struct rio_dev *rdev); | ||
32 | extern int rio_lock_device(struct rio_mport *port, u16 destid, | 30 | extern int rio_lock_device(struct rio_mport *port, u16 destid, |
33 | u8 hopcount, int wait_ms); | 31 | u8 hopcount, int wait_ms); |
34 | extern int rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount); | 32 | extern int rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount); |
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 74fd9746aeca..5fb439897fe1 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c | |||
@@ -195,6 +195,8 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, | |||
195 | goto exit_ida; | 195 | goto exit_ida; |
196 | } | 196 | } |
197 | 197 | ||
198 | device_initialize(&rtc->dev); | ||
199 | |||
198 | rtc->id = id; | 200 | rtc->id = id; |
199 | rtc->ops = ops; | 201 | rtc->ops = ops; |
200 | rtc->owner = owner; | 202 | rtc->owner = owner; |
@@ -233,14 +235,19 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, | |||
233 | 235 | ||
234 | rtc_dev_prepare(rtc); | 236 | rtc_dev_prepare(rtc); |
235 | 237 | ||
236 | err = device_register(&rtc->dev); | 238 | err = cdev_device_add(&rtc->char_dev, &rtc->dev); |
237 | if (err) { | 239 | if (err) { |
240 | dev_warn(&rtc->dev, "%s: failed to add char device %d:%d\n", | ||
241 | rtc->name, MAJOR(rtc->dev.devt), rtc->id); | ||
242 | |||
238 | /* This will free both memory and the ID */ | 243 | /* This will free both memory and the ID */ |
239 | put_device(&rtc->dev); | 244 | put_device(&rtc->dev); |
240 | goto exit; | 245 | goto exit; |
246 | } else { | ||
247 | dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", rtc->name, | ||
248 | MAJOR(rtc->dev.devt), rtc->id); | ||
241 | } | 249 | } |
242 | 250 | ||
243 | rtc_dev_add_device(rtc); | ||
244 | rtc_proc_add_device(rtc); | 251 | rtc_proc_add_device(rtc); |
245 | 252 | ||
246 | dev_info(dev, "rtc core: registered %s as %s\n", | 253 | dev_info(dev, "rtc core: registered %s as %s\n", |
@@ -271,9 +278,8 @@ void rtc_device_unregister(struct rtc_device *rtc) | |||
271 | * Remove innards of this RTC, then disable it, before | 278 | * Remove innards of this RTC, then disable it, before |
272 | * letting any rtc_class_open() users access it again | 279 | * letting any rtc_class_open() users access it again |
273 | */ | 280 | */ |
274 | rtc_dev_del_device(rtc); | ||
275 | rtc_proc_del_device(rtc); | 281 | rtc_proc_del_device(rtc); |
276 | device_del(&rtc->dev); | 282 | cdev_device_del(&rtc->char_dev, &rtc->dev); |
277 | rtc->ops = NULL; | 283 | rtc->ops = NULL; |
278 | mutex_unlock(&rtc->ops_lock); | 284 | mutex_unlock(&rtc->ops_lock); |
279 | put_device(&rtc->dev); | 285 | put_device(&rtc->dev); |
diff --git a/drivers/rtc/rtc-core.h b/drivers/rtc/rtc-core.h index a098aea197fc..7a4ed2f7c7d7 100644 --- a/drivers/rtc/rtc-core.h +++ b/drivers/rtc/rtc-core.h | |||
@@ -3,8 +3,6 @@ | |||
3 | extern void __init rtc_dev_init(void); | 3 | extern void __init rtc_dev_init(void); |
4 | extern void __exit rtc_dev_exit(void); | 4 | extern void __exit rtc_dev_exit(void); |
5 | extern void rtc_dev_prepare(struct rtc_device *rtc); | 5 | extern void rtc_dev_prepare(struct rtc_device *rtc); |
6 | extern void rtc_dev_add_device(struct rtc_device *rtc); | ||
7 | extern void rtc_dev_del_device(struct rtc_device *rtc); | ||
8 | 6 | ||
9 | #else | 7 | #else |
10 | 8 | ||
@@ -20,14 +18,6 @@ static inline void rtc_dev_prepare(struct rtc_device *rtc) | |||
20 | { | 18 | { |
21 | } | 19 | } |
22 | 20 | ||
23 | static inline void rtc_dev_add_device(struct rtc_device *rtc) | ||
24 | { | ||
25 | } | ||
26 | |||
27 | static inline void rtc_dev_del_device(struct rtc_device *rtc) | ||
28 | { | ||
29 | } | ||
30 | |||
31 | #endif | 21 | #endif |
32 | 22 | ||
33 | #ifdef CONFIG_RTC_INTF_PROC | 23 | #ifdef CONFIG_RTC_INTF_PROC |
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 6dc8f29697ab..e81a8711fea7 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c | |||
@@ -477,23 +477,6 @@ void rtc_dev_prepare(struct rtc_device *rtc) | |||
477 | 477 | ||
478 | cdev_init(&rtc->char_dev, &rtc_dev_fops); | 478 | cdev_init(&rtc->char_dev, &rtc_dev_fops); |
479 | rtc->char_dev.owner = rtc->owner; | 479 | rtc->char_dev.owner = rtc->owner; |
480 | rtc->char_dev.kobj.parent = &rtc->dev.kobj; | ||
481 | } | ||
482 | |||
483 | void rtc_dev_add_device(struct rtc_device *rtc) | ||
484 | { | ||
485 | if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1)) | ||
486 | dev_warn(&rtc->dev, "%s: failed to add char device %d:%d\n", | ||
487 | rtc->name, MAJOR(rtc_devt), rtc->id); | ||
488 | else | ||
489 | dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", rtc->name, | ||
490 | MAJOR(rtc_devt), rtc->id); | ||
491 | } | ||
492 | |||
493 | void rtc_dev_del_device(struct rtc_device *rtc) | ||
494 | { | ||
495 | if (rtc->dev.devt) | ||
496 | cdev_del(&rtc->char_dev); | ||
497 | } | 480 | } |
498 | 481 | ||
499 | void __init rtc_dev_init(void) | 482 | void __init rtc_dev_init(void) |
diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c index ed948025112c..0e56f1eb05dc 100644 --- a/drivers/scsi/osd/osd_uld.c +++ b/drivers/scsi/osd/osd_uld.c | |||
@@ -400,9 +400,6 @@ static void __remove(struct device *dev) | |||
400 | 400 | ||
401 | kfree(oud->odi.osdname); | 401 | kfree(oud->odi.osdname); |
402 | 402 | ||
403 | if (oud->cdev.owner) | ||
404 | cdev_del(&oud->cdev); | ||
405 | |||
406 | osd_dev_fini(&oud->od); | 403 | osd_dev_fini(&oud->od); |
407 | scsi_device_put(scsi_device); | 404 | scsi_device_put(scsi_device); |
408 | 405 | ||
@@ -411,7 +408,6 @@ static void __remove(struct device *dev) | |||
411 | 408 | ||
412 | if (oud->disk) | 409 | if (oud->disk) |
413 | put_disk(oud->disk); | 410 | put_disk(oud->disk); |
414 | ida_remove(&osd_minor_ida, oud->minor); | ||
415 | 411 | ||
416 | kfree(oud); | 412 | kfree(oud); |
417 | } | 413 | } |
@@ -446,8 +442,21 @@ static int osd_probe(struct device *dev) | |||
446 | if (NULL == oud) | 442 | if (NULL == oud) |
447 | goto err_retract_minor; | 443 | goto err_retract_minor; |
448 | 444 | ||
445 | /* class device member */ | ||
446 | device_initialize(&oud->class_dev); | ||
449 | dev_set_drvdata(dev, oud); | 447 | dev_set_drvdata(dev, oud); |
450 | oud->minor = minor; | 448 | oud->minor = minor; |
449 | oud->class_dev.devt = MKDEV(SCSI_OSD_MAJOR, oud->minor); | ||
450 | oud->class_dev.class = &osd_uld_class; | ||
451 | oud->class_dev.parent = dev; | ||
452 | oud->class_dev.release = __remove; | ||
453 | |||
454 | /* hold one more reference to the scsi_device that will get released | ||
455 | * in __release, in case a logout is happening while fs is mounted | ||
456 | */ | ||
457 | if (scsi_device_get(scsi_device)) | ||
458 | goto err_retract_minor; | ||
459 | osd_dev_init(&oud->od, scsi_device); | ||
451 | 460 | ||
452 | /* allocate a disk and set it up */ | 461 | /* allocate a disk and set it up */ |
453 | /* FIXME: do we need this since sg has already done that */ | 462 | /* FIXME: do we need this since sg has already done that */ |
@@ -461,61 +470,34 @@ static int osd_probe(struct device *dev) | |||
461 | sprintf(disk->disk_name, "osd%d", oud->minor); | 470 | sprintf(disk->disk_name, "osd%d", oud->minor); |
462 | oud->disk = disk; | 471 | oud->disk = disk; |
463 | 472 | ||
464 | /* hold one more reference to the scsi_device that will get released | ||
465 | * in __release, in case a logout is happening while fs is mounted | ||
466 | */ | ||
467 | if (scsi_device_get(scsi_device)) | ||
468 | goto err_put_disk; | ||
469 | osd_dev_init(&oud->od, scsi_device); | ||
470 | |||
471 | /* Detect the OSD Version */ | 473 | /* Detect the OSD Version */ |
472 | error = __detect_osd(oud); | 474 | error = __detect_osd(oud); |
473 | if (error) { | 475 | if (error) { |
474 | OSD_ERR("osd detection failed, non-compatible OSD device\n"); | 476 | OSD_ERR("osd detection failed, non-compatible OSD device\n"); |
475 | goto err_put_sdev; | 477 | goto err_free_osd; |
476 | } | 478 | } |
477 | 479 | ||
478 | /* init the char-device for communication with user-mode */ | 480 | /* init the char-device for communication with user-mode */ |
479 | cdev_init(&oud->cdev, &osd_fops); | 481 | cdev_init(&oud->cdev, &osd_fops); |
480 | oud->cdev.owner = THIS_MODULE; | 482 | oud->cdev.owner = THIS_MODULE; |
481 | error = cdev_add(&oud->cdev, | ||
482 | MKDEV(SCSI_OSD_MAJOR, oud->minor), 1); | ||
483 | if (error) { | ||
484 | OSD_ERR("cdev_add failed\n"); | ||
485 | goto err_put_disk; | ||
486 | } | ||
487 | 483 | ||
488 | /* class device member */ | ||
489 | oud->class_dev.devt = oud->cdev.dev; | ||
490 | oud->class_dev.class = &osd_uld_class; | ||
491 | oud->class_dev.parent = dev; | ||
492 | oud->class_dev.release = __remove; | ||
493 | error = dev_set_name(&oud->class_dev, "%s", disk->disk_name); | 484 | error = dev_set_name(&oud->class_dev, "%s", disk->disk_name); |
494 | if (error) { | 485 | if (error) { |
495 | OSD_ERR("dev_set_name failed => %d\n", error); | 486 | OSD_ERR("dev_set_name failed => %d\n", error); |
496 | goto err_put_cdev; | 487 | goto err_free_osd; |
497 | } | 488 | } |
498 | 489 | ||
499 | error = device_register(&oud->class_dev); | 490 | error = cdev_device_add(&oud->cdev, &oud->class_dev); |
500 | if (error) { | 491 | if (error) { |
501 | OSD_ERR("device_register failed => %d\n", error); | 492 | OSD_ERR("device_register failed => %d\n", error); |
502 | goto err_put_cdev; | 493 | goto err_free_osd; |
503 | } | 494 | } |
504 | 495 | ||
505 | get_device(&oud->class_dev); | ||
506 | |||
507 | OSD_INFO("osd_probe %s\n", disk->disk_name); | 496 | OSD_INFO("osd_probe %s\n", disk->disk_name); |
508 | return 0; | 497 | return 0; |
509 | 498 | ||
510 | err_put_cdev: | ||
511 | cdev_del(&oud->cdev); | ||
512 | err_put_sdev: | ||
513 | scsi_device_put(scsi_device); | ||
514 | err_put_disk: | ||
515 | put_disk(disk); | ||
516 | err_free_osd: | 499 | err_free_osd: |
517 | dev_set_drvdata(dev, NULL); | 500 | put_device(&oud->class_dev); |
518 | kfree(oud); | ||
519 | err_retract_minor: | 501 | err_retract_minor: |
520 | ida_remove(&osd_minor_ida, minor); | 502 | ida_remove(&osd_minor_ida, minor); |
521 | return error; | 503 | return error; |
@@ -531,9 +513,10 @@ static int osd_remove(struct device *dev) | |||
531 | dev, oud->od.scsi_device, scsi_device); | 513 | dev, oud->od.scsi_device, scsi_device); |
532 | } | 514 | } |
533 | 515 | ||
534 | device_unregister(&oud->class_dev); | 516 | cdev_device_del(&oud->cdev, &oud->class_dev); |
535 | 517 | ida_remove(&osd_minor_ida, oud->minor); | |
536 | put_device(&oud->class_dev); | 518 | put_device(&oud->class_dev); |
519 | |||
537 | return 0; | 520 | return 0; |
538 | } | 521 | } |
539 | 522 | ||
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 60ce7fd54e89..1c196f87e9d9 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c | |||
@@ -66,7 +66,7 @@ static ssize_t map_size_show(struct uio_mem *mem, char *buf) | |||
66 | 66 | ||
67 | static ssize_t map_offset_show(struct uio_mem *mem, char *buf) | 67 | static ssize_t map_offset_show(struct uio_mem *mem, char *buf) |
68 | { | 68 | { |
69 | return sprintf(buf, "0x%llx\n", (unsigned long long)mem->addr & ~PAGE_MASK); | 69 | return sprintf(buf, "0x%llx\n", (unsigned long long)mem->offs); |
70 | } | 70 | } |
71 | 71 | ||
72 | struct map_sysfs_entry { | 72 | struct map_sysfs_entry { |
diff --git a/drivers/uio/uio_mf624.c b/drivers/uio/uio_mf624.c index d1f95a1567bb..35187c052e8c 100644 --- a/drivers/uio/uio_mf624.c +++ b/drivers/uio/uio_mf624.c | |||
@@ -127,6 +127,24 @@ static int mf624_irqcontrol(struct uio_info *info, s32 irq_on) | |||
127 | return 0; | 127 | return 0; |
128 | } | 128 | } |
129 | 129 | ||
130 | static int mf624_setup_mem(struct pci_dev *dev, int bar, struct uio_mem *mem, const char *name) | ||
131 | { | ||
132 | resource_size_t start = pci_resource_start(dev, bar); | ||
133 | resource_size_t len = pci_resource_len(dev, bar); | ||
134 | |||
135 | mem->name = name; | ||
136 | mem->addr = start & PAGE_MASK; | ||
137 | mem->offs = start & ~PAGE_MASK; | ||
138 | if (!mem->addr) | ||
139 | return -ENODEV; | ||
140 | mem->size = ((start & ~PAGE_MASK) + len + PAGE_SIZE - 1) & PAGE_MASK; | ||
141 | mem->memtype = UIO_MEM_PHYS; | ||
142 | mem->internal_addr = pci_ioremap_bar(dev, bar); | ||
143 | if (!mem->internal_addr) | ||
144 | return -ENODEV; | ||
145 | return 0; | ||
146 | } | ||
147 | |||
130 | static int mf624_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | 148 | static int mf624_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) |
131 | { | 149 | { |
132 | struct uio_info *info; | 150 | struct uio_info *info; |
@@ -147,37 +165,15 @@ static int mf624_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
147 | /* Note: Datasheet says device uses BAR0, BAR1, BAR2 -- do not trust it */ | 165 | /* Note: Datasheet says device uses BAR0, BAR1, BAR2 -- do not trust it */ |
148 | 166 | ||
149 | /* BAR0 */ | 167 | /* BAR0 */ |
150 | info->mem[0].name = "PCI chipset, interrupts, status " | 168 | if (mf624_setup_mem(dev, 0, &info->mem[0], "PCI chipset, interrupts, status " |
151 | "bits, special functions"; | 169 | "bits, special functions")) |
152 | info->mem[0].addr = pci_resource_start(dev, 0); | ||
153 | if (!info->mem[0].addr) | ||
154 | goto out_release; | 170 | goto out_release; |
155 | info->mem[0].size = pci_resource_len(dev, 0); | ||
156 | info->mem[0].memtype = UIO_MEM_PHYS; | ||
157 | info->mem[0].internal_addr = pci_ioremap_bar(dev, 0); | ||
158 | if (!info->mem[0].internal_addr) | ||
159 | goto out_release; | ||
160 | |||
161 | /* BAR2 */ | 171 | /* BAR2 */ |
162 | info->mem[1].name = "ADC, DAC, DIO"; | 172 | if (mf624_setup_mem(dev, 2, &info->mem[1], "ADC, DAC, DIO")) |
163 | info->mem[1].addr = pci_resource_start(dev, 2); | ||
164 | if (!info->mem[1].addr) | ||
165 | goto out_unmap0; | ||
166 | info->mem[1].size = pci_resource_len(dev, 2); | ||
167 | info->mem[1].memtype = UIO_MEM_PHYS; | ||
168 | info->mem[1].internal_addr = pci_ioremap_bar(dev, 2); | ||
169 | if (!info->mem[1].internal_addr) | ||
170 | goto out_unmap0; | 173 | goto out_unmap0; |
171 | 174 | ||
172 | /* BAR4 */ | 175 | /* BAR4 */ |
173 | info->mem[2].name = "Counter/timer chip"; | 176 | if (mf624_setup_mem(dev, 4, &info->mem[2], "Counter/timer chip")) |
174 | info->mem[2].addr = pci_resource_start(dev, 4); | ||
175 | if (!info->mem[2].addr) | ||
176 | goto out_unmap1; | ||
177 | info->mem[2].size = pci_resource_len(dev, 4); | ||
178 | info->mem[2].memtype = UIO_MEM_PHYS; | ||
179 | info->mem[2].internal_addr = pci_ioremap_bar(dev, 4); | ||
180 | if (!info->mem[2].internal_addr) | ||
181 | goto out_unmap1; | 177 | goto out_unmap1; |
182 | 178 | ||
183 | info->irq = dev->irq; | 179 | info->irq = dev->irq; |
diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c index 0035cf79760a..6a3ead42aba8 100644 --- a/drivers/vme/vme.c +++ b/drivers/vme/vme.c | |||
@@ -76,9 +76,16 @@ static struct vme_bridge *find_bridge(struct vme_resource *resource) | |||
76 | } | 76 | } |
77 | } | 77 | } |
78 | 78 | ||
79 | /* | 79 | /** |
80 | * vme_free_consistent - Allocate contiguous memory. | ||
81 | * @resource: Pointer to VME resource. | ||
82 | * @size: Size of allocation required. | ||
83 | * @dma: Pointer to variable to store physical address of allocation. | ||
84 | * | ||
80 | * Allocate a contiguous block of memory for use by the driver. This is used to | 85 | * Allocate a contiguous block of memory for use by the driver. This is used to |
81 | * create the buffers for the slave windows. | 86 | * create the buffers for the slave windows. |
87 | * | ||
88 | * Return: Virtual address of allocation on success, NULL on failure. | ||
82 | */ | 89 | */ |
83 | void *vme_alloc_consistent(struct vme_resource *resource, size_t size, | 90 | void *vme_alloc_consistent(struct vme_resource *resource, size_t size, |
84 | dma_addr_t *dma) | 91 | dma_addr_t *dma) |
@@ -111,8 +118,14 @@ void *vme_alloc_consistent(struct vme_resource *resource, size_t size, | |||
111 | } | 118 | } |
112 | EXPORT_SYMBOL(vme_alloc_consistent); | 119 | EXPORT_SYMBOL(vme_alloc_consistent); |
113 | 120 | ||
114 | /* | 121 | /** |
115 | * Free previously allocated contiguous block of memory. | 122 | * vme_free_consistent - Free previously allocated memory. |
123 | * @resource: Pointer to VME resource. | ||
124 | * @size: Size of allocation to free. | ||
125 | * @vaddr: Virtual address of allocation. | ||
126 | * @dma: Physical address of allocation. | ||
127 | * | ||
128 | * Free previously allocated block of contiguous memory. | ||
116 | */ | 129 | */ |
117 | void vme_free_consistent(struct vme_resource *resource, size_t size, | 130 | void vme_free_consistent(struct vme_resource *resource, size_t size, |
118 | void *vaddr, dma_addr_t dma) | 131 | void *vaddr, dma_addr_t dma) |
@@ -145,6 +158,16 @@ void vme_free_consistent(struct vme_resource *resource, size_t size, | |||
145 | } | 158 | } |
146 | EXPORT_SYMBOL(vme_free_consistent); | 159 | EXPORT_SYMBOL(vme_free_consistent); |
147 | 160 | ||
161 | /** | ||
162 | * vme_get_size - Helper function returning size of a VME window | ||
163 | * @resource: Pointer to VME slave or master resource. | ||
164 | * | ||
165 | * Determine the size of the VME window provided. This is a helper | ||
166 | * function, wrappering the call to vme_master_get or vme_slave_get | ||
167 | * depending on the type of window resource handed to it. | ||
168 | * | ||
169 | * Return: Size of the window on success, zero on failure. | ||
170 | */ | ||
148 | size_t vme_get_size(struct vme_resource *resource) | 171 | size_t vme_get_size(struct vme_resource *resource) |
149 | { | 172 | { |
150 | int enabled, retval; | 173 | int enabled, retval; |
@@ -259,9 +282,16 @@ static u32 vme_get_aspace(int am) | |||
259 | return 0; | 282 | return 0; |
260 | } | 283 | } |
261 | 284 | ||
262 | /* | 285 | /** |
263 | * Request a slave image with specific attributes, return some unique | 286 | * vme_slave_request - Request a VME slave window resource. |
264 | * identifier. | 287 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. |
288 | * @address: Required VME address space. | ||
289 | * @cycle: Required VME data transfer cycle type. | ||
290 | * | ||
291 | * Request use of a VME window resource capable of being set for the requested | ||
292 | * address space and data transfer cycle. | ||
293 | * | ||
294 | * Return: Pointer to VME resource on success, NULL on failure. | ||
265 | */ | 295 | */ |
266 | struct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address, | 296 | struct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address, |
267 | u32 cycle) | 297 | u32 cycle) |
@@ -327,6 +357,23 @@ err_bus: | |||
327 | } | 357 | } |
328 | EXPORT_SYMBOL(vme_slave_request); | 358 | EXPORT_SYMBOL(vme_slave_request); |
329 | 359 | ||
360 | /** | ||
361 | * vme_slave_set - Set VME slave window configuration. | ||
362 | * @resource: Pointer to VME slave resource. | ||
363 | * @enabled: State to which the window should be configured. | ||
364 | * @vme_base: Base address for the window. | ||
365 | * @size: Size of the VME window. | ||
366 | * @buf_base: Based address of buffer used to provide VME slave window storage. | ||
367 | * @aspace: VME address space for the VME window. | ||
368 | * @cycle: VME data transfer cycle type for the VME window. | ||
369 | * | ||
370 | * Set configuration for provided VME slave window. | ||
371 | * | ||
372 | * Return: Zero on success, -EINVAL if operation is not supported on this | ||
373 | * device, if an invalid resource has been provided or invalid | ||
374 | * attributes are provided. Hardware specific errors may also be | ||
375 | * returned. | ||
376 | */ | ||
330 | int vme_slave_set(struct vme_resource *resource, int enabled, | 377 | int vme_slave_set(struct vme_resource *resource, int enabled, |
331 | unsigned long long vme_base, unsigned long long size, | 378 | unsigned long long vme_base, unsigned long long size, |
332 | dma_addr_t buf_base, u32 aspace, u32 cycle) | 379 | dma_addr_t buf_base, u32 aspace, u32 cycle) |
@@ -362,6 +409,21 @@ int vme_slave_set(struct vme_resource *resource, int enabled, | |||
362 | } | 409 | } |
363 | EXPORT_SYMBOL(vme_slave_set); | 410 | EXPORT_SYMBOL(vme_slave_set); |
364 | 411 | ||
412 | /** | ||
413 | * vme_slave_get - Retrieve VME slave window configuration. | ||
414 | * @resource: Pointer to VME slave resource. | ||
415 | * @enabled: Pointer to variable for storing state. | ||
416 | * @vme_base: Pointer to variable for storing window base address. | ||
417 | * @size: Pointer to variable for storing window size. | ||
418 | * @buf_base: Pointer to variable for storing slave buffer base address. | ||
419 | * @aspace: Pointer to variable for storing VME address space. | ||
420 | * @cycle: Pointer to variable for storing VME data transfer cycle type. | ||
421 | * | ||
422 | * Return configuration for provided VME slave window. | ||
423 | * | ||
424 | * Return: Zero on success, -EINVAL if operation is not supported on this | ||
425 | * device or if an invalid resource has been provided. | ||
426 | */ | ||
365 | int vme_slave_get(struct vme_resource *resource, int *enabled, | 427 | int vme_slave_get(struct vme_resource *resource, int *enabled, |
366 | unsigned long long *vme_base, unsigned long long *size, | 428 | unsigned long long *vme_base, unsigned long long *size, |
367 | dma_addr_t *buf_base, u32 *aspace, u32 *cycle) | 429 | dma_addr_t *buf_base, u32 *aspace, u32 *cycle) |
@@ -386,6 +448,12 @@ int vme_slave_get(struct vme_resource *resource, int *enabled, | |||
386 | } | 448 | } |
387 | EXPORT_SYMBOL(vme_slave_get); | 449 | EXPORT_SYMBOL(vme_slave_get); |
388 | 450 | ||
451 | /** | ||
452 | * vme_slave_free - Free VME slave window | ||
453 | * @resource: Pointer to VME slave resource. | ||
454 | * | ||
455 | * Free the provided slave resource so that it may be reallocated. | ||
456 | */ | ||
389 | void vme_slave_free(struct vme_resource *resource) | 457 | void vme_slave_free(struct vme_resource *resource) |
390 | { | 458 | { |
391 | struct vme_slave_resource *slave_image; | 459 | struct vme_slave_resource *slave_image; |
@@ -415,9 +483,17 @@ void vme_slave_free(struct vme_resource *resource) | |||
415 | } | 483 | } |
416 | EXPORT_SYMBOL(vme_slave_free); | 484 | EXPORT_SYMBOL(vme_slave_free); |
417 | 485 | ||
418 | /* | 486 | /** |
419 | * Request a master image with specific attributes, return some unique | 487 | * vme_master_request - Request a VME master window resource. |
420 | * identifier. | 488 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. |
489 | * @address: Required VME address space. | ||
490 | * @cycle: Required VME data transfer cycle type. | ||
491 | * @dwidth: Required VME data transfer width. | ||
492 | * | ||
493 | * Request use of a VME window resource capable of being set for the requested | ||
494 | * address space, data transfer cycle and width. | ||
495 | * | ||
496 | * Return: Pointer to VME resource on success, NULL on failure. | ||
421 | */ | 497 | */ |
422 | struct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address, | 498 | struct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address, |
423 | u32 cycle, u32 dwidth) | 499 | u32 cycle, u32 dwidth) |
@@ -486,6 +562,23 @@ err_bus: | |||
486 | } | 562 | } |
487 | EXPORT_SYMBOL(vme_master_request); | 563 | EXPORT_SYMBOL(vme_master_request); |
488 | 564 | ||
565 | /** | ||
566 | * vme_master_set - Set VME master window configuration. | ||
567 | * @resource: Pointer to VME master resource. | ||
568 | * @enabled: State to which the window should be configured. | ||
569 | * @vme_base: Base address for the window. | ||
570 | * @size: Size of the VME window. | ||
571 | * @aspace: VME address space for the VME window. | ||
572 | * @cycle: VME data transfer cycle type for the VME window. | ||
573 | * @dwidth: VME data transfer width for the VME window. | ||
574 | * | ||
575 | * Set configuration for provided VME master window. | ||
576 | * | ||
577 | * Return: Zero on success, -EINVAL if operation is not supported on this | ||
578 | * device, if an invalid resource has been provided or invalid | ||
579 | * attributes are provided. Hardware specific errors may also be | ||
580 | * returned. | ||
581 | */ | ||
489 | int vme_master_set(struct vme_resource *resource, int enabled, | 582 | int vme_master_set(struct vme_resource *resource, int enabled, |
490 | unsigned long long vme_base, unsigned long long size, u32 aspace, | 583 | unsigned long long vme_base, unsigned long long size, u32 aspace, |
491 | u32 cycle, u32 dwidth) | 584 | u32 cycle, u32 dwidth) |
@@ -522,6 +615,21 @@ int vme_master_set(struct vme_resource *resource, int enabled, | |||
522 | } | 615 | } |
523 | EXPORT_SYMBOL(vme_master_set); | 616 | EXPORT_SYMBOL(vme_master_set); |
524 | 617 | ||
618 | /** | ||
619 | * vme_master_get - Retrieve VME master window configuration. | ||
620 | * @resource: Pointer to VME master resource. | ||
621 | * @enabled: Pointer to variable for storing state. | ||
622 | * @vme_base: Pointer to variable for storing window base address. | ||
623 | * @size: Pointer to variable for storing window size. | ||
624 | * @aspace: Pointer to variable for storing VME address space. | ||
625 | * @cycle: Pointer to variable for storing VME data transfer cycle type. | ||
626 | * @dwidth: Pointer to variable for storing VME data transfer width. | ||
627 | * | ||
628 | * Return configuration for provided VME master window. | ||
629 | * | ||
630 | * Return: Zero on success, -EINVAL if operation is not supported on this | ||
631 | * device or if an invalid resource has been provided. | ||
632 | */ | ||
525 | int vme_master_get(struct vme_resource *resource, int *enabled, | 633 | int vme_master_get(struct vme_resource *resource, int *enabled, |
526 | unsigned long long *vme_base, unsigned long long *size, u32 *aspace, | 634 | unsigned long long *vme_base, unsigned long long *size, u32 *aspace, |
527 | u32 *cycle, u32 *dwidth) | 635 | u32 *cycle, u32 *dwidth) |
@@ -546,8 +654,20 @@ int vme_master_get(struct vme_resource *resource, int *enabled, | |||
546 | } | 654 | } |
547 | EXPORT_SYMBOL(vme_master_get); | 655 | EXPORT_SYMBOL(vme_master_get); |
548 | 656 | ||
549 | /* | 657 | /** |
550 | * Read data out of VME space into a buffer. | 658 | * vme_master_write - Read data from VME space into a buffer. |
659 | * @resource: Pointer to VME master resource. | ||
660 | * @buf: Pointer to buffer where data should be transferred. | ||
661 | * @count: Number of bytes to transfer. | ||
662 | * @offset: Offset into VME master window at which to start transfer. | ||
663 | * | ||
664 | * Perform read of count bytes of data from location on VME bus which maps into | ||
665 | * the VME master window at offset to buf. | ||
666 | * | ||
667 | * Return: Number of bytes read, -EINVAL if resource is not a VME master | ||
668 | * resource or read operation is not supported. -EFAULT returned if | ||
669 | * invalid offset is provided. Hardware specific errors may also be | ||
670 | * returned. | ||
551 | */ | 671 | */ |
552 | ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count, | 672 | ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count, |
553 | loff_t offset) | 673 | loff_t offset) |
@@ -583,8 +703,20 @@ ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count, | |||
583 | } | 703 | } |
584 | EXPORT_SYMBOL(vme_master_read); | 704 | EXPORT_SYMBOL(vme_master_read); |
585 | 705 | ||
586 | /* | 706 | /** |
587 | * Write data out to VME space from a buffer. | 707 | * vme_master_write - Write data out to VME space from a buffer. |
708 | * @resource: Pointer to VME master resource. | ||
709 | * @buf: Pointer to buffer holding data to transfer. | ||
710 | * @count: Number of bytes to transfer. | ||
711 | * @offset: Offset into VME master window at which to start transfer. | ||
712 | * | ||
713 | * Perform write of count bytes of data from buf to location on VME bus which | ||
714 | * maps into the VME master window at offset. | ||
715 | * | ||
716 | * Return: Number of bytes written, -EINVAL if resource is not a VME master | ||
717 | * resource or write operation is not supported. -EFAULT returned if | ||
718 | * invalid offset is provided. Hardware specific errors may also be | ||
719 | * returned. | ||
588 | */ | 720 | */ |
589 | ssize_t vme_master_write(struct vme_resource *resource, void *buf, | 721 | ssize_t vme_master_write(struct vme_resource *resource, void *buf, |
590 | size_t count, loff_t offset) | 722 | size_t count, loff_t offset) |
@@ -619,8 +751,24 @@ ssize_t vme_master_write(struct vme_resource *resource, void *buf, | |||
619 | } | 751 | } |
620 | EXPORT_SYMBOL(vme_master_write); | 752 | EXPORT_SYMBOL(vme_master_write); |
621 | 753 | ||
622 | /* | 754 | /** |
623 | * Perform RMW cycle to provided location. | 755 | * vme_master_rmw - Perform read-modify-write cycle. |
756 | * @resource: Pointer to VME master resource. | ||
757 | * @mask: Bits to be compared and swapped in operation. | ||
758 | * @compare: Bits to be compared with data read from offset. | ||
759 | * @swap: Bits to be swapped in data read from offset. | ||
760 | * @offset: Offset into VME master window at which to perform operation. | ||
761 | * | ||
762 | * Perform read-modify-write cycle on provided location: | ||
763 | * - Location on VME bus is read. | ||
764 | * - Bits selected by mask are compared with compare. | ||
765 | * - Where a selected bit matches that in compare and are selected in swap, | ||
766 | * the bit is swapped. | ||
767 | * - Result written back to location on VME bus. | ||
768 | * | ||
769 | * Return: Bytes written on success, -EINVAL if resource is not a VME master | ||
770 | * resource or RMW operation is not supported. Hardware specific | ||
771 | * errors may also be returned. | ||
624 | */ | 772 | */ |
625 | unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask, | 773 | unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask, |
626 | unsigned int compare, unsigned int swap, loff_t offset) | 774 | unsigned int compare, unsigned int swap, loff_t offset) |
@@ -644,6 +792,17 @@ unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask, | |||
644 | } | 792 | } |
645 | EXPORT_SYMBOL(vme_master_rmw); | 793 | EXPORT_SYMBOL(vme_master_rmw); |
646 | 794 | ||
795 | /** | ||
796 | * vme_master_mmap - Mmap region of VME master window. | ||
797 | * @resource: Pointer to VME master resource. | ||
798 | * @vma: Pointer to definition of user mapping. | ||
799 | * | ||
800 | * Memory map a region of the VME master window into user space. | ||
801 | * | ||
802 | * Return: Zero on success, -EINVAL if resource is not a VME master | ||
803 | * resource or -EFAULT if map exceeds window size. Other generic mmap | ||
804 | * errors may also be returned. | ||
805 | */ | ||
647 | int vme_master_mmap(struct vme_resource *resource, struct vm_area_struct *vma) | 806 | int vme_master_mmap(struct vme_resource *resource, struct vm_area_struct *vma) |
648 | { | 807 | { |
649 | struct vme_master_resource *image; | 808 | struct vme_master_resource *image; |
@@ -670,6 +829,12 @@ int vme_master_mmap(struct vme_resource *resource, struct vm_area_struct *vma) | |||
670 | } | 829 | } |
671 | EXPORT_SYMBOL(vme_master_mmap); | 830 | EXPORT_SYMBOL(vme_master_mmap); |
672 | 831 | ||
832 | /** | ||
833 | * vme_master_free - Free VME master window | ||
834 | * @resource: Pointer to VME master resource. | ||
835 | * | ||
836 | * Free the provided master resource so that it may be reallocated. | ||
837 | */ | ||
673 | void vme_master_free(struct vme_resource *resource) | 838 | void vme_master_free(struct vme_resource *resource) |
674 | { | 839 | { |
675 | struct vme_master_resource *master_image; | 840 | struct vme_master_resource *master_image; |
@@ -699,9 +864,15 @@ void vme_master_free(struct vme_resource *resource) | |||
699 | } | 864 | } |
700 | EXPORT_SYMBOL(vme_master_free); | 865 | EXPORT_SYMBOL(vme_master_free); |
701 | 866 | ||
702 | /* | 867 | /** |
703 | * Request a DMA controller with specific attributes, return some unique | 868 | * vme_dma_request - Request a DMA controller. |
704 | * identifier. | 869 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. |
870 | * @route: Required src/destination combination. | ||
871 | * | ||
872 | * Request a VME DMA controller with capability to perform transfers bewteen | ||
873 | * requested source/destination combination. | ||
874 | * | ||
875 | * Return: Pointer to VME DMA resource on success, NULL on failure. | ||
705 | */ | 876 | */ |
706 | struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route) | 877 | struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route) |
707 | { | 878 | { |
@@ -768,8 +939,15 @@ err_bus: | |||
768 | } | 939 | } |
769 | EXPORT_SYMBOL(vme_dma_request); | 940 | EXPORT_SYMBOL(vme_dma_request); |
770 | 941 | ||
771 | /* | 942 | /** |
772 | * Start new list | 943 | * vme_new_dma_list - Create new VME DMA list. |
944 | * @resource: Pointer to VME DMA resource. | ||
945 | * | ||
946 | * Create a new VME DMA list. It is the responsibility of the user to free | ||
947 | * the list once it is no longer required with vme_dma_list_free(). | ||
948 | * | ||
949 | * Return: Pointer to new VME DMA list, NULL on allocation failure or invalid | ||
950 | * VME DMA resource. | ||
773 | */ | 951 | */ |
774 | struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource) | 952 | struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource) |
775 | { | 953 | { |
@@ -796,8 +974,16 @@ struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource) | |||
796 | } | 974 | } |
797 | EXPORT_SYMBOL(vme_new_dma_list); | 975 | EXPORT_SYMBOL(vme_new_dma_list); |
798 | 976 | ||
799 | /* | 977 | /** |
800 | * Create "Pattern" type attributes | 978 | * vme_dma_pattern_attribute - Create "Pattern" type VME DMA list attribute. |
979 | * @pattern: Value to use used as pattern | ||
980 | * @type: Type of pattern to be written. | ||
981 | * | ||
982 | * Create VME DMA list attribute for pattern generation. It is the | ||
983 | * responsibility of the user to free used attributes using | ||
984 | * vme_dma_free_attribute(). | ||
985 | * | ||
986 | * Return: Pointer to VME DMA attribute, NULL on failure. | ||
801 | */ | 987 | */ |
802 | struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type) | 988 | struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type) |
803 | { | 989 | { |
@@ -831,8 +1017,15 @@ err_attr: | |||
831 | } | 1017 | } |
832 | EXPORT_SYMBOL(vme_dma_pattern_attribute); | 1018 | EXPORT_SYMBOL(vme_dma_pattern_attribute); |
833 | 1019 | ||
834 | /* | 1020 | /** |
835 | * Create "PCI" type attributes | 1021 | * vme_dma_pci_attribute - Create "PCI" type VME DMA list attribute. |
1022 | * @address: PCI base address for DMA transfer. | ||
1023 | * | ||
1024 | * Create VME DMA list attribute pointing to a location on PCI for DMA | ||
1025 | * transfers. It is the responsibility of the user to free used attributes | ||
1026 | * using vme_dma_free_attribute(). | ||
1027 | * | ||
1028 | * Return: Pointer to VME DMA attribute, NULL on failure. | ||
836 | */ | 1029 | */ |
837 | struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address) | 1030 | struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address) |
838 | { | 1031 | { |
@@ -869,8 +1062,18 @@ err_attr: | |||
869 | } | 1062 | } |
870 | EXPORT_SYMBOL(vme_dma_pci_attribute); | 1063 | EXPORT_SYMBOL(vme_dma_pci_attribute); |
871 | 1064 | ||
872 | /* | 1065 | /** |
873 | * Create "VME" type attributes | 1066 | * vme_dma_vme_attribute - Create "VME" type VME DMA list attribute. |
1067 | * @address: VME base address for DMA transfer. | ||
1068 | * @aspace: VME address space to use for DMA transfer. | ||
1069 | * @cycle: VME bus cycle to use for DMA transfer. | ||
1070 | * @dwidth: VME data width to use for DMA transfer. | ||
1071 | * | ||
1072 | * Create VME DMA list attribute pointing to a location on the VME bus for DMA | ||
1073 | * transfers. It is the responsibility of the user to free used attributes | ||
1074 | * using vme_dma_free_attribute(). | ||
1075 | * | ||
1076 | * Return: Pointer to VME DMA attribute, NULL on failure. | ||
874 | */ | 1077 | */ |
875 | struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address, | 1078 | struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address, |
876 | u32 aspace, u32 cycle, u32 dwidth) | 1079 | u32 aspace, u32 cycle, u32 dwidth) |
@@ -908,8 +1111,12 @@ err_attr: | |||
908 | } | 1111 | } |
909 | EXPORT_SYMBOL(vme_dma_vme_attribute); | 1112 | EXPORT_SYMBOL(vme_dma_vme_attribute); |
910 | 1113 | ||
911 | /* | 1114 | /** |
912 | * Free attribute | 1115 | * vme_dma_free_attribute - Free DMA list attribute. |
1116 | * @attributes: Pointer to DMA list attribute. | ||
1117 | * | ||
1118 | * Free VME DMA list attribute. VME DMA list attributes can be safely freed | ||
1119 | * once vme_dma_list_add() has returned. | ||
913 | */ | 1120 | */ |
914 | void vme_dma_free_attribute(struct vme_dma_attr *attributes) | 1121 | void vme_dma_free_attribute(struct vme_dma_attr *attributes) |
915 | { | 1122 | { |
@@ -918,6 +1125,23 @@ void vme_dma_free_attribute(struct vme_dma_attr *attributes) | |||
918 | } | 1125 | } |
919 | EXPORT_SYMBOL(vme_dma_free_attribute); | 1126 | EXPORT_SYMBOL(vme_dma_free_attribute); |
920 | 1127 | ||
1128 | /** | ||
1129 | * vme_dma_list_add - Add enty to a VME DMA list. | ||
1130 | * @list: Pointer to VME list. | ||
1131 | * @src: Pointer to DMA list attribute to use as source. | ||
1132 | * @dest: Pointer to DMA list attribute to use as destination. | ||
1133 | * @count: Number of bytes to transfer. | ||
1134 | * | ||
1135 | * Add an entry to the provided VME DMA list. Entry requires pointers to source | ||
1136 | * and destination DMA attributes and a count. | ||
1137 | * | ||
1138 | * Please note, the attributes supported as source and destinations for | ||
1139 | * transfers are hardware dependent. | ||
1140 | * | ||
1141 | * Return: Zero on success, -EINVAL if operation is not supported on this | ||
1142 | * device or if the link list has already been submitted for execution. | ||
1143 | * Hardware specific errors also possible. | ||
1144 | */ | ||
921 | int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, | 1145 | int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, |
922 | struct vme_dma_attr *dest, size_t count) | 1146 | struct vme_dma_attr *dest, size_t count) |
923 | { | 1147 | { |
@@ -942,6 +1166,16 @@ int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, | |||
942 | } | 1166 | } |
943 | EXPORT_SYMBOL(vme_dma_list_add); | 1167 | EXPORT_SYMBOL(vme_dma_list_add); |
944 | 1168 | ||
1169 | /** | ||
1170 | * vme_dma_list_exec - Queue a VME DMA list for execution. | ||
1171 | * @list: Pointer to VME list. | ||
1172 | * | ||
1173 | * Queue the provided VME DMA list for execution. The call will return once the | ||
1174 | * list has been executed. | ||
1175 | * | ||
1176 | * Return: Zero on success, -EINVAL if operation is not supported on this | ||
1177 | * device. Hardware specific errors also possible. | ||
1178 | */ | ||
945 | int vme_dma_list_exec(struct vme_dma_list *list) | 1179 | int vme_dma_list_exec(struct vme_dma_list *list) |
946 | { | 1180 | { |
947 | struct vme_bridge *bridge = list->parent->parent; | 1181 | struct vme_bridge *bridge = list->parent->parent; |
@@ -962,6 +1196,15 @@ int vme_dma_list_exec(struct vme_dma_list *list) | |||
962 | } | 1196 | } |
963 | EXPORT_SYMBOL(vme_dma_list_exec); | 1197 | EXPORT_SYMBOL(vme_dma_list_exec); |
964 | 1198 | ||
1199 | /** | ||
1200 | * vme_dma_list_free - Free a VME DMA list. | ||
1201 | * @list: Pointer to VME list. | ||
1202 | * | ||
1203 | * Free the provided DMA list and all its entries. | ||
1204 | * | ||
1205 | * Return: Zero on success, -EINVAL on invalid VME resource, -EBUSY if resource | ||
1206 | * is still in use. Hardware specific errors also possible. | ||
1207 | */ | ||
965 | int vme_dma_list_free(struct vme_dma_list *list) | 1208 | int vme_dma_list_free(struct vme_dma_list *list) |
966 | { | 1209 | { |
967 | struct vme_bridge *bridge = list->parent->parent; | 1210 | struct vme_bridge *bridge = list->parent->parent; |
@@ -994,6 +1237,15 @@ int vme_dma_list_free(struct vme_dma_list *list) | |||
994 | } | 1237 | } |
995 | EXPORT_SYMBOL(vme_dma_list_free); | 1238 | EXPORT_SYMBOL(vme_dma_list_free); |
996 | 1239 | ||
1240 | /** | ||
1241 | * vme_dma_free - Free a VME DMA resource. | ||
1242 | * @resource: Pointer to VME DMA resource. | ||
1243 | * | ||
1244 | * Free the provided DMA resource so that it may be reallocated. | ||
1245 | * | ||
1246 | * Return: Zero on success, -EINVAL on invalid VME resource, -EBUSY if resource | ||
1247 | * is still active. | ||
1248 | */ | ||
997 | int vme_dma_free(struct vme_resource *resource) | 1249 | int vme_dma_free(struct vme_resource *resource) |
998 | { | 1250 | { |
999 | struct vme_dma_resource *ctrlr; | 1251 | struct vme_dma_resource *ctrlr; |
@@ -1099,6 +1351,22 @@ void vme_irq_handler(struct vme_bridge *bridge, int level, int statid) | |||
1099 | } | 1351 | } |
1100 | EXPORT_SYMBOL(vme_irq_handler); | 1352 | EXPORT_SYMBOL(vme_irq_handler); |
1101 | 1353 | ||
1354 | /** | ||
1355 | * vme_irq_request - Request a specific VME interrupt. | ||
1356 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | ||
1357 | * @level: Interrupt priority being requested. | ||
1358 | * @statid: Interrupt vector being requested. | ||
1359 | * @callback: Pointer to callback function called when VME interrupt/vector | ||
1360 | * received. | ||
1361 | * @priv_data: Generic pointer that will be passed to the callback function. | ||
1362 | * | ||
1363 | * Request callback to be attached as a handler for VME interrupts with provided | ||
1364 | * level and statid. | ||
1365 | * | ||
1366 | * Return: Zero on success, -EINVAL on invalid vme device, level or if the | ||
1367 | * function is not supported, -EBUSY if the level/statid combination is | ||
1368 | * already in use. Hardware specific errors also possible. | ||
1369 | */ | ||
1102 | int vme_irq_request(struct vme_dev *vdev, int level, int statid, | 1370 | int vme_irq_request(struct vme_dev *vdev, int level, int statid, |
1103 | void (*callback)(int, int, void *), | 1371 | void (*callback)(int, int, void *), |
1104 | void *priv_data) | 1372 | void *priv_data) |
@@ -1142,6 +1410,14 @@ int vme_irq_request(struct vme_dev *vdev, int level, int statid, | |||
1142 | } | 1410 | } |
1143 | EXPORT_SYMBOL(vme_irq_request); | 1411 | EXPORT_SYMBOL(vme_irq_request); |
1144 | 1412 | ||
1413 | /** | ||
1414 | * vme_irq_free - Free a VME interrupt. | ||
1415 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | ||
1416 | * @level: Interrupt priority of interrupt being freed. | ||
1417 | * @statid: Interrupt vector of interrupt being freed. | ||
1418 | * | ||
1419 | * Remove previously attached callback from VME interrupt priority/vector. | ||
1420 | */ | ||
1145 | void vme_irq_free(struct vme_dev *vdev, int level, int statid) | 1421 | void vme_irq_free(struct vme_dev *vdev, int level, int statid) |
1146 | { | 1422 | { |
1147 | struct vme_bridge *bridge; | 1423 | struct vme_bridge *bridge; |
@@ -1177,6 +1453,18 @@ void vme_irq_free(struct vme_dev *vdev, int level, int statid) | |||
1177 | } | 1453 | } |
1178 | EXPORT_SYMBOL(vme_irq_free); | 1454 | EXPORT_SYMBOL(vme_irq_free); |
1179 | 1455 | ||
1456 | /** | ||
1457 | * vme_irq_generate - Generate VME interrupt. | ||
1458 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | ||
1459 | * @level: Interrupt priority at which to assert the interrupt. | ||
1460 | * @statid: Interrupt vector to associate with the interrupt. | ||
1461 | * | ||
1462 | * Generate a VME interrupt of the provided level and with the provided | ||
1463 | * statid. | ||
1464 | * | ||
1465 | * Return: Zero on success, -EINVAL on invalid vme device, level or if the | ||
1466 | * function is not supported. Hardware specific errors also possible. | ||
1467 | */ | ||
1180 | int vme_irq_generate(struct vme_dev *vdev, int level, int statid) | 1468 | int vme_irq_generate(struct vme_dev *vdev, int level, int statid) |
1181 | { | 1469 | { |
1182 | struct vme_bridge *bridge; | 1470 | struct vme_bridge *bridge; |
@@ -1201,8 +1489,15 @@ int vme_irq_generate(struct vme_dev *vdev, int level, int statid) | |||
1201 | } | 1489 | } |
1202 | EXPORT_SYMBOL(vme_irq_generate); | 1490 | EXPORT_SYMBOL(vme_irq_generate); |
1203 | 1491 | ||
1204 | /* | 1492 | /** |
1205 | * Request the location monitor, return resource or NULL | 1493 | * vme_lm_request - Request a VME location monitor |
1494 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | ||
1495 | * | ||
1496 | * Allocate a location monitor resource to the driver. A location monitor | ||
1497 | * allows the driver to monitor accesses to a contiguous number of | ||
1498 | * addresses on the VME bus. | ||
1499 | * | ||
1500 | * Return: Pointer to a VME resource on success or NULL on failure. | ||
1206 | */ | 1501 | */ |
1207 | struct vme_resource *vme_lm_request(struct vme_dev *vdev) | 1502 | struct vme_resource *vme_lm_request(struct vme_dev *vdev) |
1208 | { | 1503 | { |
@@ -1218,7 +1513,7 @@ struct vme_resource *vme_lm_request(struct vme_dev *vdev) | |||
1218 | goto err_bus; | 1513 | goto err_bus; |
1219 | } | 1514 | } |
1220 | 1515 | ||
1221 | /* Loop through DMA resources */ | 1516 | /* Loop through LM resources */ |
1222 | list_for_each(lm_pos, &bridge->lm_resources) { | 1517 | list_for_each(lm_pos, &bridge->lm_resources) { |
1223 | lm = list_entry(lm_pos, | 1518 | lm = list_entry(lm_pos, |
1224 | struct vme_lm_resource, list); | 1519 | struct vme_lm_resource, list); |
@@ -1264,6 +1559,17 @@ err_bus: | |||
1264 | } | 1559 | } |
1265 | EXPORT_SYMBOL(vme_lm_request); | 1560 | EXPORT_SYMBOL(vme_lm_request); |
1266 | 1561 | ||
1562 | /** | ||
1563 | * vme_lm_count - Determine number of VME Addresses monitored | ||
1564 | * @resource: Pointer to VME location monitor resource. | ||
1565 | * | ||
1566 | * The number of contiguous addresses monitored is hardware dependent. | ||
1567 | * Return the number of contiguous addresses monitored by the | ||
1568 | * location monitor. | ||
1569 | * | ||
1570 | * Return: Count of addresses monitored or -EINVAL when provided with an | ||
1571 | * invalid location monitor resource. | ||
1572 | */ | ||
1267 | int vme_lm_count(struct vme_resource *resource) | 1573 | int vme_lm_count(struct vme_resource *resource) |
1268 | { | 1574 | { |
1269 | struct vme_lm_resource *lm; | 1575 | struct vme_lm_resource *lm; |
@@ -1279,6 +1585,20 @@ int vme_lm_count(struct vme_resource *resource) | |||
1279 | } | 1585 | } |
1280 | EXPORT_SYMBOL(vme_lm_count); | 1586 | EXPORT_SYMBOL(vme_lm_count); |
1281 | 1587 | ||
1588 | /** | ||
1589 | * vme_lm_set - Configure location monitor | ||
1590 | * @resource: Pointer to VME location monitor resource. | ||
1591 | * @lm_base: Base address to monitor. | ||
1592 | * @aspace: VME address space to monitor. | ||
1593 | * @cycle: VME bus cycle type to monitor. | ||
1594 | * | ||
1595 | * Set the base address, address space and cycle type of accesses to be | ||
1596 | * monitored by the location monitor. | ||
1597 | * | ||
1598 | * Return: Zero on success, -EINVAL when provided with an invalid location | ||
1599 | * monitor resource or function is not supported. Hardware specific | ||
1600 | * errors may also be returned. | ||
1601 | */ | ||
1282 | int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base, | 1602 | int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base, |
1283 | u32 aspace, u32 cycle) | 1603 | u32 aspace, u32 cycle) |
1284 | { | 1604 | { |
@@ -1301,6 +1621,20 @@ int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base, | |||
1301 | } | 1621 | } |
1302 | EXPORT_SYMBOL(vme_lm_set); | 1622 | EXPORT_SYMBOL(vme_lm_set); |
1303 | 1623 | ||
1624 | /** | ||
1625 | * vme_lm_get - Retrieve location monitor settings | ||
1626 | * @resource: Pointer to VME location monitor resource. | ||
1627 | * @lm_base: Pointer used to output the base address monitored. | ||
1628 | * @aspace: Pointer used to output the address space monitored. | ||
1629 | * @cycle: Pointer used to output the VME bus cycle type monitored. | ||
1630 | * | ||
1631 | * Retrieve the base address, address space and cycle type of accesses to | ||
1632 | * be monitored by the location monitor. | ||
1633 | * | ||
1634 | * Return: Zero on success, -EINVAL when provided with an invalid location | ||
1635 | * monitor resource or function is not supported. Hardware specific | ||
1636 | * errors may also be returned. | ||
1637 | */ | ||
1304 | int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base, | 1638 | int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base, |
1305 | u32 *aspace, u32 *cycle) | 1639 | u32 *aspace, u32 *cycle) |
1306 | { | 1640 | { |
@@ -1323,6 +1657,21 @@ int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base, | |||
1323 | } | 1657 | } |
1324 | EXPORT_SYMBOL(vme_lm_get); | 1658 | EXPORT_SYMBOL(vme_lm_get); |
1325 | 1659 | ||
1660 | /** | ||
1661 | * vme_lm_attach - Provide callback for location monitor address | ||
1662 | * @resource: Pointer to VME location monitor resource. | ||
1663 | * @monitor: Offset to which callback should be attached. | ||
1664 | * @callback: Pointer to callback function called when triggered. | ||
1665 | * @data: Generic pointer that will be passed to the callback function. | ||
1666 | * | ||
1667 | * Attach a callback to the specificed offset into the location monitors | ||
1668 | * monitored addresses. A generic pointer is provided to allow data to be | ||
1669 | * passed to the callback when called. | ||
1670 | * | ||
1671 | * Return: Zero on success, -EINVAL when provided with an invalid location | ||
1672 | * monitor resource or function is not supported. Hardware specific | ||
1673 | * errors may also be returned. | ||
1674 | */ | ||
1326 | int vme_lm_attach(struct vme_resource *resource, int monitor, | 1675 | int vme_lm_attach(struct vme_resource *resource, int monitor, |
1327 | void (*callback)(void *), void *data) | 1676 | void (*callback)(void *), void *data) |
1328 | { | 1677 | { |
@@ -1345,6 +1694,18 @@ int vme_lm_attach(struct vme_resource *resource, int monitor, | |||
1345 | } | 1694 | } |
1346 | EXPORT_SYMBOL(vme_lm_attach); | 1695 | EXPORT_SYMBOL(vme_lm_attach); |
1347 | 1696 | ||
1697 | /** | ||
1698 | * vme_lm_detach - Remove callback for location monitor address | ||
1699 | * @resource: Pointer to VME location monitor resource. | ||
1700 | * @monitor: Offset to which callback should be removed. | ||
1701 | * | ||
1702 | * Remove the callback associated with the specificed offset into the | ||
1703 | * location monitors monitored addresses. | ||
1704 | * | ||
1705 | * Return: Zero on success, -EINVAL when provided with an invalid location | ||
1706 | * monitor resource or function is not supported. Hardware specific | ||
1707 | * errors may also be returned. | ||
1708 | */ | ||
1348 | int vme_lm_detach(struct vme_resource *resource, int monitor) | 1709 | int vme_lm_detach(struct vme_resource *resource, int monitor) |
1349 | { | 1710 | { |
1350 | struct vme_bridge *bridge = find_bridge(resource); | 1711 | struct vme_bridge *bridge = find_bridge(resource); |
@@ -1366,6 +1727,18 @@ int vme_lm_detach(struct vme_resource *resource, int monitor) | |||
1366 | } | 1727 | } |
1367 | EXPORT_SYMBOL(vme_lm_detach); | 1728 | EXPORT_SYMBOL(vme_lm_detach); |
1368 | 1729 | ||
1730 | /** | ||
1731 | * vme_lm_free - Free allocated VME location monitor | ||
1732 | * @resource: Pointer to VME location monitor resource. | ||
1733 | * | ||
1734 | * Free allocation of a VME location monitor. | ||
1735 | * | ||
1736 | * WARNING: This function currently expects that any callbacks that have | ||
1737 | * been attached to the location monitor have been removed. | ||
1738 | * | ||
1739 | * Return: Zero on success, -EINVAL when provided with an invalid location | ||
1740 | * monitor resource. | ||
1741 | */ | ||
1369 | void vme_lm_free(struct vme_resource *resource) | 1742 | void vme_lm_free(struct vme_resource *resource) |
1370 | { | 1743 | { |
1371 | struct vme_lm_resource *lm; | 1744 | struct vme_lm_resource *lm; |
@@ -1392,6 +1765,16 @@ void vme_lm_free(struct vme_resource *resource) | |||
1392 | } | 1765 | } |
1393 | EXPORT_SYMBOL(vme_lm_free); | 1766 | EXPORT_SYMBOL(vme_lm_free); |
1394 | 1767 | ||
1768 | /** | ||
1769 | * vme_slot_num - Retrieve slot ID | ||
1770 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | ||
1771 | * | ||
1772 | * Retrieve the slot ID associated with the provided VME device. | ||
1773 | * | ||
1774 | * Return: The slot ID on success, -EINVAL if VME bridge cannot be determined | ||
1775 | * or the function is not supported. Hardware specific errors may also | ||
1776 | * be returned. | ||
1777 | */ | ||
1395 | int vme_slot_num(struct vme_dev *vdev) | 1778 | int vme_slot_num(struct vme_dev *vdev) |
1396 | { | 1779 | { |
1397 | struct vme_bridge *bridge; | 1780 | struct vme_bridge *bridge; |
@@ -1411,6 +1794,15 @@ int vme_slot_num(struct vme_dev *vdev) | |||
1411 | } | 1794 | } |
1412 | EXPORT_SYMBOL(vme_slot_num); | 1795 | EXPORT_SYMBOL(vme_slot_num); |
1413 | 1796 | ||
1797 | /** | ||
1798 | * vme_bus_num - Retrieve bus number | ||
1799 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | ||
1800 | * | ||
1801 | * Retrieve the bus enumeration associated with the provided VME device. | ||
1802 | * | ||
1803 | * Return: The bus number on success, -EINVAL if VME bridge cannot be | ||
1804 | * determined. | ||
1805 | */ | ||
1414 | int vme_bus_num(struct vme_dev *vdev) | 1806 | int vme_bus_num(struct vme_dev *vdev) |
1415 | { | 1807 | { |
1416 | struct vme_bridge *bridge; | 1808 | struct vme_bridge *bridge; |
@@ -1556,6 +1948,15 @@ static int __vme_register_driver(struct vme_driver *drv, unsigned int ndevs) | |||
1556 | return err; | 1948 | return err; |
1557 | } | 1949 | } |
1558 | 1950 | ||
1951 | /** | ||
1952 | * vme_register_driver - Register a VME driver | ||
1953 | * @drv: Pointer to VME driver structure to register. | ||
1954 | * @ndevs: Maximum number of devices to allow to be enumerated. | ||
1955 | * | ||
1956 | * Register a VME device driver with the VME subsystem. | ||
1957 | * | ||
1958 | * Return: Zero on success, error value on registration failure. | ||
1959 | */ | ||
1559 | int vme_register_driver(struct vme_driver *drv, unsigned int ndevs) | 1960 | int vme_register_driver(struct vme_driver *drv, unsigned int ndevs) |
1560 | { | 1961 | { |
1561 | int err; | 1962 | int err; |
@@ -1576,6 +1977,12 @@ int vme_register_driver(struct vme_driver *drv, unsigned int ndevs) | |||
1576 | } | 1977 | } |
1577 | EXPORT_SYMBOL(vme_register_driver); | 1978 | EXPORT_SYMBOL(vme_register_driver); |
1578 | 1979 | ||
1980 | /** | ||
1981 | * vme_unregister_driver - Unregister a VME driver | ||
1982 | * @drv: Pointer to VME driver structure to unregister. | ||
1983 | * | ||
1984 | * Unregister a VME device driver from the VME subsystem. | ||
1985 | */ | ||
1579 | void vme_unregister_driver(struct vme_driver *drv) | 1986 | void vme_unregister_driver(struct vme_driver *drv) |
1580 | { | 1987 | { |
1581 | struct vme_dev *dev, *dev_tmp; | 1988 | struct vme_dev *dev, *dev_tmp; |
diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c index 3749db8b4396..97a676bf5989 100644 --- a/drivers/w1/masters/matrox_w1.c +++ b/drivers/w1/masters/matrox_w1.c | |||
@@ -36,7 +36,6 @@ | |||
36 | 36 | ||
37 | #include "../w1.h" | 37 | #include "../w1.h" |
38 | #include "../w1_int.h" | 38 | #include "../w1_int.h" |
39 | #include "../w1_log.h" | ||
40 | 39 | ||
41 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
42 | MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>"); | 41 | MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>"); |
@@ -157,9 +156,6 @@ static int matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent | |||
157 | struct matrox_device *dev; | 156 | struct matrox_device *dev; |
158 | int err; | 157 | int err; |
159 | 158 | ||
160 | assert(pdev != NULL); | ||
161 | assert(ent != NULL); | ||
162 | |||
163 | if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400) | 159 | if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400) |
164 | return -ENODEV; | 160 | return -ENODEV; |
165 | 161 | ||
@@ -224,8 +220,6 @@ static void matrox_w1_remove(struct pci_dev *pdev) | |||
224 | { | 220 | { |
225 | struct matrox_device *dev = pci_get_drvdata(pdev); | 221 | struct matrox_device *dev = pci_get_drvdata(pdev); |
226 | 222 | ||
227 | assert(dev != NULL); | ||
228 | |||
229 | if (dev->found) { | 223 | if (dev->found) { |
230 | w1_remove_master_device(dev->bus_master); | 224 | w1_remove_master_device(dev->bus_master); |
231 | iounmap(dev->virt_addr); | 225 | iounmap(dev->virt_addr); |
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index 0ef9f2663dbd..fb68465908f2 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig | |||
@@ -86,6 +86,12 @@ config W1_SLAVE_DS2433_CRC | |||
86 | Each block has 30 bytes of data and a two byte CRC16. | 86 | Each block has 30 bytes of data and a two byte CRC16. |
87 | Full block writes are only allowed if the CRC is valid. | 87 | Full block writes are only allowed if the CRC is valid. |
88 | 88 | ||
89 | config W1_SLAVE_DS2438 | ||
90 | tristate "DS2438 Smart Battery Monitor 0x26 family support" | ||
91 | help | ||
92 | Say Y here if you want to use a 1-wire | ||
93 | DS2438 Smart Battery Monitor device support | ||
94 | |||
89 | config W1_SLAVE_DS2760 | 95 | config W1_SLAVE_DS2760 |
90 | tristate "Dallas 2760 battery monitor chip (HP iPAQ & others)" | 96 | tristate "Dallas 2760 battery monitor chip (HP iPAQ & others)" |
91 | help | 97 | help |
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile index b4a358955ef9..54c63e420302 100644 --- a/drivers/w1/slaves/Makefile +++ b/drivers/w1/slaves/Makefile | |||
@@ -11,6 +11,7 @@ obj-$(CONFIG_W1_SLAVE_DS2406) += w1_ds2406.o | |||
11 | obj-$(CONFIG_W1_SLAVE_DS2423) += w1_ds2423.o | 11 | obj-$(CONFIG_W1_SLAVE_DS2423) += w1_ds2423.o |
12 | obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o | 12 | obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o |
13 | obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o | 13 | obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o |
14 | obj-$(CONFIG_W1_SLAVE_DS2438) += w1_ds2438.o | ||
14 | obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o | 15 | obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o |
15 | obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o | 16 | obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o |
16 | obj-$(CONFIG_W1_SLAVE_DS2781) += w1_ds2781.o | 17 | obj-$(CONFIG_W1_SLAVE_DS2781) += w1_ds2781.o |
diff --git a/drivers/w1/slaves/w1_ds2438.c b/drivers/w1/slaves/w1_ds2438.c new file mode 100644 index 000000000000..5ededb4965e1 --- /dev/null +++ b/drivers/w1/slaves/w1_ds2438.c | |||
@@ -0,0 +1,390 @@ | |||
1 | /* | ||
2 | * 1-Wire implementation for the ds2438 chip | ||
3 | * | ||
4 | * Copyright (c) 2017 Mariusz Bialonczyk <manio@skyboo.net> | ||
5 | * | ||
6 | * This source code is licensed under the GNU General Public License, | ||
7 | * Version 2. See the file COPYING for more details. | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/device.h> | ||
13 | #include <linux/types.h> | ||
14 | #include <linux/delay.h> | ||
15 | |||
16 | #include "../w1.h" | ||
17 | #include "../w1_family.h" | ||
18 | |||
19 | #define W1_DS2438_RETRIES 3 | ||
20 | |||
21 | /* Memory commands */ | ||
22 | #define W1_DS2438_READ_SCRATCH 0xBE | ||
23 | #define W1_DS2438_WRITE_SCRATCH 0x4E | ||
24 | #define W1_DS2438_COPY_SCRATCH 0x48 | ||
25 | #define W1_DS2438_RECALL_MEMORY 0xB8 | ||
26 | /* Register commands */ | ||
27 | #define W1_DS2438_CONVERT_TEMP 0x44 | ||
28 | #define W1_DS2438_CONVERT_VOLTAGE 0xB4 | ||
29 | |||
30 | #define DS2438_PAGE_SIZE 8 | ||
31 | #define DS2438_ADC_INPUT_VAD 0 | ||
32 | #define DS2438_ADC_INPUT_VDD 1 | ||
33 | #define DS2438_MAX_CONVERSION_TIME 10 /* ms */ | ||
34 | |||
35 | /* Page #0 definitions */ | ||
36 | #define DS2438_STATUS_REG 0x00 /* Status/Configuration Register */ | ||
37 | #define DS2438_STATUS_IAD (1 << 0) /* Current A/D Control Bit */ | ||
38 | #define DS2438_STATUS_CA (1 << 1) /* Current Accumulator Configuration */ | ||
39 | #define DS2438_STATUS_EE (1 << 2) /* Current Accumulator Shadow Selector bit */ | ||
40 | #define DS2438_STATUS_AD (1 << 3) /* Voltage A/D Input Select Bit */ | ||
41 | #define DS2438_STATUS_TB (1 << 4) /* Temperature Busy Flag */ | ||
42 | #define DS2438_STATUS_NVB (1 << 5) /* Nonvolatile Memory Busy Flag */ | ||
43 | #define DS2438_STATUS_ADB (1 << 6) /* A/D Converter Busy Flag */ | ||
44 | |||
45 | #define DS2438_TEMP_LSB 0x01 | ||
46 | #define DS2438_TEMP_MSB 0x02 | ||
47 | #define DS2438_VOLTAGE_LSB 0x03 | ||
48 | #define DS2438_VOLTAGE_MSB 0x04 | ||
49 | #define DS2438_CURRENT_LSB 0x05 | ||
50 | #define DS2438_CURRENT_MSB 0x06 | ||
51 | #define DS2438_THRESHOLD 0x07 | ||
52 | |||
53 | int w1_ds2438_get_page(struct w1_slave *sl, int pageno, u8 *buf) | ||
54 | { | ||
55 | unsigned int retries = W1_DS2438_RETRIES; | ||
56 | u8 w1_buf[2]; | ||
57 | u8 crc; | ||
58 | size_t count; | ||
59 | |||
60 | while (retries--) { | ||
61 | crc = 0; | ||
62 | |||
63 | if (w1_reset_select_slave(sl)) | ||
64 | continue; | ||
65 | w1_buf[0] = W1_DS2438_RECALL_MEMORY; | ||
66 | w1_buf[1] = 0x00; | ||
67 | w1_write_block(sl->master, w1_buf, 2); | ||
68 | |||
69 | if (w1_reset_select_slave(sl)) | ||
70 | continue; | ||
71 | w1_buf[0] = W1_DS2438_READ_SCRATCH; | ||
72 | w1_buf[1] = 0x00; | ||
73 | w1_write_block(sl->master, w1_buf, 2); | ||
74 | |||
75 | count = w1_read_block(sl->master, buf, DS2438_PAGE_SIZE + 1); | ||
76 | if (count == DS2438_PAGE_SIZE + 1) { | ||
77 | crc = w1_calc_crc8(buf, DS2438_PAGE_SIZE); | ||
78 | |||
79 | /* check for correct CRC */ | ||
80 | if ((u8)buf[DS2438_PAGE_SIZE] == crc) | ||
81 | return 0; | ||
82 | } | ||
83 | } | ||
84 | return -1; | ||
85 | } | ||
86 | |||
87 | int w1_ds2438_get_temperature(struct w1_slave *sl, int16_t *temperature) | ||
88 | { | ||
89 | unsigned int retries = W1_DS2438_RETRIES; | ||
90 | u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; | ||
91 | unsigned int tm = DS2438_MAX_CONVERSION_TIME; | ||
92 | unsigned long sleep_rem; | ||
93 | int ret; | ||
94 | |||
95 | mutex_lock(&sl->master->bus_mutex); | ||
96 | |||
97 | while (retries--) { | ||
98 | if (w1_reset_select_slave(sl)) | ||
99 | continue; | ||
100 | w1_write_8(sl->master, W1_DS2438_CONVERT_TEMP); | ||
101 | |||
102 | mutex_unlock(&sl->master->bus_mutex); | ||
103 | sleep_rem = msleep_interruptible(tm); | ||
104 | if (sleep_rem != 0) { | ||
105 | ret = -1; | ||
106 | goto post_unlock; | ||
107 | } | ||
108 | |||
109 | if (mutex_lock_interruptible(&sl->master->bus_mutex) != 0) { | ||
110 | ret = -1; | ||
111 | goto post_unlock; | ||
112 | } | ||
113 | |||
114 | break; | ||
115 | } | ||
116 | |||
117 | if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { | ||
118 | *temperature = (((int16_t) w1_buf[DS2438_TEMP_MSB]) << 8) | ((uint16_t) w1_buf[DS2438_TEMP_LSB]); | ||
119 | ret = 0; | ||
120 | } else | ||
121 | ret = -1; | ||
122 | |||
123 | mutex_unlock(&sl->master->bus_mutex); | ||
124 | |||
125 | post_unlock: | ||
126 | return ret; | ||
127 | } | ||
128 | |||
129 | int w1_ds2438_change_config_bit(struct w1_slave *sl, u8 mask, u8 value) | ||
130 | { | ||
131 | unsigned int retries = W1_DS2438_RETRIES; | ||
132 | u8 w1_buf[3]; | ||
133 | u8 status; | ||
134 | int perform_write = 0; | ||
135 | |||
136 | while (retries--) { | ||
137 | if (w1_reset_select_slave(sl)) | ||
138 | continue; | ||
139 | w1_buf[0] = W1_DS2438_RECALL_MEMORY; | ||
140 | w1_buf[1] = 0x00; | ||
141 | w1_write_block(sl->master, w1_buf, 2); | ||
142 | |||
143 | if (w1_reset_select_slave(sl)) | ||
144 | continue; | ||
145 | w1_buf[0] = W1_DS2438_READ_SCRATCH; | ||
146 | w1_buf[1] = 0x00; | ||
147 | w1_write_block(sl->master, w1_buf, 2); | ||
148 | |||
149 | /* reading one byte of result */ | ||
150 | status = w1_read_8(sl->master); | ||
151 | |||
152 | /* if bit0=1, set a value to a mask for easy compare */ | ||
153 | if (value) | ||
154 | value = mask; | ||
155 | |||
156 | if ((status & mask) == value) | ||
157 | return 0; /* already set as requested */ | ||
158 | else { | ||
159 | /* changing bit */ | ||
160 | status ^= mask; | ||
161 | perform_write = 1; | ||
162 | } | ||
163 | break; | ||
164 | } | ||
165 | |||
166 | if (perform_write) { | ||
167 | retries = W1_DS2438_RETRIES; | ||
168 | while (retries--) { | ||
169 | if (w1_reset_select_slave(sl)) | ||
170 | continue; | ||
171 | w1_buf[0] = W1_DS2438_WRITE_SCRATCH; | ||
172 | w1_buf[1] = 0x00; | ||
173 | w1_buf[2] = status; | ||
174 | w1_write_block(sl->master, w1_buf, 3); | ||
175 | |||
176 | if (w1_reset_select_slave(sl)) | ||
177 | continue; | ||
178 | w1_buf[0] = W1_DS2438_COPY_SCRATCH; | ||
179 | w1_buf[1] = 0x00; | ||
180 | w1_write_block(sl->master, w1_buf, 2); | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | } | ||
185 | return -1; | ||
186 | } | ||
187 | |||
188 | uint16_t w1_ds2438_get_voltage(struct w1_slave *sl, int adc_input, uint16_t *voltage) | ||
189 | { | ||
190 | unsigned int retries = W1_DS2438_RETRIES; | ||
191 | u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; | ||
192 | unsigned int tm = DS2438_MAX_CONVERSION_TIME; | ||
193 | unsigned long sleep_rem; | ||
194 | int ret; | ||
195 | |||
196 | mutex_lock(&sl->master->bus_mutex); | ||
197 | |||
198 | if (w1_ds2438_change_config_bit(sl, DS2438_STATUS_AD, adc_input)) { | ||
199 | ret = -1; | ||
200 | goto pre_unlock; | ||
201 | } | ||
202 | |||
203 | while (retries--) { | ||
204 | if (w1_reset_select_slave(sl)) | ||
205 | continue; | ||
206 | w1_write_8(sl->master, W1_DS2438_CONVERT_VOLTAGE); | ||
207 | |||
208 | mutex_unlock(&sl->master->bus_mutex); | ||
209 | sleep_rem = msleep_interruptible(tm); | ||
210 | if (sleep_rem != 0) { | ||
211 | ret = -1; | ||
212 | goto post_unlock; | ||
213 | } | ||
214 | |||
215 | if (mutex_lock_interruptible(&sl->master->bus_mutex) != 0) { | ||
216 | ret = -1; | ||
217 | goto post_unlock; | ||
218 | } | ||
219 | |||
220 | break; | ||
221 | } | ||
222 | |||
223 | if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { | ||
224 | *voltage = (((uint16_t) w1_buf[DS2438_VOLTAGE_MSB]) << 8) | ((uint16_t) w1_buf[DS2438_VOLTAGE_LSB]); | ||
225 | ret = 0; | ||
226 | } else | ||
227 | ret = -1; | ||
228 | |||
229 | pre_unlock: | ||
230 | mutex_unlock(&sl->master->bus_mutex); | ||
231 | |||
232 | post_unlock: | ||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | static ssize_t iad_write(struct file *filp, struct kobject *kobj, | ||
237 | struct bin_attribute *bin_attr, char *buf, | ||
238 | loff_t off, size_t count) | ||
239 | { | ||
240 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
241 | int ret; | ||
242 | |||
243 | if (count != 1 || off != 0) | ||
244 | return -EFAULT; | ||
245 | |||
246 | mutex_lock(&sl->master->bus_mutex); | ||
247 | |||
248 | if (w1_ds2438_change_config_bit(sl, DS2438_STATUS_IAD, *buf & 0x01) == 0) | ||
249 | ret = 1; | ||
250 | else | ||
251 | ret = -EIO; | ||
252 | |||
253 | mutex_unlock(&sl->master->bus_mutex); | ||
254 | |||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | static ssize_t page0_read(struct file *filp, struct kobject *kobj, | ||
259 | struct bin_attribute *bin_attr, char *buf, | ||
260 | loff_t off, size_t count) | ||
261 | { | ||
262 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
263 | int ret; | ||
264 | u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; | ||
265 | |||
266 | if (off != 0) | ||
267 | return 0; | ||
268 | if (!buf) | ||
269 | return -EINVAL; | ||
270 | |||
271 | mutex_lock(&sl->master->bus_mutex); | ||
272 | |||
273 | if (w1_ds2438_get_page(sl, 0, w1_buf) == 0) { | ||
274 | memcpy(buf, &w1_buf, DS2438_PAGE_SIZE); | ||
275 | ret = DS2438_PAGE_SIZE; | ||
276 | } else | ||
277 | ret = -EIO; | ||
278 | |||
279 | mutex_unlock(&sl->master->bus_mutex); | ||
280 | |||
281 | return ret; | ||
282 | } | ||
283 | |||
284 | static ssize_t temperature_read(struct file *filp, struct kobject *kobj, | ||
285 | struct bin_attribute *bin_attr, char *buf, | ||
286 | loff_t off, size_t count) | ||
287 | { | ||
288 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
289 | int ret; | ||
290 | ssize_t c = PAGE_SIZE; | ||
291 | int16_t temp; | ||
292 | |||
293 | if (off != 0) | ||
294 | return 0; | ||
295 | if (!buf) | ||
296 | return -EINVAL; | ||
297 | |||
298 | if (w1_ds2438_get_temperature(sl, &temp) == 0) { | ||
299 | c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", temp); | ||
300 | ret = PAGE_SIZE - c; | ||
301 | } else | ||
302 | ret = -EIO; | ||
303 | |||
304 | return ret; | ||
305 | } | ||
306 | |||
307 | static ssize_t vad_read(struct file *filp, struct kobject *kobj, | ||
308 | struct bin_attribute *bin_attr, char *buf, | ||
309 | loff_t off, size_t count) | ||
310 | { | ||
311 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
312 | int ret; | ||
313 | ssize_t c = PAGE_SIZE; | ||
314 | uint16_t voltage; | ||
315 | |||
316 | if (off != 0) | ||
317 | return 0; | ||
318 | if (!buf) | ||
319 | return -EINVAL; | ||
320 | |||
321 | if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VAD, &voltage) == 0) { | ||
322 | c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", voltage); | ||
323 | ret = PAGE_SIZE - c; | ||
324 | } else | ||
325 | ret = -EIO; | ||
326 | |||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | static ssize_t vdd_read(struct file *filp, struct kobject *kobj, | ||
331 | struct bin_attribute *bin_attr, char *buf, | ||
332 | loff_t off, size_t count) | ||
333 | { | ||
334 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
335 | int ret; | ||
336 | ssize_t c = PAGE_SIZE; | ||
337 | uint16_t voltage; | ||
338 | |||
339 | if (off != 0) | ||
340 | return 0; | ||
341 | if (!buf) | ||
342 | return -EINVAL; | ||
343 | |||
344 | if (w1_ds2438_get_voltage(sl, DS2438_ADC_INPUT_VDD, &voltage) == 0) { | ||
345 | c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", voltage); | ||
346 | ret = PAGE_SIZE - c; | ||
347 | } else | ||
348 | ret = -EIO; | ||
349 | |||
350 | return ret; | ||
351 | } | ||
352 | |||
353 | static BIN_ATTR(iad, S_IRUGO | S_IWUSR | S_IWGRP, NULL, iad_write, 1); | ||
354 | static BIN_ATTR_RO(page0, DS2438_PAGE_SIZE); | ||
355 | static BIN_ATTR_RO(temperature, 0/* real length varies */); | ||
356 | static BIN_ATTR_RO(vad, 0/* real length varies */); | ||
357 | static BIN_ATTR_RO(vdd, 0/* real length varies */); | ||
358 | |||
359 | static struct bin_attribute *w1_ds2438_bin_attrs[] = { | ||
360 | &bin_attr_iad, | ||
361 | &bin_attr_page0, | ||
362 | &bin_attr_temperature, | ||
363 | &bin_attr_vad, | ||
364 | &bin_attr_vdd, | ||
365 | NULL, | ||
366 | }; | ||
367 | |||
368 | static const struct attribute_group w1_ds2438_group = { | ||
369 | .bin_attrs = w1_ds2438_bin_attrs, | ||
370 | }; | ||
371 | |||
372 | static const struct attribute_group *w1_ds2438_groups[] = { | ||
373 | &w1_ds2438_group, | ||
374 | NULL, | ||
375 | }; | ||
376 | |||
377 | static struct w1_family_ops w1_ds2438_fops = { | ||
378 | .groups = w1_ds2438_groups, | ||
379 | }; | ||
380 | |||
381 | static struct w1_family w1_ds2438_family = { | ||
382 | .fid = W1_FAMILY_DS2438, | ||
383 | .fops = &w1_ds2438_fops, | ||
384 | }; | ||
385 | module_w1_family(w1_ds2438_family); | ||
386 | |||
387 | MODULE_LICENSE("GPL"); | ||
388 | MODULE_AUTHOR("Mariusz Bialonczyk <manio@skyboo.net>"); | ||
389 | MODULE_DESCRIPTION("1-wire driver for Maxim/Dallas DS2438 Smart Battery Monitor"); | ||
390 | MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2438)); | ||
diff --git a/drivers/w1/slaves/w1_ds2760.h b/drivers/w1/slaves/w1_ds2760.h index 58e774141568..24168c94eeae 100644 --- a/drivers/w1/slaves/w1_ds2760.h +++ b/drivers/w1/slaves/w1_ds2760.h | |||
@@ -24,11 +24,13 @@ | |||
24 | #define DS2760_DATA_SIZE 0x40 | 24 | #define DS2760_DATA_SIZE 0x40 |
25 | 25 | ||
26 | #define DS2760_PROTECTION_REG 0x00 | 26 | #define DS2760_PROTECTION_REG 0x00 |
27 | |||
27 | #define DS2760_STATUS_REG 0x01 | 28 | #define DS2760_STATUS_REG 0x01 |
28 | #define DS2760_STATUS_IE (1 << 2) | 29 | #define DS2760_STATUS_IE (1 << 2) |
29 | #define DS2760_STATUS_SWEN (1 << 3) | 30 | #define DS2760_STATUS_SWEN (1 << 3) |
30 | #define DS2760_STATUS_RNAOP (1 << 4) | 31 | #define DS2760_STATUS_RNAOP (1 << 4) |
31 | #define DS2760_STATUS_PMOD (1 << 5) | 32 | #define DS2760_STATUS_PMOD (1 << 5) |
33 | |||
32 | #define DS2760_EEPROM_REG 0x07 | 34 | #define DS2760_EEPROM_REG 0x07 |
33 | #define DS2760_SPECIAL_FEATURE_REG 0x08 | 35 | #define DS2760_SPECIAL_FEATURE_REG 0x08 |
34 | #define DS2760_VOLTAGE_MSB 0x0c | 36 | #define DS2760_VOLTAGE_MSB 0x0c |
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 90a3d9338fd2..8511d1685db9 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
@@ -29,7 +29,6 @@ | |||
29 | #include <linux/atomic.h> | 29 | #include <linux/atomic.h> |
30 | 30 | ||
31 | #include "w1.h" | 31 | #include "w1.h" |
32 | #include "w1_log.h" | ||
33 | #include "w1_int.h" | 32 | #include "w1_int.h" |
34 | #include "w1_family.h" | 33 | #include "w1_family.h" |
35 | #include "w1_netlink.h" | 34 | #include "w1_netlink.h" |
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index c4a6b257a367..869a3ff87d29 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h | |||
@@ -29,6 +29,7 @@ | |||
29 | #define W1_COUNTER_DS2423 0x1D | 29 | #define W1_COUNTER_DS2423 0x1D |
30 | #define W1_THERM_DS1822 0x22 | 30 | #define W1_THERM_DS1822 0x22 |
31 | #define W1_EEPROM_DS2433 0x23 | 31 | #define W1_EEPROM_DS2433 0x23 |
32 | #define W1_FAMILY_DS2438 0x26 | ||
32 | #define W1_THERM_DS18B20 0x28 | 33 | #define W1_THERM_DS18B20 0x28 |
33 | #define W1_FAMILY_DS2408 0x29 | 34 | #define W1_FAMILY_DS2408 0x29 |
34 | #define W1_EEPROM_DS2431 0x2D | 35 | #define W1_EEPROM_DS2431 0x2D |
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index 2cae7b29bb5f..1072a2e620bb 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/moduleparam.h> | 22 | #include <linux/moduleparam.h> |
23 | 23 | ||
24 | #include "w1.h" | 24 | #include "w1.h" |
25 | #include "w1_log.h" | ||
26 | #include "w1_netlink.h" | 25 | #include "w1_netlink.h" |
27 | #include "w1_int.h" | 26 | #include "w1_int.h" |
28 | 27 | ||
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index de8bebc27896..1134e6b1eb02 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | 20 | ||
21 | #include "w1.h" | 21 | #include "w1.h" |
22 | #include "w1_log.h" | ||
23 | 22 | ||
24 | static int w1_delay_parm = 1; | 23 | static int w1_delay_parm = 1; |
25 | module_param_named(delay_coef, w1_delay_parm, int, 0); | 24 | module_param_named(delay_coef, w1_delay_parm, int, 0); |
diff --git a/drivers/w1/w1_log.h b/drivers/w1/w1_log.h deleted file mode 100644 index dd1422b6afbb..000000000000 --- a/drivers/w1/w1_log.h +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | */ | ||
14 | |||
15 | #ifndef __W1_LOG_H | ||
16 | #define __W1_LOG_H | ||
17 | |||
18 | #define DEBUG | ||
19 | |||
20 | #ifdef W1_DEBUG | ||
21 | # define assert(expr) do {} while (0) | ||
22 | #else | ||
23 | # define assert(expr) \ | ||
24 | if(unlikely(!(expr))) { \ | ||
25 | pr_err("Assertion failed! %s,%s,%s,line=%d\n", \ | ||
26 | #expr, __FILE__, __func__, __LINE__); \ | ||
27 | } | ||
28 | #endif | ||
29 | |||
30 | #endif /* __W1_LOG_H */ | ||
31 | |||
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 49e520ca79c5..027950f997d1 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c | |||
@@ -18,13 +18,10 @@ | |||
18 | #include <linux/connector.h> | 18 | #include <linux/connector.h> |
19 | 19 | ||
20 | #include "w1.h" | 20 | #include "w1.h" |
21 | #include "w1_log.h" | ||
22 | #include "w1_netlink.h" | 21 | #include "w1_netlink.h" |
23 | 22 | ||
24 | #if defined(CONFIG_W1_CON) && (defined(CONFIG_CONNECTOR) || (defined(CONFIG_CONNECTOR_MODULE) && defined(CONFIG_W1_MODULE))) | 23 | #if defined(CONFIG_W1_CON) && (defined(CONFIG_CONNECTOR) || (defined(CONFIG_CONNECTOR_MODULE) && defined(CONFIG_W1_MODULE))) |
25 | 24 | ||
26 | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) | ||
27 | |||
28 | /* Bundle together everything required to process a request in one memory | 25 | /* Bundle together everything required to process a request in one memory |
29 | * allocation. | 26 | * allocation. |
30 | */ | 27 | */ |
@@ -598,7 +595,7 @@ static void w1_cn_callback(struct cn_msg *cn, struct netlink_skb_parms *nsp) | |||
598 | sizeof(struct w1_netlink_msg) + | 595 | sizeof(struct w1_netlink_msg) + |
599 | sizeof(struct w1_netlink_cmd)); | 596 | sizeof(struct w1_netlink_cmd)); |
600 | } | 597 | } |
601 | reply_size = MIN(CONNECTOR_MAX_MSG_SIZE, reply_size); | 598 | reply_size = min(CONNECTOR_MAX_MSG_SIZE, reply_size); |
602 | 599 | ||
603 | /* allocate space for the block, a copy of the original message, | 600 | /* allocate space for the block, a copy of the original message, |
604 | * one node per cmd to point into the original message, | 601 | * one node per cmd to point into the original message, |
diff --git a/drivers/zorro/zorro-driver.c b/drivers/zorro/zorro-driver.c index eacae1434b73..fa23b7366b98 100644 --- a/drivers/zorro/zorro-driver.c +++ b/drivers/zorro/zorro-driver.c | |||
@@ -14,6 +14,8 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/zorro.h> | 15 | #include <linux/zorro.h> |
16 | 16 | ||
17 | #include "zorro.h" | ||
18 | |||
17 | 19 | ||
18 | /** | 20 | /** |
19 | * zorro_match_device - Tell if a Zorro device structure has a matching | 21 | * zorro_match_device - Tell if a Zorro device structure has a matching |
@@ -161,12 +163,13 @@ static int zorro_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
161 | } | 163 | } |
162 | 164 | ||
163 | struct bus_type zorro_bus_type = { | 165 | struct bus_type zorro_bus_type = { |
164 | .name = "zorro", | 166 | .name = "zorro", |
165 | .dev_name = "zorro", | 167 | .dev_name = "zorro", |
166 | .match = zorro_bus_match, | 168 | .dev_groups = zorro_device_attribute_groups, |
167 | .uevent = zorro_uevent, | 169 | .match = zorro_bus_match, |
168 | .probe = zorro_device_probe, | 170 | .uevent = zorro_uevent, |
169 | .remove = zorro_device_remove, | 171 | .probe = zorro_device_probe, |
172 | .remove = zorro_device_remove, | ||
170 | }; | 173 | }; |
171 | EXPORT_SYMBOL(zorro_bus_type); | 174 | EXPORT_SYMBOL(zorro_bus_type); |
172 | 175 | ||
diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c index 9282dbf5abdb..3d34dba9bb2d 100644 --- a/drivers/zorro/zorro-sysfs.c +++ b/drivers/zorro/zorro-sysfs.c | |||
@@ -23,33 +23,33 @@ | |||
23 | 23 | ||
24 | /* show configuration fields */ | 24 | /* show configuration fields */ |
25 | #define zorro_config_attr(name, field, format_string) \ | 25 | #define zorro_config_attr(name, field, format_string) \ |
26 | static ssize_t \ | 26 | static ssize_t name##_show(struct device *dev, \ |
27 | show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ | 27 | struct device_attribute *attr, char *buf) \ |
28 | { \ | 28 | { \ |
29 | struct zorro_dev *z; \ | 29 | struct zorro_dev *z; \ |
30 | \ | 30 | \ |
31 | z = to_zorro_dev(dev); \ | 31 | z = to_zorro_dev(dev); \ |
32 | return sprintf(buf, format_string, z->field); \ | 32 | return sprintf(buf, format_string, z->field); \ |
33 | } \ | 33 | } \ |
34 | static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); | 34 | static DEVICE_ATTR_RO(name); |
35 | 35 | ||
36 | zorro_config_attr(id, id, "0x%08x\n"); | 36 | zorro_config_attr(id, id, "0x%08x\n"); |
37 | zorro_config_attr(type, rom.er_Type, "0x%02x\n"); | 37 | zorro_config_attr(type, rom.er_Type, "0x%02x\n"); |
38 | zorro_config_attr(slotaddr, slotaddr, "0x%04x\n"); | 38 | zorro_config_attr(slotaddr, slotaddr, "0x%04x\n"); |
39 | zorro_config_attr(slotsize, slotsize, "0x%04x\n"); | 39 | zorro_config_attr(slotsize, slotsize, "0x%04x\n"); |
40 | 40 | ||
41 | static ssize_t | 41 | static ssize_t serial_show(struct device *dev, struct device_attribute *attr, |
42 | show_serial(struct device *dev, struct device_attribute *attr, char *buf) | 42 | char *buf) |
43 | { | 43 | { |
44 | struct zorro_dev *z; | 44 | struct zorro_dev *z; |
45 | 45 | ||
46 | z = to_zorro_dev(dev); | 46 | z = to_zorro_dev(dev); |
47 | return sprintf(buf, "0x%08x\n", be32_to_cpu(z->rom.er_SerialNumber)); | 47 | return sprintf(buf, "0x%08x\n", be32_to_cpu(z->rom.er_SerialNumber)); |
48 | } | 48 | } |
49 | static DEVICE_ATTR_RO(serial); | ||
49 | 50 | ||
50 | static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL); | 51 | static ssize_t resource_show(struct device *dev, struct device_attribute *attr, |
51 | 52 | char *buf) | |
52 | static ssize_t zorro_show_resource(struct device *dev, struct device_attribute *attr, char *buf) | ||
53 | { | 53 | { |
54 | struct zorro_dev *z = to_zorro_dev(dev); | 54 | struct zorro_dev *z = to_zorro_dev(dev); |
55 | 55 | ||
@@ -58,8 +58,27 @@ static ssize_t zorro_show_resource(struct device *dev, struct device_attribute * | |||
58 | (unsigned long)zorro_resource_end(z), | 58 | (unsigned long)zorro_resource_end(z), |
59 | zorro_resource_flags(z)); | 59 | zorro_resource_flags(z)); |
60 | } | 60 | } |
61 | static DEVICE_ATTR_RO(resource); | ||
62 | |||
63 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | ||
64 | char *buf) | ||
65 | { | ||
66 | struct zorro_dev *z = to_zorro_dev(dev); | ||
61 | 67 | ||
62 | static DEVICE_ATTR(resource, S_IRUGO, zorro_show_resource, NULL); | 68 | return sprintf(buf, ZORRO_DEVICE_MODALIAS_FMT "\n", z->id); |
69 | } | ||
70 | static DEVICE_ATTR_RO(modalias); | ||
71 | |||
72 | static struct attribute *zorro_device_attrs[] = { | ||
73 | &dev_attr_id.attr, | ||
74 | &dev_attr_type.attr, | ||
75 | &dev_attr_serial.attr, | ||
76 | &dev_attr_slotaddr.attr, | ||
77 | &dev_attr_slotsize.attr, | ||
78 | &dev_attr_resource.attr, | ||
79 | &dev_attr_modalias.attr, | ||
80 | NULL | ||
81 | }; | ||
63 | 82 | ||
64 | static ssize_t zorro_read_config(struct file *filp, struct kobject *kobj, | 83 | static ssize_t zorro_read_config(struct file *filp, struct kobject *kobj, |
65 | struct bin_attribute *bin_attr, | 84 | struct bin_attribute *bin_attr, |
@@ -88,32 +107,17 @@ static struct bin_attribute zorro_config_attr = { | |||
88 | .read = zorro_read_config, | 107 | .read = zorro_read_config, |
89 | }; | 108 | }; |
90 | 109 | ||
91 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | 110 | static struct bin_attribute *zorro_device_bin_attrs[] = { |
92 | char *buf) | 111 | &zorro_config_attr, |
93 | { | 112 | NULL |
94 | struct zorro_dev *z = to_zorro_dev(dev); | 113 | }; |
95 | |||
96 | return sprintf(buf, ZORRO_DEVICE_MODALIAS_FMT "\n", z->id); | ||
97 | } | ||
98 | |||
99 | static DEVICE_ATTR(modalias, S_IRUGO, modalias_show, NULL); | ||
100 | 114 | ||
101 | int zorro_create_sysfs_dev_files(struct zorro_dev *z) | 115 | static const struct attribute_group zorro_device_attr_group = { |
102 | { | 116 | .attrs = zorro_device_attrs, |
103 | struct device *dev = &z->dev; | 117 | .bin_attrs = zorro_device_bin_attrs, |
104 | int error; | 118 | }; |
105 | |||
106 | /* current configuration's attributes */ | ||
107 | if ((error = device_create_file(dev, &dev_attr_id)) || | ||
108 | (error = device_create_file(dev, &dev_attr_type)) || | ||
109 | (error = device_create_file(dev, &dev_attr_serial)) || | ||
110 | (error = device_create_file(dev, &dev_attr_slotaddr)) || | ||
111 | (error = device_create_file(dev, &dev_attr_slotsize)) || | ||
112 | (error = device_create_file(dev, &dev_attr_resource)) || | ||
113 | (error = device_create_file(dev, &dev_attr_modalias)) || | ||
114 | (error = sysfs_create_bin_file(&dev->kobj, &zorro_config_attr))) | ||
115 | return error; | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | 119 | ||
120 | const struct attribute_group *zorro_device_attribute_groups[] = { | ||
121 | &zorro_device_attr_group, | ||
122 | NULL | ||
123 | }; | ||
diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c index d295d9878dff..cc1b1ac57d61 100644 --- a/drivers/zorro/zorro.c +++ b/drivers/zorro/zorro.c | |||
@@ -197,9 +197,6 @@ static int __init amiga_zorro_probe(struct platform_device *pdev) | |||
197 | put_device(&z->dev); | 197 | put_device(&z->dev); |
198 | continue; | 198 | continue; |
199 | } | 199 | } |
200 | error = zorro_create_sysfs_dev_files(z); | ||
201 | if (error) | ||
202 | dev_err(&z->dev, "Error creating sysfs files\n"); | ||
203 | } | 200 | } |
204 | 201 | ||
205 | /* Mark all available Zorro II memory */ | 202 | /* Mark all available Zorro II memory */ |
diff --git a/drivers/zorro/zorro.h b/drivers/zorro/zorro.h index 34119fb4e560..4f805c01cfbc 100644 --- a/drivers/zorro/zorro.h +++ b/drivers/zorro/zorro.h | |||
@@ -5,5 +5,4 @@ extern void zorro_name_device(struct zorro_dev *z); | |||
5 | static inline void zorro_name_device(struct zorro_dev *dev) { } | 5 | static inline void zorro_name_device(struct zorro_dev *dev) { } |
6 | #endif | 6 | #endif |
7 | 7 | ||
8 | extern int zorro_create_sysfs_dev_files(struct zorro_dev *z); | 8 | extern const struct attribute_group *zorro_device_attribute_groups[]; |
9 | |||
diff --git a/fs/char_dev.c b/fs/char_dev.c index 44a240c4bb65..fb8507f521b2 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c | |||
@@ -471,6 +471,85 @@ int cdev_add(struct cdev *p, dev_t dev, unsigned count) | |||
471 | return 0; | 471 | return 0; |
472 | } | 472 | } |
473 | 473 | ||
474 | /** | ||
475 | * cdev_set_parent() - set the parent kobject for a char device | ||
476 | * @p: the cdev structure | ||
477 | * @kobj: the kobject to take a reference to | ||
478 | * | ||
479 | * cdev_set_parent() sets a parent kobject which will be referenced | ||
480 | * appropriately so the parent is not freed before the cdev. This | ||
481 | * should be called before cdev_add. | ||
482 | */ | ||
483 | void cdev_set_parent(struct cdev *p, struct kobject *kobj) | ||
484 | { | ||
485 | WARN_ON(!kobj->state_initialized); | ||
486 | p->kobj.parent = kobj; | ||
487 | } | ||
488 | |||
489 | /** | ||
490 | * cdev_device_add() - add a char device and it's corresponding | ||
491 | * struct device, linkink | ||
492 | * @dev: the device structure | ||
493 | * @cdev: the cdev structure | ||
494 | * | ||
495 | * cdev_device_add() adds the char device represented by @cdev to the system, | ||
496 | * just as cdev_add does. It then adds @dev to the system using device_add | ||
497 | * The dev_t for the char device will be taken from the struct device which | ||
498 | * needs to be initialized first. This helper function correctly takes a | ||
499 | * reference to the parent device so the parent will not get released until | ||
500 | * all references to the cdev are released. | ||
501 | * | ||
502 | * This helper uses dev->devt for the device number. If it is not set | ||
503 | * it will not add the cdev and it will be equivalent to device_add. | ||
504 | * | ||
505 | * This function should be used whenever the struct cdev and the | ||
506 | * struct device are members of the same structure whose lifetime is | ||
507 | * managed by the struct device. | ||
508 | * | ||
509 | * NOTE: Callers must assume that userspace was able to open the cdev and | ||
510 | * can call cdev fops callbacks at any time, even if this function fails. | ||
511 | */ | ||
512 | int cdev_device_add(struct cdev *cdev, struct device *dev) | ||
513 | { | ||
514 | int rc = 0; | ||
515 | |||
516 | if (dev->devt) { | ||
517 | cdev_set_parent(cdev, &dev->kobj); | ||
518 | |||
519 | rc = cdev_add(cdev, dev->devt, 1); | ||
520 | if (rc) | ||
521 | return rc; | ||
522 | } | ||
523 | |||
524 | rc = device_add(dev); | ||
525 | if (rc) | ||
526 | cdev_del(cdev); | ||
527 | |||
528 | return rc; | ||
529 | } | ||
530 | |||
531 | /** | ||
532 | * cdev_device_del() - inverse of cdev_device_add | ||
533 | * @dev: the device structure | ||
534 | * @cdev: the cdev structure | ||
535 | * | ||
536 | * cdev_device_del() is a helper function to call cdev_del and device_del. | ||
537 | * It should be used whenever cdev_device_add is used. | ||
538 | * | ||
539 | * If dev->devt is not set it will not remove the cdev and will be equivalent | ||
540 | * to device_del. | ||
541 | * | ||
542 | * NOTE: This guarantees that associated sysfs callbacks are not running | ||
543 | * or runnable, however any cdevs already open will remain and their fops | ||
544 | * will still be callable even after this function returns. | ||
545 | */ | ||
546 | void cdev_device_del(struct cdev *cdev, struct device *dev) | ||
547 | { | ||
548 | device_del(dev); | ||
549 | if (dev->devt) | ||
550 | cdev_del(cdev); | ||
551 | } | ||
552 | |||
474 | static void cdev_unmap(dev_t dev, unsigned count) | 553 | static void cdev_unmap(dev_t dev, unsigned count) |
475 | { | 554 | { |
476 | kobj_unmap(cdev_map, dev, count); | 555 | kobj_unmap(cdev_map, dev, count); |
@@ -482,6 +561,10 @@ static void cdev_unmap(dev_t dev, unsigned count) | |||
482 | * | 561 | * |
483 | * cdev_del() removes @p from the system, possibly freeing the structure | 562 | * cdev_del() removes @p from the system, possibly freeing the structure |
484 | * itself. | 563 | * itself. |
564 | * | ||
565 | * NOTE: This guarantees that cdev device will no longer be able to be | ||
566 | * opened, however any cdevs already open will remain and their fops will | ||
567 | * still be callable even after cdev_del returns. | ||
485 | */ | 568 | */ |
486 | void cdev_del(struct cdev *p) | 569 | void cdev_del(struct cdev *p) |
487 | { | 570 | { |
@@ -570,5 +653,8 @@ EXPORT_SYMBOL(cdev_init); | |||
570 | EXPORT_SYMBOL(cdev_alloc); | 653 | EXPORT_SYMBOL(cdev_alloc); |
571 | EXPORT_SYMBOL(cdev_del); | 654 | EXPORT_SYMBOL(cdev_del); |
572 | EXPORT_SYMBOL(cdev_add); | 655 | EXPORT_SYMBOL(cdev_add); |
656 | EXPORT_SYMBOL(cdev_set_parent); | ||
657 | EXPORT_SYMBOL(cdev_device_add); | ||
658 | EXPORT_SYMBOL(cdev_device_del); | ||
573 | EXPORT_SYMBOL(__register_chrdev); | 659 | EXPORT_SYMBOL(__register_chrdev); |
574 | EXPORT_SYMBOL(__unregister_chrdev); | 660 | EXPORT_SYMBOL(__unregister_chrdev); |
diff --git a/include/linux/cdev.h b/include/linux/cdev.h index f8763615a5f2..408bc09ce497 100644 --- a/include/linux/cdev.h +++ b/include/linux/cdev.h | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/kobject.h> | 4 | #include <linux/kobject.h> |
5 | #include <linux/kdev_t.h> | 5 | #include <linux/kdev_t.h> |
6 | #include <linux/list.h> | 6 | #include <linux/list.h> |
7 | #include <linux/device.h> | ||
7 | 8 | ||
8 | struct file_operations; | 9 | struct file_operations; |
9 | struct inode; | 10 | struct inode; |
@@ -26,6 +27,10 @@ void cdev_put(struct cdev *p); | |||
26 | 27 | ||
27 | int cdev_add(struct cdev *, dev_t, unsigned); | 28 | int cdev_add(struct cdev *, dev_t, unsigned); |
28 | 29 | ||
30 | void cdev_set_parent(struct cdev *p, struct kobject *kobj); | ||
31 | int cdev_device_add(struct cdev *cdev, struct device *dev); | ||
32 | void cdev_device_del(struct cdev *cdev, struct device *dev); | ||
33 | |||
29 | void cdev_del(struct cdev *); | 34 | void cdev_del(struct cdev *); |
30 | 35 | ||
31 | void cd_forget(struct inode *); | 36 | void cd_forget(struct inode *); |
diff --git a/include/linux/fpga/altera-pr-ip-core.h b/include/linux/fpga/altera-pr-ip-core.h new file mode 100644 index 000000000000..3810a9033f49 --- /dev/null +++ b/include/linux/fpga/altera-pr-ip-core.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * Driver for Altera Partial Reconfiguration IP Core | ||
3 | * | ||
4 | * Copyright (C) 2016 Intel Corporation | ||
5 | * | ||
6 | * Based on socfpga-a10.c Copyright (C) 2015-2016 Altera Corporation | ||
7 | * by Alan Tull <atull@opensource.altera.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms and conditions of the GNU General Public License, | ||
11 | * version 2, as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | ||
21 | |||
22 | #ifndef _ALT_PR_IP_CORE_H | ||
23 | #define _ALT_PR_IP_CORE_H | ||
24 | #include <linux/io.h> | ||
25 | |||
26 | int alt_pr_register(struct device *dev, void __iomem *reg_base); | ||
27 | int alt_pr_unregister(struct device *dev); | ||
28 | |||
29 | #endif /* _ALT_PR_IP_CORE_H */ | ||
diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h index 57beb5d09bfc..b4ac24c4411d 100644 --- a/include/linux/fpga/fpga-mgr.h +++ b/include/linux/fpga/fpga-mgr.h | |||
@@ -70,17 +70,21 @@ enum fpga_mgr_states { | |||
70 | */ | 70 | */ |
71 | #define FPGA_MGR_PARTIAL_RECONFIG BIT(0) | 71 | #define FPGA_MGR_PARTIAL_RECONFIG BIT(0) |
72 | #define FPGA_MGR_EXTERNAL_CONFIG BIT(1) | 72 | #define FPGA_MGR_EXTERNAL_CONFIG BIT(1) |
73 | #define FPGA_MGR_ENCRYPTED_BITSTREAM BIT(2) | ||
73 | 74 | ||
74 | /** | 75 | /** |
75 | * struct fpga_image_info - information specific to a FPGA image | 76 | * struct fpga_image_info - information specific to a FPGA image |
76 | * @flags: boolean flags as defined above | 77 | * @flags: boolean flags as defined above |
77 | * @enable_timeout_us: maximum time to enable traffic through bridge (uSec) | 78 | * @enable_timeout_us: maximum time to enable traffic through bridge (uSec) |
78 | * @disable_timeout_us: maximum time to disable traffic through bridge (uSec) | 79 | * @disable_timeout_us: maximum time to disable traffic through bridge (uSec) |
80 | * @config_complete_timeout_us: maximum time for FPGA to switch to operating | ||
81 | * status in the write_complete op. | ||
79 | */ | 82 | */ |
80 | struct fpga_image_info { | 83 | struct fpga_image_info { |
81 | u32 flags; | 84 | u32 flags; |
82 | u32 enable_timeout_us; | 85 | u32 enable_timeout_us; |
83 | u32 disable_timeout_us; | 86 | u32 disable_timeout_us; |
87 | u32 config_complete_timeout_us; | ||
84 | }; | 88 | }; |
85 | 89 | ||
86 | /** | 90 | /** |
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 0c170a3f0d8b..e09fc8290c2f 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h | |||
@@ -491,6 +491,12 @@ struct vmbus_channel_rescind_offer { | |||
491 | u32 child_relid; | 491 | u32 child_relid; |
492 | } __packed; | 492 | } __packed; |
493 | 493 | ||
494 | static inline u32 | ||
495 | hv_ringbuffer_pending_size(const struct hv_ring_buffer_info *rbi) | ||
496 | { | ||
497 | return rbi->ring_buffer->pending_send_sz; | ||
498 | } | ||
499 | |||
494 | /* | 500 | /* |
495 | * Request Offer -- no parameters, SynIC message contains the partition ID | 501 | * Request Offer -- no parameters, SynIC message contains the partition ID |
496 | * Set Snoop -- no parameters, SynIC message contains the partition ID | 502 | * Set Snoop -- no parameters, SynIC message contains the partition ID |
@@ -524,10 +530,10 @@ struct vmbus_channel_open_channel { | |||
524 | u32 target_vp; | 530 | u32 target_vp; |
525 | 531 | ||
526 | /* | 532 | /* |
527 | * The upstream ring buffer begins at offset zero in the memory | 533 | * The upstream ring buffer begins at offset zero in the memory |
528 | * described by RingBufferGpadlHandle. The downstream ring buffer | 534 | * described by RingBufferGpadlHandle. The downstream ring buffer |
529 | * follows it at this offset (in pages). | 535 | * follows it at this offset (in pages). |
530 | */ | 536 | */ |
531 | u32 downstream_ringbuffer_pageoffset; | 537 | u32 downstream_ringbuffer_pageoffset; |
532 | 538 | ||
533 | /* User-specific data to be passed along to the server endpoint. */ | 539 | /* User-specific data to be passed along to the server endpoint. */ |
@@ -1013,7 +1019,7 @@ extern int vmbus_open(struct vmbus_channel *channel, | |||
1013 | u32 recv_ringbuffersize, | 1019 | u32 recv_ringbuffersize, |
1014 | void *userdata, | 1020 | void *userdata, |
1015 | u32 userdatalen, | 1021 | u32 userdatalen, |
1016 | void(*onchannel_callback)(void *context), | 1022 | void (*onchannel_callback)(void *context), |
1017 | void *context); | 1023 | void *context); |
1018 | 1024 | ||
1019 | extern void vmbus_close(struct vmbus_channel *channel); | 1025 | extern void vmbus_close(struct vmbus_channel *channel); |
@@ -1155,6 +1161,17 @@ static inline void *hv_get_drvdata(struct hv_device *dev) | |||
1155 | return dev_get_drvdata(&dev->device); | 1161 | return dev_get_drvdata(&dev->device); |
1156 | } | 1162 | } |
1157 | 1163 | ||
1164 | struct hv_ring_buffer_debug_info { | ||
1165 | u32 current_interrupt_mask; | ||
1166 | u32 current_read_index; | ||
1167 | u32 current_write_index; | ||
1168 | u32 bytes_avail_toread; | ||
1169 | u32 bytes_avail_towrite; | ||
1170 | }; | ||
1171 | |||
1172 | void hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, | ||
1173 | struct hv_ring_buffer_debug_info *debug_info); | ||
1174 | |||
1158 | /* Vmbus interface */ | 1175 | /* Vmbus interface */ |
1159 | #define vmbus_driver_register(driver) \ | 1176 | #define vmbus_driver_register(driver) \ |
1160 | __vmbus_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) | 1177 | __vmbus_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) |
@@ -1428,7 +1445,7 @@ struct hyperv_service_callback { | |||
1428 | char *log_msg; | 1445 | char *log_msg; |
1429 | uuid_le data; | 1446 | uuid_le data; |
1430 | struct vmbus_channel *channel; | 1447 | struct vmbus_channel *channel; |
1431 | void (*callback) (void *context); | 1448 | void (*callback)(void *context); |
1432 | }; | 1449 | }; |
1433 | 1450 | ||
1434 | #define MAX_SRV_VER 0x7ffffff | 1451 | #define MAX_SRV_VER 0x7ffffff |
@@ -1504,8 +1521,6 @@ static inline void hv_signal_on_read(struct vmbus_channel *channel) | |||
1504 | cached_write_sz = hv_get_cached_bytes_to_write(rbi); | 1521 | cached_write_sz = hv_get_cached_bytes_to_write(rbi); |
1505 | if (cached_write_sz < pending_sz) | 1522 | if (cached_write_sz < pending_sz) |
1506 | vmbus_setevent(channel); | 1523 | vmbus_setevent(channel); |
1507 | |||
1508 | return; | ||
1509 | } | 1524 | } |
1510 | 1525 | ||
1511 | /* | 1526 | /* |
diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h index 32c0e83d6239..3c85c81b0027 100644 --- a/include/linux/uio_driver.h +++ b/include/linux/uio_driver.h | |||
@@ -23,11 +23,13 @@ struct uio_map; | |||
23 | /** | 23 | /** |
24 | * struct uio_mem - description of a UIO memory region | 24 | * struct uio_mem - description of a UIO memory region |
25 | * @name: name of the memory region for identification | 25 | * @name: name of the memory region for identification |
26 | * @addr: address of the device's memory (phys_addr is used since | 26 | * @addr: address of the device's memory rounded to page |
27 | * addr can be logical, virtual, or physical & phys_addr_t | 27 | * size (phys_addr is used since addr can be |
28 | * should always be large enough to handle any of the | 28 | * logical, virtual, or physical & phys_addr_t |
29 | * address types) | 29 | * should always be large enough to handle any of |
30 | * @size: size of IO | 30 | * the address types) |
31 | * @offs: offset of device memory within the page | ||
32 | * @size: size of IO (multiple of page size) | ||
31 | * @memtype: type of memory addr points to | 33 | * @memtype: type of memory addr points to |
32 | * @internal_addr: ioremap-ped version of addr, for driver internal use | 34 | * @internal_addr: ioremap-ped version of addr, for driver internal use |
33 | * @map: for use by the UIO core only. | 35 | * @map: for use by the UIO core only. |
@@ -35,6 +37,7 @@ struct uio_map; | |||
35 | struct uio_mem { | 37 | struct uio_mem { |
36 | const char *name; | 38 | const char *name; |
37 | phys_addr_t addr; | 39 | phys_addr_t addr; |
40 | unsigned long offs; | ||
38 | resource_size_t size; | 41 | resource_size_t size; |
39 | int memtype; | 42 | int memtype; |
40 | void __iomem *internal_addr; | 43 | void __iomem *internal_addr; |
diff --git a/include/linux/vme.h b/include/linux/vme.h index ec5e8bf6118e..25874da3f2e1 100644 --- a/include/linux/vme.h +++ b/include/linux/vme.h | |||
@@ -92,7 +92,7 @@ extern struct bus_type vme_bus_type; | |||
92 | #define VME_SLOT_ALL -2 | 92 | #define VME_SLOT_ALL -2 |
93 | 93 | ||
94 | /** | 94 | /** |
95 | * Structure representing a VME device | 95 | * struct vme_dev - Structure representing a VME device |
96 | * @num: The device number | 96 | * @num: The device number |
97 | * @bridge: Pointer to the bridge device this device is on | 97 | * @bridge: Pointer to the bridge device this device is on |
98 | * @dev: Internal device structure | 98 | * @dev: Internal device structure |
@@ -107,6 +107,16 @@ struct vme_dev { | |||
107 | struct list_head bridge_list; | 107 | struct list_head bridge_list; |
108 | }; | 108 | }; |
109 | 109 | ||
110 | /** | ||
111 | * struct vme_driver - Structure representing a VME driver | ||
112 | * @name: Driver name, should be unique among VME drivers and usually the same | ||
113 | * as the module name. | ||
114 | * @match: Callback used to determine whether probe should be run. | ||
115 | * @probe: Callback for device binding, called when new device is detected. | ||
116 | * @remove: Callback, called on device removal. | ||
117 | * @driver: Underlying generic device driver structure. | ||
118 | * @devices: List of VME devices (struct vme_dev) associated with this driver. | ||
119 | */ | ||
110 | struct vme_driver { | 120 | struct vme_driver { |
111 | const char *name; | 121 | const char *name; |
112 | int (*match)(struct vme_dev *); | 122 | int (*match)(struct vme_dev *); |
diff --git a/include/misc/charlcd.h b/include/misc/charlcd.h new file mode 100644 index 000000000000..23f61850f363 --- /dev/null +++ b/include/misc/charlcd.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * Character LCD driver for Linux | ||
3 | * | ||
4 | * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu> | ||
5 | * Copyright (C) 2016-2017 Glider bvba | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | struct charlcd { | ||
14 | const struct charlcd_ops *ops; | ||
15 | const unsigned char *char_conv; /* Optional */ | ||
16 | |||
17 | int ifwidth; /* 4-bit or 8-bit (default) */ | ||
18 | int height; | ||
19 | int width; | ||
20 | int bwidth; /* Default set by charlcd_alloc() */ | ||
21 | int hwidth; /* Default set by charlcd_alloc() */ | ||
22 | |||
23 | void *drvdata; /* Set by charlcd_alloc() */ | ||
24 | }; | ||
25 | |||
26 | struct charlcd_ops { | ||
27 | /* Required */ | ||
28 | void (*write_cmd)(struct charlcd *lcd, int cmd); | ||
29 | void (*write_data)(struct charlcd *lcd, int data); | ||
30 | |||
31 | /* Optional */ | ||
32 | void (*write_cmd_raw4)(struct charlcd *lcd, int cmd); /* 4-bit only */ | ||
33 | void (*clear_fast)(struct charlcd *lcd); | ||
34 | void (*backlight)(struct charlcd *lcd, int on); | ||
35 | }; | ||
36 | |||
37 | struct charlcd *charlcd_alloc(unsigned int drvdata_size); | ||
38 | |||
39 | int charlcd_register(struct charlcd *lcd); | ||
40 | int charlcd_unregister(struct charlcd *lcd); | ||
41 | |||
42 | void charlcd_poke(struct charlcd *lcd); | ||
diff --git a/include/uapi/linux/aspeed-lpc-ctrl.h b/include/uapi/linux/aspeed-lpc-ctrl.h new file mode 100644 index 000000000000..c328c976c684 --- /dev/null +++ b/include/uapi/linux/aspeed-lpc-ctrl.h | |||
@@ -0,0 +1,61 @@ | |||
1 | /* | ||
2 | * Copyright 2017 IBM Corp. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | |||
10 | #ifndef _UAPI_LINUX_ASPEED_LPC_CTRL_H | ||
11 | #define _UAPI_LINUX_ASPEED_LPC_CTRL_H | ||
12 | |||
13 | #include <linux/ioctl.h> | ||
14 | #include <linux/types.h> | ||
15 | |||
16 | /* Window types */ | ||
17 | #define ASPEED_LPC_CTRL_WINDOW_FLASH 1 | ||
18 | #define ASPEED_LPC_CTRL_WINDOW_MEMORY 2 | ||
19 | |||
20 | /* | ||
21 | * This driver provides a window for the host to access a BMC resource | ||
22 | * across the BMC <-> Host LPC bus. | ||
23 | * | ||
24 | * window_type: The BMC resource that the host will access through the | ||
25 | * window. BMC flash and BMC RAM. | ||
26 | * | ||
27 | * window_id: For each window type there may be multiple windows, | ||
28 | * these are referenced by ID. | ||
29 | * | ||
30 | * flags: Reserved for future use, this field is expected to be | ||
31 | * zeroed. | ||
32 | * | ||
33 | * addr: Address on the host LPC bus that the specified window should | ||
34 | * be mapped. This address must be power of two aligned. | ||
35 | * | ||
36 | * offset: Offset into the BMC window that should be mapped to the | ||
37 | * host (at addr). This must be a multiple of size. | ||
38 | * | ||
39 | * size: The size of the mapping. The smallest possible size is 64K. | ||
40 | * This must be power of two aligned. | ||
41 | * | ||
42 | */ | ||
43 | |||
44 | struct aspeed_lpc_ctrl_mapping { | ||
45 | __u8 window_type; | ||
46 | __u8 window_id; | ||
47 | __u16 flags; | ||
48 | __u32 addr; | ||
49 | __u32 offset; | ||
50 | __u32 size; | ||
51 | }; | ||
52 | |||
53 | #define __ASPEED_LPC_CTRL_IOCTL_MAGIC 0xb2 | ||
54 | |||
55 | #define ASPEED_LPC_CTRL_IOCTL_GET_SIZE _IOWR(__ASPEED_LPC_CTRL_IOCTL_MAGIC, \ | ||
56 | 0x00, struct aspeed_lpc_ctrl_mapping) | ||
57 | |||
58 | #define ASPEED_LPC_CTRL_IOCTL_MAP _IOW(__ASPEED_LPC_CTRL_IOCTL_MAGIC, \ | ||
59 | 0x01, struct aspeed_lpc_ctrl_mapping) | ||
60 | |||
61 | #endif /* _UAPI_LINUX_ASPEED_LPC_CTRL_H */ | ||
diff --git a/include/uapi/linux/pps.h b/include/uapi/linux/pps.h index a9bb1d93451a..c1cb3825a8bc 100644 --- a/include/uapi/linux/pps.h +++ b/include/uapi/linux/pps.h | |||
@@ -55,6 +55,12 @@ struct pps_ktime { | |||
55 | __s32 nsec; | 55 | __s32 nsec; |
56 | __u32 flags; | 56 | __u32 flags; |
57 | }; | 57 | }; |
58 | |||
59 | struct pps_ktime_compat { | ||
60 | __s64 sec; | ||
61 | __s32 nsec; | ||
62 | __u32 flags; | ||
63 | } __attribute__((packed, aligned(4))); | ||
58 | #define PPS_TIME_INVALID (1<<0) /* used to specify timeout==NULL */ | 64 | #define PPS_TIME_INVALID (1<<0) /* used to specify timeout==NULL */ |
59 | 65 | ||
60 | struct pps_kinfo { | 66 | struct pps_kinfo { |
@@ -65,6 +71,14 @@ struct pps_kinfo { | |||
65 | int current_mode; /* current mode bits */ | 71 | int current_mode; /* current mode bits */ |
66 | }; | 72 | }; |
67 | 73 | ||
74 | struct pps_kinfo_compat { | ||
75 | __u32 assert_sequence; /* seq. num. of assert event */ | ||
76 | __u32 clear_sequence; /* seq. num. of clear event */ | ||
77 | struct pps_ktime_compat assert_tu; /* time of assert event */ | ||
78 | struct pps_ktime_compat clear_tu; /* time of clear event */ | ||
79 | int current_mode; /* current mode bits */ | ||
80 | }; | ||
81 | |||
68 | struct pps_kparams { | 82 | struct pps_kparams { |
69 | int api_version; /* API version # */ | 83 | int api_version; /* API version # */ |
70 | int mode; /* mode bits */ | 84 | int mode; /* mode bits */ |
@@ -114,6 +128,11 @@ struct pps_fdata { | |||
114 | struct pps_ktime timeout; | 128 | struct pps_ktime timeout; |
115 | }; | 129 | }; |
116 | 130 | ||
131 | struct pps_fdata_compat { | ||
132 | struct pps_kinfo_compat info; | ||
133 | struct pps_ktime_compat timeout; | ||
134 | }; | ||
135 | |||
117 | struct pps_bind_args { | 136 | struct pps_bind_args { |
118 | int tsformat; /* format of time stamps */ | 137 | int tsformat; /* format of time stamps */ |
119 | int edge; /* selected event type */ | 138 | int edge; /* selected event type */ |
diff --git a/samples/mei/TODO b/samples/mei/TODO deleted file mode 100644 index 6b3625d3058c..000000000000 --- a/samples/mei/TODO +++ /dev/null | |||
@@ -1,2 +0,0 @@ | |||
1 | TODO: | ||
2 | - Cleanup and split the timer function | ||
diff --git a/scripts/ver_linux b/scripts/ver_linux index 430b201f3e25..b51de8a7e2a3 100755 --- a/scripts/ver_linux +++ b/scripts/ver_linux | |||
@@ -1,4 +1,4 @@ | |||
1 | #!/bin/awk -f | 1 | #!/usr/bin/awk -f |
2 | # Before running this script please ensure that your PATH is | 2 | # Before running this script please ensure that your PATH is |
3 | # typical as you use for compilation/installation. I use | 3 | # typical as you use for compilation/installation. I use |
4 | # /bin /sbin /usr/bin /usr/sbin /usr/local/bin, but it may | 4 | # /bin /sbin /usr/bin /usr/sbin /usr/local/bin, but it may |