diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt index d1061469f63d..9a1175b46f49 100644 --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt @@ -5,6 +5,9 @@ Required properties: can be "at91sam9260", "at91sam9g45" or "at91sam9x5" - reg: Should contain ADC registers location and length - interrupts: Should contain the IRQ line for the ADC + - clock-names: tuple listing input clock names. + Required elements: "adc_clk", "adc_op_clk". + - clocks: phandles to input clocks. - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this device - atmel,adc-startup-time: Startup Time of the ADC in microseconds as @@ -44,6 +47,8 @@ adc0: adc@fffb0000 { compatible = "atmel,at91sam9260-adc"; reg = <0xfffb0000 0x100>; interrupts = <20 4>; + clocks = <&adc_clk>, <&adc_op_clk>; + clock-names = "adc_clk", "adc_op_clk"; atmel,adc-channel-base = <0x30>; atmel,adc-channels-used = <0xff>; atmel,adc-drdy-mask = <0x10000>; diff --git a/Documentation/devicetree/bindings/graph.txt b/Documentation/devicetree/bindings/graph.txt new file mode 100644 index 000000000000..1a69c078adf2 --- /dev/null +++ b/Documentation/devicetree/bindings/graph.txt @@ -0,0 +1,129 @@ +Common bindings for device graphs + +General concept +--------------- + +The hierarchical organisation of the device tree is well suited to describe +control flow to devices, but there can be more complex connections between +devices that work together to form a logical compound device, following an +arbitrarily complex graph. +There already is a simple directed graph between devices tree nodes using +phandle properties pointing to other nodes to describe connections that +can not be inferred from device tree parent-child relationships. The device +tree graph bindings described herein abstract more complex devices that can +have multiple specifiable ports, each of which can be linked to one or more +ports of other devices. + +These common bindings do not contain any information about the direction or +type of the connections, they just map their existence. Specific properties +may be described by specialized bindings depending on the type of connection. + +To see how this binding applies to video pipelines, for example, see +Documentation/device-tree/bindings/media/video-interfaces.txt. +Here the ports describe data interfaces, and the links between them are +the connecting data buses. A single port with multiple connections can +correspond to multiple devices being connected to the same physical bus. + +Organisation of ports and endpoints +----------------------------------- + +Ports are described by child 'port' nodes contained in the device node. +Each port node contains an 'endpoint' subnode for each remote device port +connected to this port. If a single port is connected to more than one +remote device, an 'endpoint' child node must be provided for each link. +If more than one port is present in a device node or there is more than one +endpoint at a port, or a port node needs to be associated with a selected +hardware interface, a common scheme using '#address-cells', '#size-cells' +and 'reg' properties is used number the nodes. + +device { + ... + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + endpoint@0 { + reg = <0>; + ... + }; + endpoint@1 { + reg = <1>; + ... + }; + }; + + port@1 { + reg = <1>; + + endpoint { ... }; + }; +}; + +All 'port' nodes can be grouped under an optional 'ports' node, which +allows to specify #address-cells, #size-cells properties for the 'port' +nodes independently from any other child device nodes a device might +have. + +device { + ... + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + ... + endpoint@0 { ... }; + endpoint@1 { ... }; + }; + + port@1 { ... }; + }; +}; + +Links between endpoints +----------------------- + +Each endpoint should contain a 'remote-endpoint' phandle property that points +to the corresponding endpoint in the port of the remote device. In turn, the +remote endpoint should contain a 'remote-endpoint' property. If it has one, +it must not point to another than the local endpoint. Two endpoints with their +'remote-endpoint' phandles pointing at each other form a link between the +containing ports. + +device-1 { + port { + device_1_output: endpoint { + remote-endpoint = <&device_2_input>; + }; + }; +}; + +device-2 { + port { + device_2_input: endpoint { + remote-endpoint = <&device_1_output>; + }; + }; +}; + + +Required properties +------------------- + +If there is more than one 'port' or more than one 'endpoint' node or 'reg' +property is present in port and/or endpoint nodes the following properties +are required in a relevant parent node: + + - #address-cells : number of cells required to define port/endpoint + identifier, should be 1. + - #size-cells : should be zero. + +Optional endpoint properties +---------------------------- + +- remote-endpoint: phandle to an 'endpoint' subnode of a remote device node. + diff --git a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt new file mode 100644 index 000000000000..dcebff1928e1 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt @@ -0,0 +1,22 @@ +Freescale vf610 Analog to Digital Converter bindings + +The devicetree bindings are for the new ADC driver written for +vf610/i.MX6slx and upward SoCs from Freescale. + +Required properties: +- compatible: Should contain "fsl,vf610-adc" +- reg: Offset and length of the register set for the device +- interrupts: Should contain the interrupt for the device +- clocks: The clock is needed by the ADC controller, ADC clock source is ipg clock. +- clock-names: Must contain "adc", matching entry in the clocks property. +- vref-supply: The regulator supply ADC refrence voltage. + +Example: +adc0: adc@4003b000 { + compatible = "fsl,vf610-adc"; + reg = <0x4003b000 0x1000>; + interrupts = <0 53 0x04>; + clocks = <&clks VF610_CLK_ADC0>; + clock-names = "adc"; + vref-supply = <®_vcc_3v3_mcu>; +}; diff --git a/Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt b/Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt new file mode 100644 index 000000000000..d9ee909d2b78 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt @@ -0,0 +1,113 @@ +Xilinx XADC device driver + +This binding document describes the bindings for both of them since the +bindings are very similar. The Xilinx XADC is a ADC that can be found in the +series 7 FPGAs from Xilinx. The XADC has a DRP interface for communication. +Currently two different frontends for the DRP interface exist. One that is only +available on the ZYNQ family as a hardmacro in the SoC portion of the ZYNQ. The +other one is available on all series 7 platforms and is a softmacro with a AXI +interface. This binding document describes the bindings for both of them since +the bindings are very similar. + +Required properties: + - compatible: Should be one of + * "xlnx,zynq-xadc-1.00.a": When using the ZYNQ device + configuration interface to interface to the XADC hardmacro. + * "xlnx,axi-xadc-1.00.a": When using the axi-xadc pcore to + interface to the XADC hardmacro. + - reg: Address and length of the register set for the device + - interrupts: Interrupt for the XADC control interface. + - clocks: When using the ZYNQ this must be the ZYNQ PCAP clock, + when using the AXI-XADC pcore this must be the clock that provides the + clock to the AXI bus interface of the core. + +Optional properties: + - interrupt-parent: phandle to the parent interrupt controller + - xlnx,external-mux: + * "none": No external multiplexer is used, this is the default + if the property is omitted. + * "single": External multiplexer mode is used with one + multiplexer. + * "dual": External multiplexer mode is used with two + multiplexers for simultaneous sampling. + - xlnx,external-mux-channel: Configures which pair of pins is used to + sample data in external mux mode. + Valid values for single external multiplexer mode are: + 0: VP/VN + 1: VAUXP[0]/VAUXN[0] + 2: VAUXP[1]/VAUXN[1] + ... + 16: VAUXP[15]/VAUXN[15] + Valid values for dual external multiplexer mode are: + 1: VAUXP[0]/VAUXN[0] - VAUXP[8]/VAUXN[8] + 2: VAUXP[1]/VAUXN[1] - VAUXP[9]/VAUXN[9] + ... + 8: VAUXP[7]/VAUXN[7] - VAUXP[15]/VAUXN[15] + + This property needs to be present if the device is configured for + external multiplexer mode (either single or dual). If the device is + not using external multiplexer mode the property is ignored. + - xnlx,channels: List of external channels that are connected to the ADC + Required properties: + * #address-cells: Should be 1. + * #size-cells: Should be 0. + + The child nodes of this node represent the external channels which are + connected to the ADC. If the property is no present no external + channels will be assumed to be connected. + + Each child node represents one channel and has the following + properties: + Required properties: + * reg: Pair of pins the the channel is connected to. + 0: VP/VN + 1: VAUXP[0]/VAUXN[0] + 2: VAUXP[1]/VAUXN[1] + ... + 16: VAUXP[15]/VAUXN[15] + Note each channel number should only be used at most + once. + Optional properties: + * xlnx,bipolar: If set the channel is used in bipolar + mode. + + +Examples: + xadc@f8007100 { + compatible = "xlnx,zynq-xadc-1.00.a"; + reg = <0xf8007100 0x20>; + interrupts = <0 7 4>; + interrupt-parent = <&gic>; + clocks = <&pcap_clk>; + + xlnx,channels { + #address-cells = <1>; + #size-cells = <0>; + channel@0 { + reg = <0>; + }; + channel@1 { + reg = <1>; + }; + channel@8 { + reg = <8>; + }; + }; + }; + + xadc@43200000 { + compatible = "xlnx,axi-xadc-1.00.a"; + reg = <0x43200000 0x1000>; + interrupts = <0 53 4>; + interrupt-parent = <&gic>; + clocks = <&fpga1_clk>; + + xlnx,channels { + #address-cells = <1>; + #size-cells = <0>; + channel@0 { + reg = <0>; + xlnx,bipolar; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt index b876d4925a57..3be5ce7a9654 100644 --- a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt +++ b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt @@ -1,3 +1,22 @@ +Freescale i.MX DRM master device +================================ + +The freescale i.MX DRM master device is a virtual device needed to list all +IPU or other display interface nodes that comprise the graphics subsystem. + +Required properties: +- compatible: Should be "fsl,imx-display-subsystem" +- ports: Should contain a list of phandles pointing to display interface ports + of IPU devices + +example: + +display-subsystem { + compatible = "fsl,display-subsystem"; + ports = <&ipu_di0>; +}; + + Freescale i.MX IPUv3 ==================== @@ -7,18 +26,31 @@ Required properties: datasheet - interrupts: Should contain sync interrupt and error interrupt, in this order. -- #crtc-cells: 1, See below - resets: phandle pointing to the system reset controller and reset line index, see reset/fsl,imx-src.txt for details +Optional properties: +- port@[0-3]: Port nodes with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. + Ports 0 and 1 should correspond to CSI0 and CSI1, + ports 2 and 3 should correspond to DI0 and DI1, respectively. example: ipu: ipu@18000000 { - #crtc-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; compatible = "fsl,imx53-ipu"; reg = <0x18000000 0x080000000>; interrupts = <11 10>; resets = <&src 2>; + + ipu_di0: port@2 { + reg = <2>; + + ipu_di0_disp0: endpoint { + remote-endpoint = <&display_in>; + }; + }; }; Parallel display support @@ -26,19 +58,25 @@ Parallel display support Required properties: - compatible: Should be "fsl,imx-parallel-display" -- crtc: the crtc this display is connected to, see below Optional properties: - interface_pix_fmt: How this display is connected to the - crtc. Currently supported types: "rgb24", "rgb565", "bgr666" + display interface. Currently supported types: "rgb24", "rgb565", "bgr666" - edid: verbatim EDID data block describing attached display. - ddc: phandle describing the i2c bus handling the display data channel +- port: A port node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. example: display@di0 { compatible = "fsl,imx-parallel-display"; edid = [edid-data]; - crtc = <&ipu 0>; interface-pix-fmt = "rgb24"; + + port { + display_in: endpoint { + remote-endpoint = <&ipu_di0_disp0>; + }; + }; }; diff --git a/Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt b/Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt new file mode 100644 index 000000000000..1b756cf9afb0 --- /dev/null +++ b/Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt @@ -0,0 +1,58 @@ +Device-Tree bindings for HDMI Transmitter + +HDMI Transmitter +================ + +The HDMI Transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP +with accompanying PHY IP. + +Required properties: + - #address-cells : should be <1> + - #size-cells : should be <0> + - compatible : should be "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi". + - gpr : should be <&gpr>. + The phandle points to the iomuxc-gpr region containing the HDMI + multiplexer control register. + - clocks, clock-names : phandles to the HDMI iahb and isrf clocks, as described + in Documentation/devicetree/bindings/clock/clock-bindings.txt and + Documentation/devicetree/bindings/clock/imx6q-clock.txt. + - port@[0-4]: Up to four port nodes with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt, + corresponding to the four inputs to the HDMI multiplexer. + +Optional properties: + - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing + +example: + + gpr: iomuxc-gpr@020e0000 { + /* ... */ + }; + + hdmi: hdmi@0120000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx6q-hdmi"; + reg = <0x00120000 0x9000>; + interrupts = <0 115 0x04>; + gpr = <&gpr>; + clocks = <&clks 123>, <&clks 124>; + clock-names = "iahb", "isfr"; + ddc-i2c-bus = <&i2c2>; + + port@0 { + reg = <0>; + + hdmi_mux_0: endpoint { + remote-endpoint = <&ipu1_di0_hdmi>; + }; + }; + + port@1 { + reg = <1>; + + hdmi_mux_1: endpoint { + remote-endpoint = <&ipu1_di1_hdmi>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt b/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt index ed9377811ee2..578a1fca366e 100644 --- a/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt +++ b/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt @@ -50,12 +50,14 @@ have a look at Documentation/devicetree/bindings/video/display-timing.txt. Required properties: - reg : should be <0> or <1> - - crtcs : a list of phandles with index pointing to the IPU display interfaces - that can be used as video source for this channel. - fsl,data-mapping : should be "spwg" or "jeida" This describes how the color bits are laid out in the serialized LVDS signal. - fsl,data-width : should be <18> or <24> + - port: A port node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. + On i.MX6, there should be four ports (port@[0-3]) that correspond + to the four LVDS multiplexer inputs. example: @@ -77,23 +79,33 @@ ldb: ldb@53fa8008 { lvds-channel@0 { reg = <0>; - crtcs = <&ipu 0>; fsl,data-mapping = "spwg"; fsl,data-width = <24>; display-timings { /* ... */ }; + + port { + lvds0_in: endpoint { + remote-endpoint = <&ipu_di0_lvds0>; + }; + }; }; lvds-channel@1 { reg = <1>; - crtcs = <&ipu 1>; fsl,data-mapping = "spwg"; fsl,data-width = <24>; display-timings { /* ... */ }; + + port { + lvds1_in: endpoint { + remote-endpoint = <&ipu_di1_lvds1>; + }; + }; }; }; diff --git a/MAINTAINERS b/MAINTAINERS index 4a2ea1a168b2..48a88402c25d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8394,6 +8394,12 @@ M: Teddy Wang S: Odd Fixes F: drivers/staging/sm7xxfb/ +STAGING - SLICOSS +M: Lior Dotan +M: Christopher Harrer +S: Odd Fixes +F: drivers/staging/slicoss/ + STAGING - SOFTLOGIC 6x10 MPEG CODEC M: Ismael Luceno S: Supported @@ -9079,6 +9085,13 @@ F: drivers/cdrom/cdrom.c F: include/linux/cdrom.h F: include/uapi/linux/cdrom.h +UNISYS S-PAR DRIVERS +M: Benjamin Romer +M: David Kershner +L: sparmaintainer@unisys.com (Unisys internal) +S: Supported +F: drivers/staging/unisys/ + UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER M: Vinayak Holikatti M: Santosh Y diff --git a/arch/arm/boot/dts/imx51-apf51dev.dts b/arch/arm/boot/dts/imx51-apf51dev.dts index 5a7f552786a1..d3f98141462c 100644 --- a/arch/arm/boot/dts/imx51-apf51dev.dts +++ b/arch/arm/boot/dts/imx51-apf51dev.dts @@ -18,7 +18,6 @@ display@di1 { compatible = "fsl,imx-parallel-display"; - crtcs = <&ipu 0>; interface-pix-fmt = "bgr666"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ipu_disp1_1>; @@ -41,6 +40,12 @@ pixelclk-active = <0>; }; }; + + port { + display_in: endpoint { + remote-endpoint = <&ipu_di0_disp0>; + }; + }; }; gpio-keys { @@ -122,3 +127,7 @@ }; }; }; + +&ipu_di0_disp0 { + remote-endpoint = <&display_in>; +}; diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts index be1407cf5abd..671927145632 100644 --- a/arch/arm/boot/dts/imx51-babbage.dts +++ b/arch/arm/boot/dts/imx51-babbage.dts @@ -21,9 +21,8 @@ reg = <0x90000000 0x20000000>; }; - display@di0 { + display0: display@di0 { compatible = "fsl,imx-parallel-display"; - crtcs = <&ipu 0>; interface-pix-fmt = "rgb24"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ipu_disp1_1>; @@ -41,11 +40,16 @@ vsync-len = <10>; }; }; + + port { + display0_in: endpoint { + remote-endpoint = <&ipu_di0_disp0>; + }; + }; }; - display@di1 { + display1: display@di1 { compatible = "fsl,imx-parallel-display"; - crtcs = <&ipu 1>; interface-pix-fmt = "rgb565"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ipu_disp2_1>; @@ -68,6 +72,12 @@ pixelclk-active = <0>; }; }; + + port { + display1_in: endpoint { + remote-endpoint = <&ipu_di1_disp1>; + }; + }; }; gpio-keys { @@ -258,6 +268,14 @@ }; }; +&ipu_di0_disp0 { + remote-endpoint = <&display0_in>; +}; + +&ipu_di1_disp1 { + remote-endpoint = <&display1_in>; +}; + &ssi2 { fsl,mode = "i2s-slave"; status = "okay"; diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index 4bcdd3ad15e5..28c96aada80b 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -79,6 +79,11 @@ }; }; + display-subsystem { + compatible = "fsl,imx-display-subsystem"; + ports = <&ipu_di0>, <&ipu_di1>; + }; + soc { #address-cells = <1>; #size-cells = <1>; @@ -92,13 +97,28 @@ }; ipu: ipu@40000000 { - #crtc-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; compatible = "fsl,imx51-ipu"; reg = <0x40000000 0x20000000>; interrupts = <11 10>; clocks = <&clks 59>, <&clks 110>, <&clks 61>; clock-names = "bus", "di0", "di1"; resets = <&src 2>; + + ipu_di0: port@2 { + reg = <2>; + + ipu_di0_disp0: endpoint { + }; + }; + + ipu_di1: port@3 { + reg = <3>; + + ipu_di1_disp1: endpoint { + }; + }; }; aips@70000000 { /* AIPS1 */ diff --git a/arch/arm/boot/dts/imx53-m53evk.dts b/arch/arm/boot/dts/imx53-m53evk.dts index 7d304d02ed38..0298adc73bb7 100644 --- a/arch/arm/boot/dts/imx53-m53evk.dts +++ b/arch/arm/boot/dts/imx53-m53evk.dts @@ -21,9 +21,8 @@ }; soc { - display@di1 { + display1: display@di1 { compatible = "fsl,imx-parallel-display"; - crtcs = <&ipu 1>; interface-pix-fmt = "bgr666"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ipu_disp2_1>; @@ -44,6 +43,12 @@ }; }; }; + + port { + display1_in: endpoint { + remote-endpoint = <&ipu_di1_disp1>; + }; + }; }; backlight { @@ -221,6 +226,10 @@ }; }; +&ipu_di1_disp1 { + remote-endpoint = <&display1_in>; +}; + &nfc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_nand_1>; diff --git a/arch/arm/boot/dts/imx53-mba53.dts b/arch/arm/boot/dts/imx53-mba53.dts index a63090267941..a5b55c603591 100644 --- a/arch/arm/boot/dts/imx53-mba53.dts +++ b/arch/arm/boot/dts/imx53-mba53.dts @@ -38,9 +38,14 @@ compatible = "fsl,imx-parallel-display"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_disp1_1>; - crtcs = <&ipu 1>; interface-pix-fmt = "rgb24"; status = "disabled"; + + port { + display1_in: endpoint { + remote-endpoint = <&ipu_di1_disp1>; + }; + }; }; reg_3p2v: 3p2v { @@ -141,6 +146,10 @@ }; }; +&ipu_di1_disp1 { + remote-endpoint = <&display1_in>; +}; + &cspi { status = "okay"; }; @@ -228,7 +237,7 @@ &tve { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_vga_sync_1>; - ddc = <&i2c3>; + i2c-ddc-bus = <&i2c3>; fsl,tve-mode = "vga"; fsl,hsync-pin = <4>; fsl,vsync-pin = <6>; diff --git a/arch/arm/boot/dts/imx53-qsb.dts b/arch/arm/boot/dts/imx53-qsb.dts index 91a5935a4aac..8b254289344f 100644 --- a/arch/arm/boot/dts/imx53-qsb.dts +++ b/arch/arm/boot/dts/imx53-qsb.dts @@ -21,9 +21,8 @@ reg = <0x70000000 0x40000000>; }; - display@di0 { + display0: display@di0 { compatible = "fsl,imx-parallel-display"; - crtcs = <&ipu 0>; interface-pix-fmt = "rgb565"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ipu_disp0_1>; @@ -46,6 +45,12 @@ pixelclk-active = <0>; }; }; + + port { + display0_in: endpoint { + remote-endpoint = <&ipu_di0_disp0>; + }; + }; }; gpio-keys { @@ -126,6 +131,10 @@ status = "okay"; }; +&ipu_di0_disp0 { + remote-endpoint = <&display0_in>; +}; + &ssi2 { fsl,mode = "i2s-slave"; status = "okay"; diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index 4307e80b2d2e..04d3127edfe1 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -45,6 +45,11 @@ }; }; + display-subsystem { + compatible = "fsl,imx-display-subsystem"; + ports = <&ipu_di0>, <&ipu_di1>; + }; + tzic: tz-interrupt-controller@0fffc000 { compatible = "fsl,imx53-tzic", "fsl,tzic"; interrupt-controller; @@ -85,13 +90,49 @@ ranges; ipu: ipu@18000000 { - #crtc-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; compatible = "fsl,imx53-ipu"; reg = <0x18000000 0x080000000>; interrupts = <11 10>; clocks = <&clks 59>, <&clks 110>, <&clks 61>; clock-names = "bus", "di0", "di1"; resets = <&src 2>; + + ipu_di0: port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + ipu_di0_disp0: endpoint@0 { + reg = <0>; + }; + + ipu_di0_lvds0: endpoint@1 { + reg = <1>; + remote-endpoint = <&lvds0_in>; + }; + }; + + ipu_di1: port@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + ipu_di1_disp1: endpoint@0 { + reg = <0>; + }; + + ipu_di1_lvds1: endpoint@1 { + reg = <1>; + remote-endpoint = <&lvds1_in>; + }; + + ipu_di1_tve: endpoint@2 { + reg = <2>; + remote-endpoint = <&tve_in>; + }; + }; }; aips@50000000 { /* AIPS1 */ @@ -838,14 +879,24 @@ lvds-channel@0 { reg = <0>; - crtcs = <&ipu 0>; status = "disabled"; + + port { + lvds0_in: endpoint { + remote-endpoint = <&ipu_di0_lvds0>; + }; + }; }; lvds-channel@1 { reg = <1>; - crtcs = <&ipu 1>; status = "disabled"; + + port { + lvds1_in: endpoint { + remote-endpoint = <&ipu_di0_lvds0>; + }; + }; }; }; @@ -1103,8 +1154,13 @@ interrupts = <92>; clocks = <&clks 69>, <&clks 116>; clock-names = "tve", "di_sel"; - crtcs = <&ipu 1>; status = "disabled"; + + port { + tve_in: endpoint { + remote-endpoint = <&ipu_di1_tve>; + }; + }; }; vpu: vpu@63ff4000 { diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi index 9e8ae118fdd4..25bbdd6f214b 100644 --- a/arch/arm/boot/dts/imx6dl.dtsi +++ b/arch/arm/boot/dts/imx6dl.dtsi @@ -70,6 +70,15 @@ }; }; }; + + display-subsystem { + compatible = "fsl,imx-display-subsystem"; + ports = <&ipu1_di0>, <&ipu1_di1>; + }; +}; + +&hdmi { + compatible = "fsl,imx6dl-hdmi"; }; &ldb { @@ -79,12 +88,4 @@ clock-names = "di0_pll", "di1_pll", "di0_sel", "di1_sel", "di0", "di1"; - - lvds-channel@0 { - crtcs = <&ipu1 0>, <&ipu1 1>; - }; - - lvds-channel@1 { - crtcs = <&ipu1 0>, <&ipu1 1>; - }; }; diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index f024ef28b34b..2a8d9de666c9 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -132,13 +132,84 @@ }; ipu2: ipu@02800000 { - #crtc-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; compatible = "fsl,imx6q-ipu"; reg = <0x02800000 0x400000>; interrupts = <0 8 0x4 0 7 0x4>; clocks = <&clks 133>, <&clks 134>, <&clks 137>; clock-names = "bus", "di0", "di1"; resets = <&src 4>; + + ipu2_di0: port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + ipu2_di0_disp0: endpoint@0 { + }; + + ipu2_di0_hdmi: endpoint@1 { + remote-endpoint = <&hdmi_mux_2>; + }; + + ipu2_di0_mipi: endpoint@2 { + }; + + ipu2_di0_lvds0: endpoint@3 { + remote-endpoint = <&lvds0_mux_2>; + }; + + ipu2_di0_lvds1: endpoint@4 { + remote-endpoint = <&lvds1_mux_2>; + }; + }; + + ipu2_di1: port@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + ipu2_di1_hdmi: endpoint@1 { + remote-endpoint = <&hdmi_mux_3>; + }; + + ipu2_di1_mipi: endpoint@2 { + }; + + ipu2_di1_lvds0: endpoint@3 { + remote-endpoint = <&lvds0_mux_3>; + }; + + ipu2_di1_lvds1: endpoint@4 { + remote-endpoint = <&lvds1_mux_3>; + }; + }; + }; + }; + + display-subsystem { + compatible = "fsl,imx-display-subsystem"; + ports = <&ipu1_di0>, <&ipu1_di1>, <&ipu2_di0>, <&ipu2_di1>; + }; +}; + +&hdmi { + compatible = "fsl,imx6q-hdmi"; + + port@2 { + reg = <2>; + + hdmi_mux_2: endpoint { + remote-endpoint = <&ipu2_di0_hdmi>; + }; + }; + + port@3 { + reg = <3>; + + hdmi_mux_3: endpoint { + remote-endpoint = <&ipu2_di1_hdmi>; }; }; }; @@ -152,10 +223,56 @@ "di0", "di1"; lvds-channel@0 { - crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>; + port@2 { + reg = <2>; + + lvds0_mux_2: endpoint { + remote-endpoint = <&ipu2_di0_lvds0>; + }; + }; + + port@3 { + reg = <3>; + + lvds0_mux_3: endpoint { + remote-endpoint = <&ipu2_di1_lvds0>; + }; + }; }; lvds-channel@1 { - crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>; + port@2 { + reg = <2>; + + lvds1_mux_2: endpoint { + remote-endpoint = <&ipu2_di0_lvds1>; + }; + }; + + port@3 { + reg = <3>; + + lvds1_mux_3: endpoint { + remote-endpoint = <&ipu2_di1_lvds1>; + }; + }; + }; +}; + +&mipi_dsi { + port@2 { + reg = <2>; + + mipi_mux_2: endpoint { + remote-endpoint = <&ipu2_di0_mipi>; + }; + }; + + port@3 { + reg = <3>; + + mipi_mux_3: endpoint { + remote-endpoint = <&ipu2_di1_mipi>; + }; }; }; diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index fb28b2ecb1db..64a8cbe9480f 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -1358,13 +1358,76 @@ status = "disabled"; lvds-channel@0 { + #address-cells = <1>; + #size-cells = <0>; reg = <0>; status = "disabled"; + + port@0 { + reg = <0>; + + lvds0_mux_0: endpoint { + remote-endpoint = <&ipu1_di0_lvds0>; + }; + }; + + port@1 { + reg = <1>; + + lvds0_mux_1: endpoint { + remote-endpoint = <&ipu1_di1_lvds0>; + }; + }; }; lvds-channel@1 { + #address-cells = <1>; + #size-cells = <0>; reg = <1>; status = "disabled"; + + port@0 { + reg = <0>; + + lvds1_mux_0: endpoint { + remote-endpoint = <&ipu1_di0_lvds1>; + }; + }; + + port@1 { + reg = <1>; + + lvds1_mux_1: endpoint { + remote-endpoint = <&ipu1_di1_lvds1>; + }; + }; + }; + }; + + hdmi: hdmi@0120000 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x00120000 0x9000>; + interrupts = <0 115 0x04>; + gpr = <&gpr>; + clocks = <&clks 123>, <&clks 124>; + clock-names = "iahb", "isfr"; + status = "disabled"; + + port@0 { + reg = <0>; + + hdmi_mux_0: endpoint { + remote-endpoint = <&ipu1_di0_hdmi>; + }; + }; + + port@1 { + reg = <1>; + + hdmi_mux_1: endpoint { + remote-endpoint = <&ipu1_di1_hdmi>; + }; }; }; @@ -1579,8 +1642,27 @@ reg = <0x021dc000 0x4000>; }; - mipi@021e0000 { /* MIPI-DSI */ + mipi_dsi: mipi@021e0000 { + #address-cells = <1>; + #size-cells = <0>; reg = <0x021e0000 0x4000>; + status = "disabled"; + + port@0 { + reg = <0>; + + mipi_mux_0: endpoint { + remote-endpoint = <&ipu1_di0_mipi>; + }; + }; + + port@1 { + reg = <1>; + + mipi_mux_1: endpoint { + remote-endpoint = <&ipu1_di1_mipi>; + }; + }; }; vdoa@021e4000 { @@ -1634,13 +1716,64 @@ }; ipu1: ipu@02400000 { - #crtc-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; compatible = "fsl,imx6q-ipu"; reg = <0x02400000 0x400000>; interrupts = <0 6 0x4 0 5 0x4>; clocks = <&clks 130>, <&clks 131>, <&clks 132>; clock-names = "bus", "di0", "di1"; resets = <&src 2>; + + ipu1_di0: port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + ipu1_di0_disp0: endpoint@0 { + }; + + ipu1_di0_hdmi: endpoint@1 { + remote-endpoint = <&hdmi_mux_0>; + }; + + ipu1_di0_mipi: endpoint@2 { + remote-endpoint = <&mipi_mux_0>; + }; + + ipu1_di0_lvds0: endpoint@3 { + remote-endpoint = <&lvds0_mux_0>; + }; + + ipu1_di0_lvds1: endpoint@4 { + remote-endpoint = <&lvds1_mux_0>; + }; + }; + + ipu1_di1: port@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + ipu1_di0_disp1: endpoint@0 { + }; + + ipu1_di1_hdmi: endpoint@1 { + remote-endpoint = <&hdmi_mux_1>; + }; + + ipu1_di1_mipi: endpoint@2 { + remote-endpoint = <&mipi_mux_1>; + }; + + ipu1_di1_lvds0: endpoint@3 { + remote-endpoint = <&lvds0_mux_1>; + }; + + ipu1_di1_lvds1: endpoint@4 { + remote-endpoint = <&lvds1_mux_1>; + }; + }; }; }; }; diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index bfec313492b3..a7e68c81f89d 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -451,9 +451,9 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = { .type = IIO_ACCEL, \ .modified = 1, \ .channel2 = IIO_MOD_##_axis, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .scan_index = AXIS_##_axis, \ .scan_type = { \ .sign = 's', \ diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 5c63f0918d12..4bf4c16de976 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -207,6 +207,16 @@ config TWL6030_GPADC This driver can also be built as a module. If so, the module will be called twl6030-gpadc. +config VF610_ADC + tristate "Freescale vf610 ADC driver" + depends on OF + help + Say yes here to support for Vybrid board analog-to-digital converter. + Since the IP is used for i.MX6SLX, the driver also support i.MX6SLX. + + This driver can also be built as a module. If so, the module will be + called vf610_adc. + config VIPERBOARD_ADC tristate "Viperboard ADC support" depends on MFD_VIPERBOARD && USB @@ -214,4 +224,17 @@ config VIPERBOARD_ADC Say yes here to access the ADC part of the Nano River Technologies Viperboard. +config XILINX_XADC + tristate "Xilinx XADC driver" + depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST + depends on HAS_IOMEM + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to have support for the Xilinx XADC. The driver does support + both the ZYNQ interface to the XADC as well as the AXI-XADC interface. + + The driver can also be build as a module. If so, the module will be called + xilinx-xadc. + endmenu diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 85a4a045f1f0..bb252540664a 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -22,4 +22,7 @@ obj-$(CONFIG_NAU7802) += nau7802.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o +obj-$(CONFIG_VF610_ADC) += vf610_adc.o obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o +xilinx-xadc-y := xilinx-xadc-core.o xilinx-xadc-events.o +obj-$(CONFIG_XILINX_XADC) += xilinx-xadc.o diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 360259266d4f..9cf3229a7272 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -8,17 +8,11 @@ * based on linux/drivers/acron/char/pcf8583.c * Copyright (C) 2000 Russell King * + * Driver for max1363 and similar chips. + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. - * - * max1363.c - * - * Partial support for max1363 and similar chips. - * - * Not currently implemented. - * - * - Control of internal reference. */ #include @@ -1253,7 +1247,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { }, [max11604] = { .bits = 8, - .int_vref_mv = 4098, + .int_vref_mv = 4096, .mode_list = max1238_mode_list, .num_modes = ARRAY_SIZE(max1238_mode_list), .default_mode = s0to11, @@ -1313,7 +1307,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { }, [max11610] = { .bits = 10, - .int_vref_mv = 4098, + .int_vref_mv = 4096, .mode_list = max1238_mode_list, .num_modes = ARRAY_SIZE(max1238_mode_list), .default_mode = s0to11, @@ -1373,7 +1367,7 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { }, [max11616] = { .bits = 12, - .int_vref_mv = 4098, + .int_vref_mv = 4096, .mode_list = max1238_mode_list, .num_modes = ARRAY_SIZE(max1238_mode_list), .default_mode = s0to11, diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index 31e786e3999b..a4db3026bec6 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -13,7 +13,6 @@ * GNU General Public License for more details. */ -#include #include #include #include diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index 53a24ebb92c3..15282f148b3b 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -28,7 +28,6 @@ * 02110-1301 USA * */ -#include #include #include #include diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c new file mode 100644 index 000000000000..44799eb5930e --- /dev/null +++ b/drivers/iio/adc/vf610_adc.c @@ -0,0 +1,711 @@ +/* + * Freescale Vybrid vf610 ADC driver + * + * Copyright 2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* This will be the driver name the kernel reports */ +#define DRIVER_NAME "vf610-adc" + +/* Vybrid/IMX ADC registers */ +#define VF610_REG_ADC_HC0 0x00 +#define VF610_REG_ADC_HC1 0x04 +#define VF610_REG_ADC_HS 0x08 +#define VF610_REG_ADC_R0 0x0c +#define VF610_REG_ADC_R1 0x10 +#define VF610_REG_ADC_CFG 0x14 +#define VF610_REG_ADC_GC 0x18 +#define VF610_REG_ADC_GS 0x1c +#define VF610_REG_ADC_CV 0x20 +#define VF610_REG_ADC_OFS 0x24 +#define VF610_REG_ADC_CAL 0x28 +#define VF610_REG_ADC_PCTL 0x30 + +/* Configuration register field define */ +#define VF610_ADC_MODE_BIT8 0x00 +#define VF610_ADC_MODE_BIT10 0x04 +#define VF610_ADC_MODE_BIT12 0x08 +#define VF610_ADC_MODE_MASK 0x0c +#define VF610_ADC_BUSCLK2_SEL 0x01 +#define VF610_ADC_ALTCLK_SEL 0x02 +#define VF610_ADC_ADACK_SEL 0x03 +#define VF610_ADC_ADCCLK_MASK 0x03 +#define VF610_ADC_CLK_DIV2 0x20 +#define VF610_ADC_CLK_DIV4 0x40 +#define VF610_ADC_CLK_DIV8 0x60 +#define VF610_ADC_CLK_MASK 0x60 +#define VF610_ADC_ADLSMP_LONG 0x10 +#define VF610_ADC_ADSTS_MASK 0x300 +#define VF610_ADC_ADLPC_EN 0x80 +#define VF610_ADC_ADHSC_EN 0x400 +#define VF610_ADC_REFSEL_VALT 0x100 +#define VF610_ADC_REFSEL_VBG 0x1000 +#define VF610_ADC_ADTRG_HARD 0x2000 +#define VF610_ADC_AVGS_8 0x4000 +#define VF610_ADC_AVGS_16 0x8000 +#define VF610_ADC_AVGS_32 0xC000 +#define VF610_ADC_AVGS_MASK 0xC000 +#define VF610_ADC_OVWREN 0x10000 + +/* General control register field define */ +#define VF610_ADC_ADACKEN 0x1 +#define VF610_ADC_DMAEN 0x2 +#define VF610_ADC_ACREN 0x4 +#define VF610_ADC_ACFGT 0x8 +#define VF610_ADC_ACFE 0x10 +#define VF610_ADC_AVGEN 0x20 +#define VF610_ADC_ADCON 0x40 +#define VF610_ADC_CAL 0x80 + +/* Other field define */ +#define VF610_ADC_ADCHC(x) ((x) & 0xF) +#define VF610_ADC_AIEN (0x1 << 7) +#define VF610_ADC_CONV_DISABLE 0x1F +#define VF610_ADC_HS_COCO0 0x1 +#define VF610_ADC_CALF 0x2 +#define VF610_ADC_TIMEOUT msecs_to_jiffies(100) + +enum clk_sel { + VF610_ADCIOC_BUSCLK_SET, + VF610_ADCIOC_ALTCLK_SET, + VF610_ADCIOC_ADACK_SET, +}; + +enum vol_ref { + VF610_ADCIOC_VR_VREF_SET, + VF610_ADCIOC_VR_VALT_SET, + VF610_ADCIOC_VR_VBG_SET, +}; + +enum average_sel { + VF610_ADC_SAMPLE_1, + VF610_ADC_SAMPLE_4, + VF610_ADC_SAMPLE_8, + VF610_ADC_SAMPLE_16, + VF610_ADC_SAMPLE_32, +}; + +struct vf610_adc_feature { + enum clk_sel clk_sel; + enum vol_ref vol_ref; + + int clk_div; + int sample_rate; + int res_mode; + + bool lpm; + bool calibration; + bool ovwren; +}; + +struct vf610_adc { + struct device *dev; + void __iomem *regs; + struct clk *clk; + + u32 vref_uv; + u32 value; + struct regulator *vref; + struct vf610_adc_feature adc_feature; + + struct completion completion; +}; + +#define VF610_ADC_CHAN(_idx, _chan_type) { \ + .type = (_chan_type), \ + .indexed = 1, \ + .channel = (_idx), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ +} + +static const struct iio_chan_spec vf610_adc_iio_channels[] = { + VF610_ADC_CHAN(0, IIO_VOLTAGE), + VF610_ADC_CHAN(1, IIO_VOLTAGE), + VF610_ADC_CHAN(2, IIO_VOLTAGE), + VF610_ADC_CHAN(3, IIO_VOLTAGE), + VF610_ADC_CHAN(4, IIO_VOLTAGE), + VF610_ADC_CHAN(5, IIO_VOLTAGE), + VF610_ADC_CHAN(6, IIO_VOLTAGE), + VF610_ADC_CHAN(7, IIO_VOLTAGE), + VF610_ADC_CHAN(8, IIO_VOLTAGE), + VF610_ADC_CHAN(9, IIO_VOLTAGE), + VF610_ADC_CHAN(10, IIO_VOLTAGE), + VF610_ADC_CHAN(11, IIO_VOLTAGE), + VF610_ADC_CHAN(12, IIO_VOLTAGE), + VF610_ADC_CHAN(13, IIO_VOLTAGE), + VF610_ADC_CHAN(14, IIO_VOLTAGE), + VF610_ADC_CHAN(15, IIO_VOLTAGE), + /* sentinel */ +}; + +/* + * ADC sample frequency, unit is ADCK cycles. + * ADC clk source is ipg clock, which is the same as bus clock. + * + * ADC conversion time = SFCAdder + AverageNum x (BCT + LSTAdder) + * SFCAdder: fixed to 6 ADCK cycles + * AverageNum: 1, 4, 8, 16, 32 samples for hardware average. + * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode + * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles + * + * By default, enable 12 bit resolution mode, clock source + * set to ipg clock, So get below frequency group: + */ +static const u32 vf610_sample_freq_avail[5] = +{1941176, 559332, 286957, 145374, 73171}; + +static inline void vf610_adc_cfg_init(struct vf610_adc *info) +{ + /* set default Configuration for ADC controller */ + info->adc_feature.clk_sel = VF610_ADCIOC_BUSCLK_SET; + info->adc_feature.vol_ref = VF610_ADCIOC_VR_VREF_SET; + + info->adc_feature.calibration = true; + info->adc_feature.ovwren = true; + + info->adc_feature.clk_div = 1; + info->adc_feature.res_mode = 12; + info->adc_feature.sample_rate = 1; + info->adc_feature.lpm = true; +} + +static void vf610_adc_cfg_post_set(struct vf610_adc *info) +{ + struct vf610_adc_feature *adc_feature = &info->adc_feature; + int cfg_data = 0; + int gc_data = 0; + + switch (adc_feature->clk_sel) { + case VF610_ADCIOC_ALTCLK_SET: + cfg_data |= VF610_ADC_ALTCLK_SEL; + break; + case VF610_ADCIOC_ADACK_SET: + cfg_data |= VF610_ADC_ADACK_SEL; + break; + default: + break; + } + + /* low power set for calibration */ + cfg_data |= VF610_ADC_ADLPC_EN; + + /* enable high speed for calibration */ + cfg_data |= VF610_ADC_ADHSC_EN; + + /* voltage reference */ + switch (adc_feature->vol_ref) { + case VF610_ADCIOC_VR_VREF_SET: + break; + case VF610_ADCIOC_VR_VALT_SET: + cfg_data |= VF610_ADC_REFSEL_VALT; + break; + case VF610_ADCIOC_VR_VBG_SET: + cfg_data |= VF610_ADC_REFSEL_VBG; + break; + default: + dev_err(info->dev, "error voltage reference\n"); + } + + /* data overwrite enable */ + if (adc_feature->ovwren) + cfg_data |= VF610_ADC_OVWREN; + + writel(cfg_data, info->regs + VF610_REG_ADC_CFG); + writel(gc_data, info->regs + VF610_REG_ADC_GC); +} + +static void vf610_adc_calibration(struct vf610_adc *info) +{ + int adc_gc, hc_cfg; + int timeout; + + if (!info->adc_feature.calibration) + return; + + /* enable calibration interrupt */ + hc_cfg = VF610_ADC_AIEN | VF610_ADC_CONV_DISABLE; + writel(hc_cfg, info->regs + VF610_REG_ADC_HC0); + + adc_gc = readl(info->regs + VF610_REG_ADC_GC); + writel(adc_gc | VF610_ADC_CAL, info->regs + VF610_REG_ADC_GC); + + timeout = wait_for_completion_timeout + (&info->completion, VF610_ADC_TIMEOUT); + if (timeout == 0) + dev_err(info->dev, "Timeout for adc calibration\n"); + + adc_gc = readl(info->regs + VF610_REG_ADC_GS); + if (adc_gc & VF610_ADC_CALF) + dev_err(info->dev, "ADC calibration failed\n"); + + info->adc_feature.calibration = false; +} + +static void vf610_adc_cfg_set(struct vf610_adc *info) +{ + struct vf610_adc_feature *adc_feature = &(info->adc_feature); + int cfg_data; + + cfg_data = readl(info->regs + VF610_REG_ADC_CFG); + + /* low power configuration */ + cfg_data &= ~VF610_ADC_ADLPC_EN; + if (adc_feature->lpm) + cfg_data |= VF610_ADC_ADLPC_EN; + + /* disable high speed */ + cfg_data &= ~VF610_ADC_ADHSC_EN; + + writel(cfg_data, info->regs + VF610_REG_ADC_CFG); +} + +static void vf610_adc_sample_set(struct vf610_adc *info) +{ + struct vf610_adc_feature *adc_feature = &(info->adc_feature); + int cfg_data, gc_data; + + cfg_data = readl(info->regs + VF610_REG_ADC_CFG); + gc_data = readl(info->regs + VF610_REG_ADC_GC); + + /* resolution mode */ + cfg_data &= ~VF610_ADC_MODE_MASK; + switch (adc_feature->res_mode) { + case 8: + cfg_data |= VF610_ADC_MODE_BIT8; + break; + case 10: + cfg_data |= VF610_ADC_MODE_BIT10; + break; + case 12: + cfg_data |= VF610_ADC_MODE_BIT12; + break; + default: + dev_err(info->dev, "error resolution mode\n"); + break; + } + + /* clock select and clock divider */ + cfg_data &= ~(VF610_ADC_CLK_MASK | VF610_ADC_ADCCLK_MASK); + switch (adc_feature->clk_div) { + case 1: + break; + case 2: + cfg_data |= VF610_ADC_CLK_DIV2; + break; + case 4: + cfg_data |= VF610_ADC_CLK_DIV4; + break; + case 8: + cfg_data |= VF610_ADC_CLK_DIV8; + break; + case 16: + switch (adc_feature->clk_sel) { + case VF610_ADCIOC_BUSCLK_SET: + cfg_data |= VF610_ADC_BUSCLK2_SEL | VF610_ADC_CLK_DIV8; + break; + default: + dev_err(info->dev, "error clk divider\n"); + break; + } + break; + } + + /* Use the short sample mode */ + cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK); + + /* update hardware average selection */ + cfg_data &= ~VF610_ADC_AVGS_MASK; + gc_data &= ~VF610_ADC_AVGEN; + switch (adc_feature->sample_rate) { + case VF610_ADC_SAMPLE_1: + break; + case VF610_ADC_SAMPLE_4: + gc_data |= VF610_ADC_AVGEN; + break; + case VF610_ADC_SAMPLE_8: + gc_data |= VF610_ADC_AVGEN; + cfg_data |= VF610_ADC_AVGS_8; + break; + case VF610_ADC_SAMPLE_16: + gc_data |= VF610_ADC_AVGEN; + cfg_data |= VF610_ADC_AVGS_16; + break; + case VF610_ADC_SAMPLE_32: + gc_data |= VF610_ADC_AVGEN; + cfg_data |= VF610_ADC_AVGS_32; + break; + default: + dev_err(info->dev, + "error hardware sample average select\n"); + } + + writel(cfg_data, info->regs + VF610_REG_ADC_CFG); + writel(gc_data, info->regs + VF610_REG_ADC_GC); +} + +static void vf610_adc_hw_init(struct vf610_adc *info) +{ + /* CFG: Feature set */ + vf610_adc_cfg_post_set(info); + vf610_adc_sample_set(info); + + /* adc calibration */ + vf610_adc_calibration(info); + + /* CFG: power and speed set */ + vf610_adc_cfg_set(info); +} + +static int vf610_adc_read_data(struct vf610_adc *info) +{ + int result; + + result = readl(info->regs + VF610_REG_ADC_R0); + + switch (info->adc_feature.res_mode) { + case 8: + result &= 0xFF; + break; + case 10: + result &= 0x3FF; + break; + case 12: + result &= 0xFFF; + break; + default: + break; + } + + return result; +} + +static irqreturn_t vf610_adc_isr(int irq, void *dev_id) +{ + struct vf610_adc *info = (struct vf610_adc *)dev_id; + int coco; + + coco = readl(info->regs + VF610_REG_ADC_HS); + if (coco & VF610_ADC_HS_COCO0) { + info->value = vf610_adc_read_data(info); + complete(&info->completion); + } + + return IRQ_HANDLED; +} + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("1941176, 559332, 286957, 145374, 73171"); + +static struct attribute *vf610_attributes[] = { + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group vf610_attribute_group = { + .attrs = vf610_attributes, +}; + +static int vf610_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct vf610_adc *info = iio_priv(indio_dev); + unsigned int hc_cfg; + long ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&indio_dev->mlock); + reinit_completion(&info->completion); + + hc_cfg = VF610_ADC_ADCHC(chan->channel); + hc_cfg |= VF610_ADC_AIEN; + writel(hc_cfg, info->regs + VF610_REG_ADC_HC0); + ret = wait_for_completion_interruptible_timeout + (&info->completion, VF610_ADC_TIMEOUT); + if (ret == 0) { + mutex_unlock(&indio_dev->mlock); + return -ETIMEDOUT; + } + if (ret < 0) { + mutex_unlock(&indio_dev->mlock); + return ret; + } + + *val = info->value; + mutex_unlock(&indio_dev->mlock); + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + *val = info->vref_uv / 1000; + *val2 = info->adc_feature.res_mode; + return IIO_VAL_FRACTIONAL_LOG2; + + case IIO_CHAN_INFO_SAMP_FREQ: + *val = vf610_sample_freq_avail[info->adc_feature.sample_rate]; + *val2 = 0; + return IIO_VAL_INT; + + default: + break; + } + + return -EINVAL; +} + +static int vf610_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct vf610_adc *info = iio_priv(indio_dev); + int i; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + for (i = 0; + i < ARRAY_SIZE(vf610_sample_freq_avail); + i++) + if (val == vf610_sample_freq_avail[i]) { + info->adc_feature.sample_rate = i; + vf610_adc_sample_set(info); + return 0; + } + break; + + default: + break; + } + + return -EINVAL; +} + +static int vf610_adc_reg_access(struct iio_dev *indio_dev, + unsigned reg, unsigned writeval, + unsigned *readval) +{ + struct vf610_adc *info = iio_priv(indio_dev); + + if ((readval == NULL) || + (!(reg % 4) || (reg > VF610_REG_ADC_PCTL))) + return -EINVAL; + + *readval = readl(info->regs + reg); + + return 0; +} + +static const struct iio_info vf610_adc_iio_info = { + .driver_module = THIS_MODULE, + .read_raw = &vf610_read_raw, + .write_raw = &vf610_write_raw, + .debugfs_reg_access = &vf610_adc_reg_access, + .attrs = &vf610_attribute_group, +}; + +static const struct of_device_id vf610_adc_match[] = { + { .compatible = "fsl,vf610-adc", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, vf610_adc_match); + +static int vf610_adc_probe(struct platform_device *pdev) +{ + struct vf610_adc *info; + struct iio_dev *indio_dev; + struct resource *mem; + int irq; + int ret; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct vf610_adc)); + if (!indio_dev) { + dev_err(&pdev->dev, "Failed allocating iio device\n"); + return -ENOMEM; + } + + info = iio_priv(indio_dev); + info->dev = &pdev->dev; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + info->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(info->regs)) + return PTR_ERR(info->regs); + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(&pdev->dev, "no irq resource?\n"); + return -EINVAL; + } + + ret = devm_request_irq(info->dev, irq, + vf610_adc_isr, 0, + dev_name(&pdev->dev), info); + if (ret < 0) { + dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", irq); + return ret; + } + + info->clk = devm_clk_get(&pdev->dev, "adc"); + if (IS_ERR(info->clk)) { + dev_err(&pdev->dev, "failed getting clock, err = %ld\n", + PTR_ERR(info->clk)); + ret = PTR_ERR(info->clk); + return ret; + } + + info->vref = devm_regulator_get(&pdev->dev, "vref"); + if (IS_ERR(info->vref)) + return PTR_ERR(info->vref); + + ret = regulator_enable(info->vref); + if (ret) + return ret; + + info->vref_uv = regulator_get_voltage(info->vref); + + platform_set_drvdata(pdev, indio_dev); + + init_completion(&info->completion); + + indio_dev->name = dev_name(&pdev->dev); + indio_dev->dev.parent = &pdev->dev; + indio_dev->dev.of_node = pdev->dev.of_node; + indio_dev->info = &vf610_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = vf610_adc_iio_channels; + indio_dev->num_channels = ARRAY_SIZE(vf610_adc_iio_channels); + + ret = clk_prepare_enable(info->clk); + if (ret) { + dev_err(&pdev->dev, + "Could not prepare or enable the clock.\n"); + goto error_adc_clk_enable; + } + + vf610_adc_cfg_init(info); + vf610_adc_hw_init(info); + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "Couldn't register the device.\n"); + goto error_iio_device_register; + } + + return 0; + + +error_iio_device_register: + clk_disable_unprepare(info->clk); +error_adc_clk_enable: + regulator_disable(info->vref); + + return ret; +} + +static int vf610_adc_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct vf610_adc *info = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + regulator_disable(info->vref); + clk_disable_unprepare(info->clk); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int vf610_adc_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct vf610_adc *info = iio_priv(indio_dev); + int hc_cfg; + + /* ADC controller enters to stop mode */ + hc_cfg = readl(info->regs + VF610_REG_ADC_HC0); + hc_cfg |= VF610_ADC_CONV_DISABLE; + writel(hc_cfg, info->regs + VF610_REG_ADC_HC0); + + clk_disable_unprepare(info->clk); + regulator_disable(info->vref); + + return 0; +} + +static int vf610_adc_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct vf610_adc *info = iio_priv(indio_dev); + int ret; + + ret = regulator_enable(info->vref); + if (ret) + return ret; + + ret = clk_prepare_enable(info->clk); + if (ret) + return ret; + + vf610_adc_hw_init(info); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, + vf610_adc_suspend, + vf610_adc_resume); + +static struct platform_driver vf610_adc_driver = { + .probe = vf610_adc_probe, + .remove = vf610_adc_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = vf610_adc_match, + .pm = &vf610_adc_pm_ops, + }, +}; + +module_platform_driver(vf610_adc_driver); + +MODULE_AUTHOR("Fugang Duan "); +MODULE_DESCRIPTION("Freescale VF610 ADC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c index d0add8f9416b..9acf6b6d705b 100644 --- a/drivers/iio/adc/viperboard_adc.c +++ b/drivers/iio/adc/viperboard_adc.c @@ -139,8 +139,6 @@ static int vprbrd_adc_probe(struct platform_device *pdev) return ret; } - platform_set_drvdata(pdev, indio_dev); - return 0; } diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c new file mode 100644 index 000000000000..ab52be29141b --- /dev/null +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -0,0 +1,1333 @@ +/* + * Xilinx XADC driver + * + * Copyright 2013-2014 Analog Devices Inc. + * Author: Lars-Peter Clauen + * + * Licensed under the GPL-2. + * + * Documentation for the parts can be found at: + * - XADC hardmacro: Xilinx UG480 + * - ZYNQ XADC interface: Xilinx UG585 + * - AXI XADC interface: Xilinx PG019 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "xilinx-xadc.h" + +static const unsigned int XADC_ZYNQ_UNMASK_TIMEOUT = 500; + +/* ZYNQ register definitions */ +#define XADC_ZYNQ_REG_CFG 0x00 +#define XADC_ZYNQ_REG_INTSTS 0x04 +#define XADC_ZYNQ_REG_INTMSK 0x08 +#define XADC_ZYNQ_REG_STATUS 0x0c +#define XADC_ZYNQ_REG_CFIFO 0x10 +#define XADC_ZYNQ_REG_DFIFO 0x14 +#define XADC_ZYNQ_REG_CTL 0x18 + +#define XADC_ZYNQ_CFG_ENABLE BIT(31) +#define XADC_ZYNQ_CFG_CFIFOTH_MASK (0xf << 20) +#define XADC_ZYNQ_CFG_CFIFOTH_OFFSET 20 +#define XADC_ZYNQ_CFG_DFIFOTH_MASK (0xf << 16) +#define XADC_ZYNQ_CFG_DFIFOTH_OFFSET 16 +#define XADC_ZYNQ_CFG_WEDGE BIT(13) +#define XADC_ZYNQ_CFG_REDGE BIT(12) +#define XADC_ZYNQ_CFG_TCKRATE_MASK (0x3 << 8) +#define XADC_ZYNQ_CFG_TCKRATE_DIV2 (0x0 << 8) +#define XADC_ZYNQ_CFG_TCKRATE_DIV4 (0x1 << 8) +#define XADC_ZYNQ_CFG_TCKRATE_DIV8 (0x2 << 8) +#define XADC_ZYNQ_CFG_TCKRATE_DIV16 (0x3 << 8) +#define XADC_ZYNQ_CFG_IGAP_MASK 0x1f +#define XADC_ZYNQ_CFG_IGAP(x) (x) + +#define XADC_ZYNQ_INT_CFIFO_LTH BIT(9) +#define XADC_ZYNQ_INT_DFIFO_GTH BIT(8) +#define XADC_ZYNQ_INT_ALARM_MASK 0xff +#define XADC_ZYNQ_INT_ALARM_OFFSET 0 + +#define XADC_ZYNQ_STATUS_CFIFO_LVL_MASK (0xf << 16) +#define XADC_ZYNQ_STATUS_CFIFO_LVL_OFFSET 16 +#define XADC_ZYNQ_STATUS_DFIFO_LVL_MASK (0xf << 12) +#define XADC_ZYNQ_STATUS_DFIFO_LVL_OFFSET 12 +#define XADC_ZYNQ_STATUS_CFIFOF BIT(11) +#define XADC_ZYNQ_STATUS_CFIFOE BIT(10) +#define XADC_ZYNQ_STATUS_DFIFOF BIT(9) +#define XADC_ZYNQ_STATUS_DFIFOE BIT(8) +#define XADC_ZYNQ_STATUS_OT BIT(7) +#define XADC_ZYNQ_STATUS_ALM(x) BIT(x) + +#define XADC_ZYNQ_CTL_RESET BIT(4) + +#define XADC_ZYNQ_CMD_NOP 0x00 +#define XADC_ZYNQ_CMD_READ 0x01 +#define XADC_ZYNQ_CMD_WRITE 0x02 + +#define XADC_ZYNQ_CMD(cmd, addr, data) (((cmd) << 26) | ((addr) << 16) | (data)) + +/* AXI register definitions */ +#define XADC_AXI_REG_RESET 0x00 +#define XADC_AXI_REG_STATUS 0x04 +#define XADC_AXI_REG_ALARM_STATUS 0x08 +#define XADC_AXI_REG_CONVST 0x0c +#define XADC_AXI_REG_XADC_RESET 0x10 +#define XADC_AXI_REG_GIER 0x5c +#define XADC_AXI_REG_IPISR 0x60 +#define XADC_AXI_REG_IPIER 0x68 +#define XADC_AXI_ADC_REG_OFFSET 0x200 + +#define XADC_AXI_RESET_MAGIC 0xa +#define XADC_AXI_GIER_ENABLE BIT(31) + +#define XADC_AXI_INT_EOS BIT(4) +#define XADC_AXI_INT_ALARM_MASK 0x3c0f + +#define XADC_FLAGS_BUFFERED BIT(0) + +static void xadc_write_reg(struct xadc *xadc, unsigned int reg, + uint32_t val) +{ + writel(val, xadc->base + reg); +} + +static void xadc_read_reg(struct xadc *xadc, unsigned int reg, + uint32_t *val) +{ + *val = readl(xadc->base + reg); +} + +/* + * The ZYNQ interface uses two asynchronous FIFOs for communication with the + * XADC. Reads and writes to the XADC register are performed by submitting a + * request to the command FIFO (CFIFO), once the request has been completed the + * result can be read from the data FIFO (DFIFO). The method currently used in + * this driver is to submit the request for a read/write operation, then go to + * sleep and wait for an interrupt that signals that a response is available in + * the data FIFO. + */ + +static void xadc_zynq_write_fifo(struct xadc *xadc, uint32_t *cmd, + unsigned int n) +{ + unsigned int i; + + for (i = 0; i < n; i++) + xadc_write_reg(xadc, XADC_ZYNQ_REG_CFIFO, cmd[i]); +} + +static void xadc_zynq_drain_fifo(struct xadc *xadc) +{ + uint32_t status, tmp; + + xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &status); + + while (!(status & XADC_ZYNQ_STATUS_DFIFOE)) { + xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &tmp); + xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &status); + } +} + +static void xadc_zynq_update_intmsk(struct xadc *xadc, unsigned int mask, + unsigned int val) +{ + xadc->zynq_intmask &= ~mask; + xadc->zynq_intmask |= val; + + xadc_write_reg(xadc, XADC_ZYNQ_REG_INTMSK, + xadc->zynq_intmask | xadc->zynq_masked_alarm); +} + +static int xadc_zynq_write_adc_reg(struct xadc *xadc, unsigned int reg, + uint16_t val) +{ + uint32_t cmd[1]; + uint32_t tmp; + int ret; + + spin_lock_irq(&xadc->lock); + xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, + XADC_ZYNQ_INT_DFIFO_GTH); + + reinit_completion(&xadc->completion); + + cmd[0] = XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_WRITE, reg, val); + xadc_zynq_write_fifo(xadc, cmd, ARRAY_SIZE(cmd)); + xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &tmp); + tmp &= ~XADC_ZYNQ_CFG_DFIFOTH_MASK; + tmp |= 0 << XADC_ZYNQ_CFG_DFIFOTH_OFFSET; + xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, tmp); + + xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, 0); + spin_unlock_irq(&xadc->lock); + + ret = wait_for_completion_interruptible_timeout(&xadc->completion, HZ); + if (ret == 0) + ret = -EIO; + else + ret = 0; + + xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &tmp); + + return ret; +} + +static int xadc_zynq_read_adc_reg(struct xadc *xadc, unsigned int reg, + uint16_t *val) +{ + uint32_t cmd[2]; + uint32_t resp, tmp; + int ret; + + cmd[0] = XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_READ, reg, 0); + cmd[1] = XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_NOP, 0, 0); + + spin_lock_irq(&xadc->lock); + xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, + XADC_ZYNQ_INT_DFIFO_GTH); + xadc_zynq_drain_fifo(xadc); + reinit_completion(&xadc->completion); + + xadc_zynq_write_fifo(xadc, cmd, ARRAY_SIZE(cmd)); + xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &tmp); + tmp &= ~XADC_ZYNQ_CFG_DFIFOTH_MASK; + tmp |= 1 << XADC_ZYNQ_CFG_DFIFOTH_OFFSET; + xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, tmp); + + xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, 0); + spin_unlock_irq(&xadc->lock); + ret = wait_for_completion_interruptible_timeout(&xadc->completion, HZ); + if (ret == 0) + ret = -EIO; + if (ret < 0) + return ret; + + xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &resp); + xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &resp); + + *val = resp & 0xffff; + + return 0; +} + +static unsigned int xadc_zynq_transform_alarm(unsigned int alarm) +{ + return ((alarm & 0x80) >> 4) | + ((alarm & 0x78) << 1) | + (alarm & 0x07); +} + +/* + * The ZYNQ threshold interrupts are level sensitive. Since we can't make the + * threshold condition go way from within the interrupt handler, this means as + * soon as a threshold condition is present we would enter the interrupt handler + * again and again. To work around this we mask all active thresholds interrupts + * in the interrupt handler and start a timer. In this timer we poll the + * interrupt status and only if the interrupt is inactive we unmask it again. + */ +static void xadc_zynq_unmask_worker(struct work_struct *work) +{ + struct xadc *xadc = container_of(work, struct xadc, zynq_unmask_work.work); + unsigned int misc_sts, unmask; + + xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &misc_sts); + + misc_sts &= XADC_ZYNQ_INT_ALARM_MASK; + + spin_lock_irq(&xadc->lock); + + /* Clear those bits which are not active anymore */ + unmask = (xadc->zynq_masked_alarm ^ misc_sts) & xadc->zynq_masked_alarm; + xadc->zynq_masked_alarm &= misc_sts; + + /* Also clear those which are masked out anyway */ + xadc->zynq_masked_alarm &= ~xadc->zynq_intmask; + + /* Clear the interrupts before we unmask them */ + xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, unmask); + + xadc_zynq_update_intmsk(xadc, 0, 0); + + spin_unlock_irq(&xadc->lock); + + /* if still pending some alarm re-trigger the timer */ + if (xadc->zynq_masked_alarm) { + schedule_delayed_work(&xadc->zynq_unmask_work, + msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT)); + } +} + +static irqreturn_t xadc_zynq_threaded_interrupt_handler(int irq, void *devid) +{ + struct iio_dev *indio_dev = devid; + struct xadc *xadc = iio_priv(indio_dev); + unsigned int alarm; + + spin_lock_irq(&xadc->lock); + alarm = xadc->zynq_alarm; + xadc->zynq_alarm = 0; + spin_unlock_irq(&xadc->lock); + + xadc_handle_events(indio_dev, xadc_zynq_transform_alarm(alarm)); + + /* unmask the required interrupts in timer. */ + schedule_delayed_work(&xadc->zynq_unmask_work, + msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT)); + + return IRQ_HANDLED; +} + +static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid) +{ + struct iio_dev *indio_dev = devid; + struct xadc *xadc = iio_priv(indio_dev); + irqreturn_t ret = IRQ_HANDLED; + uint32_t status; + + xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status); + + status &= ~(xadc->zynq_intmask | xadc->zynq_masked_alarm); + + if (!status) + return IRQ_NONE; + + spin_lock(&xadc->lock); + + xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, status); + + if (status & XADC_ZYNQ_INT_DFIFO_GTH) { + xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, + XADC_ZYNQ_INT_DFIFO_GTH); + complete(&xadc->completion); + } + + status &= XADC_ZYNQ_INT_ALARM_MASK; + if (status) { + xadc->zynq_alarm |= status; + xadc->zynq_masked_alarm |= status; + /* + * mask the current event interrupt, + * unmask it when the interrupt is no more active. + */ + xadc_zynq_update_intmsk(xadc, 0, 0); + ret = IRQ_WAKE_THREAD; + } + spin_unlock(&xadc->lock); + + return ret; +} + +#define XADC_ZYNQ_TCK_RATE_MAX 50000000 +#define XADC_ZYNQ_IGAP_DEFAULT 20 + +static int xadc_zynq_setup(struct platform_device *pdev, + struct iio_dev *indio_dev, int irq) +{ + struct xadc *xadc = iio_priv(indio_dev); + unsigned long pcap_rate; + unsigned int tck_div; + unsigned int div; + unsigned int igap; + unsigned int tck_rate; + + /* TODO: Figure out how to make igap and tck_rate configurable */ + igap = XADC_ZYNQ_IGAP_DEFAULT; + tck_rate = XADC_ZYNQ_TCK_RATE_MAX; + + xadc->zynq_intmask = ~0; + + pcap_rate = clk_get_rate(xadc->clk); + + if (tck_rate > XADC_ZYNQ_TCK_RATE_MAX) + tck_rate = XADC_ZYNQ_TCK_RATE_MAX; + if (tck_rate > pcap_rate / 2) { + div = 2; + } else { + div = pcap_rate / tck_rate; + if (pcap_rate / div > XADC_ZYNQ_TCK_RATE_MAX) + div++; + } + + if (div <= 3) + tck_div = XADC_ZYNQ_CFG_TCKRATE_DIV2; + else if (div <= 7) + tck_div = XADC_ZYNQ_CFG_TCKRATE_DIV4; + else if (div <= 15) + tck_div = XADC_ZYNQ_CFG_TCKRATE_DIV8; + else + tck_div = XADC_ZYNQ_CFG_TCKRATE_DIV16; + + xadc_write_reg(xadc, XADC_ZYNQ_REG_CTL, XADC_ZYNQ_CTL_RESET); + xadc_write_reg(xadc, XADC_ZYNQ_REG_CTL, 0); + xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, ~0); + xadc_write_reg(xadc, XADC_ZYNQ_REG_INTMSK, xadc->zynq_intmask); + xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, XADC_ZYNQ_CFG_ENABLE | + XADC_ZYNQ_CFG_REDGE | XADC_ZYNQ_CFG_WEDGE | + tck_div | XADC_ZYNQ_CFG_IGAP(igap)); + + return 0; +} + +static unsigned long xadc_zynq_get_dclk_rate(struct xadc *xadc) +{ + unsigned int div; + uint32_t val; + + xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &val); + + switch (val & XADC_ZYNQ_CFG_TCKRATE_MASK) { + case XADC_ZYNQ_CFG_TCKRATE_DIV4: + div = 4; + break; + case XADC_ZYNQ_CFG_TCKRATE_DIV8: + div = 8; + break; + case XADC_ZYNQ_CFG_TCKRATE_DIV16: + div = 16; + break; + default: + div = 2; + break; + } + + return clk_get_rate(xadc->clk) / div; +} + +static void xadc_zynq_update_alarm(struct xadc *xadc, unsigned int alarm) +{ + unsigned long flags; + uint32_t status; + + /* Move OT to bit 7 */ + alarm = ((alarm & 0x08) << 4) | ((alarm & 0xf0) >> 1) | (alarm & 0x07); + + spin_lock_irqsave(&xadc->lock, flags); + + /* Clear previous interrupts if any. */ + xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status); + xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, status & alarm); + + xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_ALARM_MASK, + ~alarm & XADC_ZYNQ_INT_ALARM_MASK); + + spin_unlock_irqrestore(&xadc->lock, flags); +} + +static const struct xadc_ops xadc_zynq_ops = { + .read = xadc_zynq_read_adc_reg, + .write = xadc_zynq_write_adc_reg, + .setup = xadc_zynq_setup, + .get_dclk_rate = xadc_zynq_get_dclk_rate, + .interrupt_handler = xadc_zynq_interrupt_handler, + .threaded_interrupt_handler = xadc_zynq_threaded_interrupt_handler, + .update_alarm = xadc_zynq_update_alarm, +}; + +static int xadc_axi_read_adc_reg(struct xadc *xadc, unsigned int reg, + uint16_t *val) +{ + uint32_t val32; + + xadc_read_reg(xadc, XADC_AXI_ADC_REG_OFFSET + reg * 4, &val32); + *val = val32 & 0xffff; + + return 0; +} + +static int xadc_axi_write_adc_reg(struct xadc *xadc, unsigned int reg, + uint16_t val) +{ + xadc_write_reg(xadc, XADC_AXI_ADC_REG_OFFSET + reg * 4, val); + + return 0; +} + +static int xadc_axi_setup(struct platform_device *pdev, + struct iio_dev *indio_dev, int irq) +{ + struct xadc *xadc = iio_priv(indio_dev); + + xadc_write_reg(xadc, XADC_AXI_REG_RESET, XADC_AXI_RESET_MAGIC); + xadc_write_reg(xadc, XADC_AXI_REG_GIER, XADC_AXI_GIER_ENABLE); + + return 0; +} + +static irqreturn_t xadc_axi_interrupt_handler(int irq, void *devid) +{ + struct iio_dev *indio_dev = devid; + struct xadc *xadc = iio_priv(indio_dev); + uint32_t status, mask; + unsigned int events; + + xadc_read_reg(xadc, XADC_AXI_REG_IPISR, &status); + xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &mask); + status &= mask; + + if (!status) + return IRQ_NONE; + + if ((status & XADC_AXI_INT_EOS) && xadc->trigger) + iio_trigger_poll(xadc->trigger, 0); + + if (status & XADC_AXI_INT_ALARM_MASK) { + /* + * The order of the bits in the AXI-XADC status register does + * not match the order of the bits in the XADC alarm enable + * register. xadc_handle_events() expects the events to be in + * the same order as the XADC alarm enable register. + */ + events = (status & 0x000e) >> 1; + events |= (status & 0x0001) << 3; + events |= (status & 0x3c00) >> 6; + xadc_handle_events(indio_dev, events); + } + + xadc_write_reg(xadc, XADC_AXI_REG_IPISR, status); + + return IRQ_HANDLED; +} + +static void xadc_axi_update_alarm(struct xadc *xadc, unsigned int alarm) +{ + uint32_t val; + unsigned long flags; + + /* + * The order of the bits in the AXI-XADC status register does not match + * the order of the bits in the XADC alarm enable register. We get + * passed the alarm mask in the same order as in the XADC alarm enable + * register. + */ + alarm = ((alarm & 0x07) << 1) | ((alarm & 0x08) >> 3) | + ((alarm & 0xf0) << 6); + + spin_lock_irqsave(&xadc->lock, flags); + xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &val); + val &= ~XADC_AXI_INT_ALARM_MASK; + val |= alarm; + xadc_write_reg(xadc, XADC_AXI_REG_IPIER, val); + spin_unlock_irqrestore(&xadc->lock, flags); +} + +static unsigned long xadc_axi_get_dclk(struct xadc *xadc) +{ + return clk_get_rate(xadc->clk); +} + +static const struct xadc_ops xadc_axi_ops = { + .read = xadc_axi_read_adc_reg, + .write = xadc_axi_write_adc_reg, + .setup = xadc_axi_setup, + .get_dclk_rate = xadc_axi_get_dclk, + .update_alarm = xadc_axi_update_alarm, + .interrupt_handler = xadc_axi_interrupt_handler, + .flags = XADC_FLAGS_BUFFERED, +}; + +static int _xadc_update_adc_reg(struct xadc *xadc, unsigned int reg, + uint16_t mask, uint16_t val) +{ + uint16_t tmp; + int ret; + + ret = _xadc_read_adc_reg(xadc, reg, &tmp); + if (ret) + return ret; + + return _xadc_write_adc_reg(xadc, reg, (tmp & ~mask) | val); +} + +static int xadc_update_adc_reg(struct xadc *xadc, unsigned int reg, + uint16_t mask, uint16_t val) +{ + int ret; + + mutex_lock(&xadc->mutex); + ret = _xadc_update_adc_reg(xadc, reg, mask, val); + mutex_unlock(&xadc->mutex); + + return ret; +} + +static unsigned long xadc_get_dclk_rate(struct xadc *xadc) +{ + return xadc->ops->get_dclk_rate(xadc); +} + +static int xadc_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *mask) +{ + struct xadc *xadc = iio_priv(indio_dev); + unsigned int n; + + n = bitmap_weight(mask, indio_dev->masklength); + + kfree(xadc->data); + xadc->data = kcalloc(n, sizeof(*xadc->data), GFP_KERNEL); + if (!xadc->data) + return -ENOMEM; + + return 0; +} + +static unsigned int xadc_scan_index_to_channel(unsigned int scan_index) +{ + switch (scan_index) { + case 5: + return XADC_REG_VCCPINT; + case 6: + return XADC_REG_VCCPAUX; + case 7: + return XADC_REG_VCCO_DDR; + case 8: + return XADC_REG_TEMP; + case 9: + return XADC_REG_VCCINT; + case 10: + return XADC_REG_VCCAUX; + case 11: + return XADC_REG_VPVN; + case 12: + return XADC_REG_VREFP; + case 13: + return XADC_REG_VREFN; + case 14: + return XADC_REG_VCCBRAM; + default: + return XADC_REG_VAUX(scan_index - 16); + } +} + +static irqreturn_t xadc_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct xadc *xadc = iio_priv(indio_dev); + unsigned int chan; + int i, j; + + if (!xadc->data) + goto out; + + j = 0; + for_each_set_bit(i, indio_dev->active_scan_mask, + indio_dev->masklength) { + chan = xadc_scan_index_to_channel(i); + xadc_read_adc_reg(xadc, chan, &xadc->data[j]); + j++; + } + + iio_push_to_buffers(indio_dev, xadc->data); + +out: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int xadc_trigger_set_state(struct iio_trigger *trigger, bool state) +{ + struct xadc *xadc = iio_trigger_get_drvdata(trigger); + unsigned long flags; + unsigned int convst; + unsigned int val; + int ret = 0; + + mutex_lock(&xadc->mutex); + + if (state) { + /* Only one of the two triggers can be active at the a time. */ + if (xadc->trigger != NULL) { + ret = -EBUSY; + goto err_out; + } else { + xadc->trigger = trigger; + if (trigger == xadc->convst_trigger) + convst = XADC_CONF0_EC; + else + convst = 0; + } + ret = _xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF0_EC, + convst); + if (ret) + goto err_out; + } else { + xadc->trigger = NULL; + } + + spin_lock_irqsave(&xadc->lock, flags); + xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &val); + xadc_write_reg(xadc, XADC_AXI_REG_IPISR, val & XADC_AXI_INT_EOS); + if (state) + val |= XADC_AXI_INT_EOS; + else + val &= ~XADC_AXI_INT_EOS; + xadc_write_reg(xadc, XADC_AXI_REG_IPIER, val); + spin_unlock_irqrestore(&xadc->lock, flags); + +err_out: + mutex_unlock(&xadc->mutex); + + return ret; +} + +static const struct iio_trigger_ops xadc_trigger_ops = { + .owner = THIS_MODULE, + .set_trigger_state = &xadc_trigger_set_state, +}; + +static struct iio_trigger *xadc_alloc_trigger(struct iio_dev *indio_dev, + const char *name) +{ + struct iio_trigger *trig; + int ret; + + trig = iio_trigger_alloc("%s%d-%s", indio_dev->name, + indio_dev->id, name); + if (trig == NULL) + return ERR_PTR(-ENOMEM); + + trig->dev.parent = indio_dev->dev.parent; + trig->ops = &xadc_trigger_ops; + iio_trigger_set_drvdata(trig, iio_priv(indio_dev)); + + ret = iio_trigger_register(trig); + if (ret) + goto error_free_trig; + + return trig; + +error_free_trig: + iio_trigger_free(trig); + return ERR_PTR(ret); +} + +static int xadc_power_adc_b(struct xadc *xadc, unsigned int seq_mode) +{ + uint16_t val; + + switch (seq_mode) { + case XADC_CONF1_SEQ_SIMULTANEOUS: + case XADC_CONF1_SEQ_INDEPENDENT: + val = XADC_CONF2_PD_ADC_B; + break; + default: + val = 0; + break; + } + + return xadc_update_adc_reg(xadc, XADC_REG_CONF2, XADC_CONF2_PD_MASK, + val); +} + +static int xadc_get_seq_mode(struct xadc *xadc, unsigned long scan_mode) +{ + unsigned int aux_scan_mode = scan_mode >> 16; + + if (xadc->external_mux_mode == XADC_EXTERNAL_MUX_DUAL) + return XADC_CONF1_SEQ_SIMULTANEOUS; + + if ((aux_scan_mode & 0xff00) == 0 || + (aux_scan_mode & 0x00ff) == 0) + return XADC_CONF1_SEQ_CONTINUOUS; + + return XADC_CONF1_SEQ_SIMULTANEOUS; +} + +static int xadc_postdisable(struct iio_dev *indio_dev) +{ + struct xadc *xadc = iio_priv(indio_dev); + unsigned long scan_mask; + int ret; + int i; + + scan_mask = 1; /* Run calibration as part of the sequence */ + for (i = 0; i < indio_dev->num_channels; i++) + scan_mask |= BIT(indio_dev->channels[i].scan_index); + + /* Enable all channels and calibration */ + ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(0), scan_mask & 0xffff); + if (ret) + return ret; + + ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(1), scan_mask >> 16); + if (ret) + return ret; + + ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_SEQ_MASK, + XADC_CONF1_SEQ_CONTINUOUS); + if (ret) + return ret; + + return xadc_power_adc_b(xadc, XADC_CONF1_SEQ_CONTINUOUS); +} + +static int xadc_preenable(struct iio_dev *indio_dev) +{ + struct xadc *xadc = iio_priv(indio_dev); + unsigned long scan_mask; + int seq_mode; + int ret; + + ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_SEQ_MASK, + XADC_CONF1_SEQ_DEFAULT); + if (ret) + goto err; + + scan_mask = *indio_dev->active_scan_mask; + seq_mode = xadc_get_seq_mode(xadc, scan_mask); + + ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(0), scan_mask & 0xffff); + if (ret) + goto err; + + ret = xadc_write_adc_reg(xadc, XADC_REG_SEQ(1), scan_mask >> 16); + if (ret) + goto err; + + ret = xadc_power_adc_b(xadc, seq_mode); + if (ret) + goto err; + + ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_SEQ_MASK, + seq_mode); + if (ret) + goto err; + + return 0; +err: + xadc_postdisable(indio_dev); + return ret; +} + +static struct iio_buffer_setup_ops xadc_buffer_ops = { + .preenable = &xadc_preenable, + .postenable = &iio_triggered_buffer_postenable, + .predisable = &iio_triggered_buffer_predisable, + .postdisable = &xadc_postdisable, +}; + +static int xadc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, long info) +{ + struct xadc *xadc = iio_priv(indio_dev); + unsigned int div; + uint16_t val16; + int ret; + + switch (info) { + case IIO_CHAN_INFO_RAW: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + ret = xadc_read_adc_reg(xadc, chan->address, &val16); + if (ret < 0) + return ret; + + val16 >>= 4; + if (chan->scan_type.sign == 'u') + *val = val16; + else + *val = sign_extend32(val16, 11); + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + /* V = (val * 3.0) / 4096 */ + switch (chan->address) { + case XADC_REG_VCCINT: + case XADC_REG_VCCAUX: + case XADC_REG_VCCBRAM: + case XADC_REG_VCCPINT: + case XADC_REG_VCCPAUX: + case XADC_REG_VCCO_DDR: + *val = 3000; + break; + default: + *val = 1000; + break; + } + *val2 = 12; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_TEMP: + /* Temp in C = (val * 503.975) / 4096 - 273.15 */ + *val = 503975; + *val2 = 12; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + /* Only the temperature channel has an offset */ + *val = -((273150 << 12) / 503975); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = xadc_read_adc_reg(xadc, XADC_REG_CONF2, &val16); + if (ret) + return ret; + + div = (val16 & XADC_CONF2_DIV_MASK) >> XADC_CONF2_DIV_OFFSET; + if (div < 2) + div = 2; + + *val = xadc_get_dclk_rate(xadc) / div / 26; + + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int xadc_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long info) +{ + struct xadc *xadc = iio_priv(indio_dev); + unsigned long clk_rate = xadc_get_dclk_rate(xadc); + unsigned int div; + + if (info != IIO_CHAN_INFO_SAMP_FREQ) + return -EINVAL; + + if (val <= 0) + return -EINVAL; + + /* Max. 150 kSPS */ + if (val > 150000) + val = 150000; + + val *= 26; + + /* Min 1MHz */ + if (val < 1000000) + val = 1000000; + + /* + * We want to round down, but only if we do not exceed the 150 kSPS + * limit. + */ + div = clk_rate / val; + if (clk_rate / div / 26 > 150000) + div++; + if (div < 2) + div = 2; + else if (div > 0xff) + div = 0xff; + + return xadc_update_adc_reg(xadc, XADC_REG_CONF2, XADC_CONF2_DIV_MASK, + div << XADC_CONF2_DIV_OFFSET); +} + +static const struct iio_event_spec xadc_temp_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_HYSTERESIS), + }, +}; + +/* Separate values for upper and lower thresholds, but only a shared enabled */ +static const struct iio_event_spec xadc_voltage_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + }, +}; + +#define XADC_CHAN_TEMP(_chan, _scan_index, _addr) { \ + .type = IIO_TEMP, \ + .indexed = 1, \ + .channel = (_chan), \ + .address = (_addr), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .event_spec = xadc_temp_events, \ + .num_event_specs = ARRAY_SIZE(xadc_temp_events), \ + .scan_index = (_scan_index), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 12, \ + .storagebits = 16, \ + .shift = 4, \ + .endianness = IIO_CPU, \ + }, \ +} + +#define XADC_CHAN_VOLTAGE(_chan, _scan_index, _addr, _ext, _alarm) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (_chan), \ + .address = (_addr), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .event_spec = (_alarm) ? xadc_voltage_events : NULL, \ + .num_event_specs = (_alarm) ? ARRAY_SIZE(xadc_voltage_events) : 0, \ + .scan_index = (_scan_index), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 12, \ + .storagebits = 16, \ + .shift = 4, \ + .endianness = IIO_CPU, \ + }, \ + .extend_name = _ext, \ +} + +static const struct iio_chan_spec xadc_channels[] = { + XADC_CHAN_TEMP(0, 8, XADC_REG_TEMP), + XADC_CHAN_VOLTAGE(0, 9, XADC_REG_VCCINT, "vccint", true), + XADC_CHAN_VOLTAGE(1, 10, XADC_REG_VCCINT, "vccaux", true), + XADC_CHAN_VOLTAGE(2, 14, XADC_REG_VCCBRAM, "vccbram", true), + XADC_CHAN_VOLTAGE(3, 5, XADC_REG_VCCPINT, "vccpint", true), + XADC_CHAN_VOLTAGE(4, 6, XADC_REG_VCCPAUX, "vccpaux", true), + XADC_CHAN_VOLTAGE(5, 7, XADC_REG_VCCO_DDR, "vccoddr", true), + XADC_CHAN_VOLTAGE(6, 12, XADC_REG_VREFP, "vrefp", false), + XADC_CHAN_VOLTAGE(7, 13, XADC_REG_VREFN, "vrefn", false), + XADC_CHAN_VOLTAGE(8, 11, XADC_REG_VPVN, NULL, false), + XADC_CHAN_VOLTAGE(9, 16, XADC_REG_VAUX(0), NULL, false), + XADC_CHAN_VOLTAGE(10, 17, XADC_REG_VAUX(1), NULL, false), + XADC_CHAN_VOLTAGE(11, 18, XADC_REG_VAUX(2), NULL, false), + XADC_CHAN_VOLTAGE(12, 19, XADC_REG_VAUX(3), NULL, false), + XADC_CHAN_VOLTAGE(13, 20, XADC_REG_VAUX(4), NULL, false), + XADC_CHAN_VOLTAGE(14, 21, XADC_REG_VAUX(5), NULL, false), + XADC_CHAN_VOLTAGE(15, 22, XADC_REG_VAUX(6), NULL, false), + XADC_CHAN_VOLTAGE(16, 23, XADC_REG_VAUX(7), NULL, false), + XADC_CHAN_VOLTAGE(17, 24, XADC_REG_VAUX(8), NULL, false), + XADC_CHAN_VOLTAGE(18, 25, XADC_REG_VAUX(9), NULL, false), + XADC_CHAN_VOLTAGE(19, 26, XADC_REG_VAUX(10), NULL, false), + XADC_CHAN_VOLTAGE(20, 27, XADC_REG_VAUX(11), NULL, false), + XADC_CHAN_VOLTAGE(21, 28, XADC_REG_VAUX(12), NULL, false), + XADC_CHAN_VOLTAGE(22, 29, XADC_REG_VAUX(13), NULL, false), + XADC_CHAN_VOLTAGE(23, 30, XADC_REG_VAUX(14), NULL, false), + XADC_CHAN_VOLTAGE(24, 31, XADC_REG_VAUX(15), NULL, false), +}; + +static const struct iio_info xadc_info = { + .read_raw = &xadc_read_raw, + .write_raw = &xadc_write_raw, + .read_event_config = &xadc_read_event_config, + .write_event_config = &xadc_write_event_config, + .read_event_value = &xadc_read_event_value, + .write_event_value = &xadc_write_event_value, + .update_scan_mode = &xadc_update_scan_mode, + .driver_module = THIS_MODULE, +}; + +static const struct of_device_id xadc_of_match_table[] = { + { .compatible = "xlnx,zynq-xadc-1.00.a", (void *)&xadc_zynq_ops }, + { .compatible = "xlnx,axi-xadc-1.00.a", (void *)&xadc_axi_ops }, + { }, +}; +MODULE_DEVICE_TABLE(of, xadc_of_match_table); + +static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, + unsigned int *conf) +{ + struct xadc *xadc = iio_priv(indio_dev); + struct iio_chan_spec *channels, *chan; + struct device_node *chan_node, *child; + unsigned int num_channels; + const char *external_mux; + u32 ext_mux_chan; + int reg; + int ret; + + *conf = 0; + + ret = of_property_read_string(np, "xlnx,external-mux", &external_mux); + if (ret < 0 || strcasecmp(external_mux, "none") == 0) + xadc->external_mux_mode = XADC_EXTERNAL_MUX_NONE; + else if (strcasecmp(external_mux, "single") == 0) + xadc->external_mux_mode = XADC_EXTERNAL_MUX_SINGLE; + else if (strcasecmp(external_mux, "dual") == 0) + xadc->external_mux_mode = XADC_EXTERNAL_MUX_DUAL; + else + return -EINVAL; + + if (xadc->external_mux_mode != XADC_EXTERNAL_MUX_NONE) { + ret = of_property_read_u32(np, "xlnx,external-mux-channel", + &ext_mux_chan); + if (ret < 0) + return ret; + + if (xadc->external_mux_mode == XADC_EXTERNAL_MUX_SINGLE) { + if (ext_mux_chan == 0) + ext_mux_chan = XADC_REG_VPVN; + else if (ext_mux_chan <= 16) + ext_mux_chan = XADC_REG_VAUX(ext_mux_chan - 1); + else + return -EINVAL; + } else { + if (ext_mux_chan > 0 && ext_mux_chan <= 8) + ext_mux_chan = XADC_REG_VAUX(ext_mux_chan - 1); + else + return -EINVAL; + } + + *conf |= XADC_CONF0_MUX | XADC_CONF0_CHAN(ext_mux_chan); + } + + channels = kmemdup(xadc_channels, sizeof(xadc_channels), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + num_channels = 9; + chan = &channels[9]; + + chan_node = of_get_child_by_name(np, "xlnx,channels"); + if (chan_node) { + for_each_child_of_node(chan_node, child) { + if (num_channels >= ARRAY_SIZE(xadc_channels)) { + of_node_put(child); + break; + } + + ret = of_property_read_u32(child, "reg", ®); + if (ret || reg > 16) + continue; + + if (of_property_read_bool(child, "xlnx,bipolar")) + chan->scan_type.sign = 's'; + + if (reg == 0) { + chan->scan_index = 11; + chan->address = XADC_REG_VPVN; + } else { + chan->scan_index = 15 + reg; + chan->scan_index = XADC_REG_VAUX(reg - 1); + } + num_channels++; + chan++; + } + } + of_node_put(chan_node); + + indio_dev->num_channels = num_channels; + indio_dev->channels = krealloc(channels, sizeof(*channels) * + num_channels, GFP_KERNEL); + /* If we can't resize the channels array, just use the original */ + if (!indio_dev->channels) + indio_dev->channels = channels; + + return 0; +} + +static int xadc_probe(struct platform_device *pdev) +{ + const struct of_device_id *id; + struct iio_dev *indio_dev; + unsigned int bipolar_mask; + struct resource *mem; + unsigned int conf0; + struct xadc *xadc; + int ret; + int irq; + int i; + + if (!pdev->dev.of_node) + return -ENODEV; + + id = of_match_node(xadc_of_match_table, pdev->dev.of_node); + if (!id) + return -EINVAL; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) + return -ENXIO; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*xadc)); + if (!indio_dev) + return -ENOMEM; + + xadc = iio_priv(indio_dev); + xadc->ops = id->data; + init_completion(&xadc->completion); + mutex_init(&xadc->mutex); + spin_lock_init(&xadc->lock); + INIT_DELAYED_WORK(&xadc->zynq_unmask_work, xadc_zynq_unmask_worker); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xadc->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(xadc->base)) + return PTR_ERR(xadc->base); + + indio_dev->dev.parent = &pdev->dev; + indio_dev->dev.of_node = pdev->dev.of_node; + indio_dev->name = "xadc"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &xadc_info; + + ret = xadc_parse_dt(indio_dev, pdev->dev.of_node, &conf0); + if (ret) + goto err_device_free; + + if (xadc->ops->flags & XADC_FLAGS_BUFFERED) { + ret = iio_triggered_buffer_setup(indio_dev, + &iio_pollfunc_store_time, &xadc_trigger_handler, + &xadc_buffer_ops); + if (ret) + goto err_device_free; + + xadc->convst_trigger = xadc_alloc_trigger(indio_dev, "convst"); + if (IS_ERR(xadc->convst_trigger)) + goto err_triggered_buffer_cleanup; + xadc->samplerate_trigger = xadc_alloc_trigger(indio_dev, + "samplerate"); + if (IS_ERR(xadc->samplerate_trigger)) + goto err_free_convst_trigger; + } + + xadc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(xadc->clk)) { + ret = PTR_ERR(xadc->clk); + goto err_free_samplerate_trigger; + } + clk_prepare_enable(xadc->clk); + + ret = xadc->ops->setup(pdev, indio_dev, irq); + if (ret) + goto err_free_samplerate_trigger; + + ret = request_threaded_irq(irq, xadc->ops->interrupt_handler, + xadc->ops->threaded_interrupt_handler, + 0, dev_name(&pdev->dev), indio_dev); + if (ret) + goto err_clk_disable_unprepare; + + for (i = 0; i < 16; i++) + xadc_read_adc_reg(xadc, XADC_REG_THRESHOLD(i), + &xadc->threshold[i]); + + ret = xadc_write_adc_reg(xadc, XADC_REG_CONF0, conf0); + if (ret) + goto err_free_irq; + + bipolar_mask = 0; + for (i = 0; i < indio_dev->num_channels; i++) { + if (indio_dev->channels[i].scan_type.sign == 's') + bipolar_mask |= BIT(indio_dev->channels[i].scan_index); + } + + ret = xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(0), bipolar_mask); + if (ret) + goto err_free_irq; + ret = xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(1), + bipolar_mask >> 16); + if (ret) + goto err_free_irq; + + /* Disable all alarms */ + xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK, + XADC_CONF1_ALARM_MASK); + + /* Set thresholds to min/max */ + for (i = 0; i < 16; i++) { + /* + * Set max voltage threshold and both temperature thresholds to + * 0xffff, min voltage threshold to 0. + */ + if (i % 8 < 4 || i == 7) + xadc->threshold[i] = 0xffff; + else + xadc->threshold[i] = 0; + xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(i), + xadc->threshold[i]); + } + + /* Go to non-buffered mode */ + xadc_postdisable(indio_dev); + + ret = iio_device_register(indio_dev); + if (ret) + goto err_free_irq; + + platform_set_drvdata(pdev, indio_dev); + + return 0; + +err_free_irq: + free_irq(irq, indio_dev); +err_free_samplerate_trigger: + if (xadc->ops->flags & XADC_FLAGS_BUFFERED) + iio_trigger_free(xadc->samplerate_trigger); +err_free_convst_trigger: + if (xadc->ops->flags & XADC_FLAGS_BUFFERED) + iio_trigger_free(xadc->convst_trigger); +err_triggered_buffer_cleanup: + if (xadc->ops->flags & XADC_FLAGS_BUFFERED) + iio_triggered_buffer_cleanup(indio_dev); +err_clk_disable_unprepare: + clk_disable_unprepare(xadc->clk); +err_device_free: + kfree(indio_dev->channels); + + return ret; +} + +static int xadc_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct xadc *xadc = iio_priv(indio_dev); + int irq = platform_get_irq(pdev, 0); + + iio_device_unregister(indio_dev); + if (xadc->ops->flags & XADC_FLAGS_BUFFERED) { + iio_trigger_free(xadc->samplerate_trigger); + iio_trigger_free(xadc->convst_trigger); + iio_triggered_buffer_cleanup(indio_dev); + } + free_irq(irq, indio_dev); + clk_disable_unprepare(xadc->clk); + cancel_delayed_work(&xadc->zynq_unmask_work); + kfree(xadc->data); + kfree(indio_dev->channels); + + return 0; +} + +static struct platform_driver xadc_driver = { + .probe = xadc_probe, + .remove = xadc_remove, + .driver = { + .name = "xadc", + .owner = THIS_MODULE, + .of_match_table = xadc_of_match_table, + }, +}; +module_platform_driver(xadc_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("Xilinx XADC IIO driver"); diff --git a/drivers/iio/adc/xilinx-xadc-events.c b/drivers/iio/adc/xilinx-xadc-events.c new file mode 100644 index 000000000000..3e7f0d7a80c3 --- /dev/null +++ b/drivers/iio/adc/xilinx-xadc-events.c @@ -0,0 +1,254 @@ +/* + * Xilinx XADC driver + * + * Copyright 2013 Analog Devices Inc. + * Author: Lars-Peter Clauen + * + * Licensed under the GPL-2. + */ + +#include +#include +#include + +#include "xilinx-xadc.h" + +static const struct iio_chan_spec *xadc_event_to_channel( + struct iio_dev *indio_dev, unsigned int event) +{ + switch (event) { + case XADC_THRESHOLD_OT_MAX: + case XADC_THRESHOLD_TEMP_MAX: + return &indio_dev->channels[0]; + case XADC_THRESHOLD_VCCINT_MAX: + case XADC_THRESHOLD_VCCAUX_MAX: + return &indio_dev->channels[event]; + default: + return &indio_dev->channels[event-1]; + } +} + +static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event) +{ + const struct iio_chan_spec *chan; + unsigned int offset; + + /* Temperature threshold error, we don't handle this yet */ + if (event == 0) + return; + + if (event < 4) + offset = event; + else + offset = event + 4; + + chan = xadc_event_to_channel(indio_dev, event); + + if (chan->type == IIO_TEMP) { + /* + * The temperature channel only supports over-temperature + * events. + */ + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(chan->type, chan->channel, + IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), + iio_get_time_ns()); + } else { + /* + * For other channels we don't know whether it is a upper or + * lower threshold event. Userspace will have to check the + * channel value if it wants to know. + */ + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(chan->type, chan->channel, + IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER), + iio_get_time_ns()); + } +} + +void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events) +{ + unsigned int i; + + for_each_set_bit(i, &events, 8) + xadc_handle_event(indio_dev, i); +} + +static unsigned xadc_get_threshold_offset(const struct iio_chan_spec *chan, + enum iio_event_direction dir) +{ + unsigned int offset; + + if (chan->type == IIO_TEMP) { + offset = XADC_THRESHOLD_OT_MAX; + } else { + if (chan->channel < 2) + offset = chan->channel + 1; + else + offset = chan->channel + 6; + } + + if (dir == IIO_EV_DIR_FALLING) + offset += 4; + + return offset; +} + +static unsigned int xadc_get_alarm_mask(const struct iio_chan_spec *chan) +{ + if (chan->type == IIO_TEMP) { + return XADC_ALARM_OT_MASK; + } else { + switch (chan->channel) { + case 0: + return XADC_ALARM_VCCINT_MASK; + case 1: + return XADC_ALARM_VCCAUX_MASK; + case 2: + return XADC_ALARM_VCCBRAM_MASK; + case 3: + return XADC_ALARM_VCCPINT_MASK; + case 4: + return XADC_ALARM_VCCPAUX_MASK; + case 5: + return XADC_ALARM_VCCODDR_MASK; + default: + /* We will never get here */ + return 0; + } + } +} + +int xadc_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir) +{ + struct xadc *xadc = iio_priv(indio_dev); + + return (bool)(xadc->alarm_mask & xadc_get_alarm_mask(chan)); +} + +int xadc_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, int state) +{ + unsigned int alarm = xadc_get_alarm_mask(chan); + struct xadc *xadc = iio_priv(indio_dev); + uint16_t cfg, old_cfg; + int ret; + + mutex_lock(&xadc->mutex); + + if (state) + xadc->alarm_mask |= alarm; + else + xadc->alarm_mask &= ~alarm; + + xadc->ops->update_alarm(xadc, xadc->alarm_mask); + + ret = _xadc_read_adc_reg(xadc, XADC_REG_CONF1, &cfg); + if (ret) + goto err_out; + + old_cfg = cfg; + cfg |= XADC_CONF1_ALARM_MASK; + cfg &= ~((xadc->alarm_mask & 0xf0) << 4); /* bram, pint, paux, ddr */ + cfg &= ~((xadc->alarm_mask & 0x08) >> 3); /* ot */ + cfg &= ~((xadc->alarm_mask & 0x07) << 1); /* temp, vccint, vccaux */ + if (old_cfg != cfg) + ret = _xadc_write_adc_reg(xadc, XADC_REG_CONF1, cfg); + +err_out: + mutex_unlock(&xadc->mutex); + + return ret; +} + +/* Register value is msb aligned, the lower 4 bits are ignored */ +#define XADC_THRESHOLD_VALUE_SHIFT 4 + +int xadc_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, + int *val, int *val2) +{ + unsigned int offset = xadc_get_threshold_offset(chan, dir); + struct xadc *xadc = iio_priv(indio_dev); + + switch (info) { + case IIO_EV_INFO_VALUE: + *val = xadc->threshold[offset]; + break; + case IIO_EV_INFO_HYSTERESIS: + *val = xadc->temp_hysteresis; + break; + default: + return -EINVAL; + } + + *val >>= XADC_THRESHOLD_VALUE_SHIFT; + + return IIO_VAL_INT; +} + +int xadc_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, + int val, int val2) +{ + unsigned int offset = xadc_get_threshold_offset(chan, dir); + struct xadc *xadc = iio_priv(indio_dev); + int ret = 0; + + val <<= XADC_THRESHOLD_VALUE_SHIFT; + + if (val < 0 || val > 0xffff) + return -EINVAL; + + mutex_lock(&xadc->mutex); + + switch (info) { + case IIO_EV_INFO_VALUE: + xadc->threshold[offset] = val; + break; + case IIO_EV_INFO_HYSTERESIS: + xadc->temp_hysteresis = val; + break; + default: + mutex_unlock(&xadc->mutex); + return -EINVAL; + } + + if (chan->type == IIO_TEMP) { + /* + * According to the datasheet we need to set the lower 4 bits to + * 0x3, otherwise 125 degree celsius will be used as the + * threshold. + */ + val |= 0x3; + + /* + * Since we store the hysteresis as relative (to the threshold) + * value, but the hardware expects an absolute value we need to + * recalcualte this value whenever the hysteresis or the + * threshold changes. + */ + if (xadc->threshold[offset] < xadc->temp_hysteresis) + xadc->threshold[offset + 4] = 0; + else + xadc->threshold[offset + 4] = xadc->threshold[offset] - + xadc->temp_hysteresis; + ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset + 4), + xadc->threshold[offset + 4]); + if (ret) + goto out_unlock; + } + + if (info == IIO_EV_INFO_VALUE) + ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset), val); + +out_unlock: + mutex_unlock(&xadc->mutex); + + return ret; +} diff --git a/drivers/iio/adc/xilinx-xadc.h b/drivers/iio/adc/xilinx-xadc.h new file mode 100644 index 000000000000..c7487e8d7f80 --- /dev/null +++ b/drivers/iio/adc/xilinx-xadc.h @@ -0,0 +1,209 @@ +/* + * Xilinx XADC driver + * + * Copyright 2013 Analog Devices Inc. + * Author: Lars-Peter Clauen + * + * Licensed under the GPL-2. + */ + +#ifndef __IIO_XILINX_XADC__ +#define __IIO_XILINX_XADC__ + +#include +#include +#include + +struct iio_dev; +struct clk; +struct xadc_ops; +struct platform_device; + +void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events); + +int xadc_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir); +int xadc_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, int state); +int xadc_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, + int *val, int *val2); +int xadc_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, + int val, int val2); + +enum xadc_external_mux_mode { + XADC_EXTERNAL_MUX_NONE, + XADC_EXTERNAL_MUX_SINGLE, + XADC_EXTERNAL_MUX_DUAL, +}; + +struct xadc { + void __iomem *base; + struct clk *clk; + + const struct xadc_ops *ops; + + uint16_t threshold[16]; + uint16_t temp_hysteresis; + unsigned int alarm_mask; + + uint16_t *data; + + struct iio_trigger *trigger; + struct iio_trigger *convst_trigger; + struct iio_trigger *samplerate_trigger; + + enum xadc_external_mux_mode external_mux_mode; + + unsigned int zynq_alarm; + unsigned int zynq_masked_alarm; + unsigned int zynq_intmask; + struct delayed_work zynq_unmask_work; + + struct mutex mutex; + spinlock_t lock; + + struct completion completion; +}; + +struct xadc_ops { + int (*read)(struct xadc *, unsigned int, uint16_t *); + int (*write)(struct xadc *, unsigned int, uint16_t); + int (*setup)(struct platform_device *pdev, struct iio_dev *indio_dev, + int irq); + void (*update_alarm)(struct xadc *, unsigned int); + unsigned long (*get_dclk_rate)(struct xadc *); + irqreturn_t (*interrupt_handler)(int, void *); + irqreturn_t (*threaded_interrupt_handler)(int, void *); + + unsigned int flags; +}; + +static inline int _xadc_read_adc_reg(struct xadc *xadc, unsigned int reg, + uint16_t *val) +{ + lockdep_assert_held(&xadc->mutex); + return xadc->ops->read(xadc, reg, val); +} + +static inline int _xadc_write_adc_reg(struct xadc *xadc, unsigned int reg, + uint16_t val) +{ + lockdep_assert_held(&xadc->mutex); + return xadc->ops->write(xadc, reg, val); +} + +static inline int xadc_read_adc_reg(struct xadc *xadc, unsigned int reg, + uint16_t *val) +{ + int ret; + + mutex_lock(&xadc->mutex); + ret = _xadc_read_adc_reg(xadc, reg, val); + mutex_unlock(&xadc->mutex); + return ret; +} + +static inline int xadc_write_adc_reg(struct xadc *xadc, unsigned int reg, + uint16_t val) +{ + int ret; + + mutex_lock(&xadc->mutex); + ret = _xadc_write_adc_reg(xadc, reg, val); + mutex_unlock(&xadc->mutex); + return ret; +} + +/* XADC hardmacro register definitions */ +#define XADC_REG_TEMP 0x00 +#define XADC_REG_VCCINT 0x01 +#define XADC_REG_VCCAUX 0x02 +#define XADC_REG_VPVN 0x03 +#define XADC_REG_VREFP 0x04 +#define XADC_REG_VREFN 0x05 +#define XADC_REG_VCCBRAM 0x06 + +#define XADC_REG_VCCPINT 0x0d +#define XADC_REG_VCCPAUX 0x0e +#define XADC_REG_VCCO_DDR 0x0f +#define XADC_REG_VAUX(x) (0x10 + (x)) + +#define XADC_REG_MAX_TEMP 0x20 +#define XADC_REG_MAX_VCCINT 0x21 +#define XADC_REG_MAX_VCCAUX 0x22 +#define XADC_REG_MAX_VCCBRAM 0x23 +#define XADC_REG_MIN_TEMP 0x24 +#define XADC_REG_MIN_VCCINT 0x25 +#define XADC_REG_MIN_VCCAUX 0x26 +#define XADC_REG_MIN_VCCBRAM 0x27 +#define XADC_REG_MAX_VCCPINT 0x28 +#define XADC_REG_MAX_VCCPAUX 0x29 +#define XADC_REG_MAX_VCCO_DDR 0x2a +#define XADC_REG_MIN_VCCPINT 0x2b +#define XADC_REG_MIN_VCCPAUX 0x2c +#define XADC_REG_MIN_VCCO_DDR 0x2d + +#define XADC_REG_CONF0 0x40 +#define XADC_REG_CONF1 0x41 +#define XADC_REG_CONF2 0x42 +#define XADC_REG_SEQ(x) (0x48 + (x)) +#define XADC_REG_INPUT_MODE(x) (0x4c + (x)) +#define XADC_REG_THRESHOLD(x) (0x50 + (x)) + +#define XADC_REG_FLAG 0x3f + +#define XADC_CONF0_EC BIT(9) +#define XADC_CONF0_ACQ BIT(8) +#define XADC_CONF0_MUX BIT(11) +#define XADC_CONF0_CHAN(x) (x) + +#define XADC_CONF1_SEQ_MASK (0xf << 12) +#define XADC_CONF1_SEQ_DEFAULT (0 << 12) +#define XADC_CONF1_SEQ_SINGLE_PASS (1 << 12) +#define XADC_CONF1_SEQ_CONTINUOUS (2 << 12) +#define XADC_CONF1_SEQ_SINGLE_CHANNEL (3 << 12) +#define XADC_CONF1_SEQ_SIMULTANEOUS (4 << 12) +#define XADC_CONF1_SEQ_INDEPENDENT (8 << 12) +#define XADC_CONF1_ALARM_MASK 0x0f0f + +#define XADC_CONF2_DIV_MASK 0xff00 +#define XADC_CONF2_DIV_OFFSET 8 + +#define XADC_CONF2_PD_MASK (0x3 << 4) +#define XADC_CONF2_PD_NONE (0x0 << 4) +#define XADC_CONF2_PD_ADC_B (0x2 << 4) +#define XADC_CONF2_PD_BOTH (0x3 << 4) + +#define XADC_ALARM_TEMP_MASK BIT(0) +#define XADC_ALARM_VCCINT_MASK BIT(1) +#define XADC_ALARM_VCCAUX_MASK BIT(2) +#define XADC_ALARM_OT_MASK BIT(3) +#define XADC_ALARM_VCCBRAM_MASK BIT(4) +#define XADC_ALARM_VCCPINT_MASK BIT(5) +#define XADC_ALARM_VCCPAUX_MASK BIT(6) +#define XADC_ALARM_VCCODDR_MASK BIT(7) + +#define XADC_THRESHOLD_TEMP_MAX 0x0 +#define XADC_THRESHOLD_VCCINT_MAX 0x1 +#define XADC_THRESHOLD_VCCAUX_MAX 0x2 +#define XADC_THRESHOLD_OT_MAX 0x3 +#define XADC_THRESHOLD_TEMP_MIN 0x4 +#define XADC_THRESHOLD_VCCINT_MIN 0x5 +#define XADC_THRESHOLD_VCCAUX_MIN 0x6 +#define XADC_THRESHOLD_OT_MIN 0x7 +#define XADC_THRESHOLD_VCCBRAM_MAX 0x8 +#define XADC_THRESHOLD_VCCPINT_MAX 0x9 +#define XADC_THRESHOLD_VCCPAUX_MAX 0xa +#define XADC_THRESHOLD_VCCODDR_MAX 0xb +#define XADC_THRESHOLD_VCCBRAM_MIN 0xc +#define XADC_THRESHOLD_VCCPINT_MIN 0xd +#define XADC_THRESHOLD_VCCPAUX_MIN 0xe +#define XADC_THRESHOLD_VCCODDR_MIN 0xf + +#endif diff --git a/drivers/iio/buffer_cb.c b/drivers/iio/buffer_cb.c index 2d9c6f8c06db..eb46e728aa2e 100644 --- a/drivers/iio/buffer_cb.c +++ b/drivers/iio/buffer_cb.c @@ -46,10 +46,8 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, struct iio_channel *chan; cb_buff = kzalloc(sizeof(*cb_buff), GFP_KERNEL); - if (cb_buff == NULL) { - ret = -ENOMEM; - goto error_ret; - } + if (cb_buff == NULL) + return ERR_PTR(-ENOMEM); iio_buffer_init(&cb_buff->buffer); @@ -91,7 +89,6 @@ error_release_channels: iio_channel_release_all(cb_buff->channels); error_free_cb_buff: kfree(cb_buff); -error_ret: return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(iio_channel_get_all_cb); diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c index d0505fd22ef4..fa2810032968 100644 --- a/drivers/iio/dac/ad7303.c +++ b/drivers/iio/dac/ad7303.c @@ -92,7 +92,7 @@ static ssize_t ad7303_write_dac_powerdown(struct iio_dev *indio_dev, ad7303_write(st, chan->channel, st->dac_cache[chan->channel]); mutex_unlock(&indio_dev->mlock); - return ret ? ret : len; + return len; } static int ad7303_get_vref(struct ad7303_state *st, diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c index de76e6a34c1e..9a82a7255ebb 100644 --- a/drivers/iio/dac/max517.c +++ b/drivers/iio/dac/max517.c @@ -19,7 +19,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index 7d9f5c31d2fc..43d14588448d 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig index 463c4d9da79e..e116bd8dd0e4 100644 --- a/drivers/iio/humidity/Kconfig +++ b/drivers/iio/humidity/Kconfig @@ -12,4 +12,14 @@ config DHT11 Other sensors should work as well as long as they speak the same protocol. +config SI7005 + tristate "SI7005 relative humidity and temperature sensor" + depends on I2C + help + Say yes here to build support for the Silabs Si7005 relative + humidity and temperature sensor. + + To compile this driver as a module, choose M here: the module + will be called si7005. + endmenu diff --git a/drivers/iio/humidity/Makefile b/drivers/iio/humidity/Makefile index d5d36c0c95f9..e3f3d942e646 100644 --- a/drivers/iio/humidity/Makefile +++ b/drivers/iio/humidity/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_DHT11) += dht11.o +obj-$(CONFIG_SI7005) += si7005.o diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c new file mode 100644 index 000000000000..bdd586e6d955 --- /dev/null +++ b/drivers/iio/humidity/si7005.c @@ -0,0 +1,189 @@ +/* + * si7005.c - Support for Silabs Si7005 humidity and temperature sensor + * + * Copyright (c) 2014 Peter Meerwald + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * (7-bit I2C slave address 0x40) + * + * TODO: heater, fast mode, processed mode (temp. / linearity compensation) + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define SI7005_STATUS 0x00 +#define SI7005_DATA 0x01 /* 16-bit, MSB */ +#define SI7005_CONFIG 0x03 +#define SI7005_ID 0x11 + +#define SI7005_STATUS_NRDY BIT(0) +#define SI7005_CONFIG_TEMP BIT(4) +#define SI7005_CONFIG_START BIT(0) + +#define SI7005_ID_7005 0x50 +#define SI7005_ID_7015 0xf0 + +struct si7005_data { + struct i2c_client *client; + struct mutex lock; + u8 config; +}; + +static int si7005_read_measurement(struct si7005_data *data, bool temp) +{ + int tries = 50; + int ret; + + mutex_lock(&data->lock); + + ret = i2c_smbus_write_byte_data(data->client, SI7005_CONFIG, + data->config | SI7005_CONFIG_START | + (temp ? SI7005_CONFIG_TEMP : 0)); + if (ret < 0) + goto done; + + while (tries-- > 0) { + msleep(20); + ret = i2c_smbus_read_byte_data(data->client, SI7005_STATUS); + if (ret < 0) + goto done; + if (!(ret & SI7005_STATUS_NRDY)) + break; + } + if (tries < 0) { + ret = -EIO; + goto done; + } + + ret = i2c_smbus_read_word_swapped(data->client, SI7005_DATA); + +done: + mutex_unlock(&data->lock); + + return ret; +} + +static int si7005_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct si7005_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = si7005_read_measurement(data, chan->type == IIO_TEMP); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + if (chan->type == IIO_TEMP) { + *val = 7; + *val2 = 812500; + } else { + *val = 3; + *val2 = 906250; + } + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + if (chan->type == IIO_TEMP) + *val = -50 * 32 * 4; + else + *val = -24 * 16 * 16; + return IIO_VAL_INT; + default: + break; + } + + return -EINVAL; +} + +static const struct iio_chan_spec si7005_channels[] = { + { + .type = IIO_HUMIDITYRELATIVE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), + }, + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), + } +}; + +static const struct iio_info si7005_info = { + .read_raw = si7005_read_raw, + .driver_module = THIS_MODULE, +}; + +static int si7005_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct si7005_data *data; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + mutex_init(&data->lock); + + indio_dev->dev.parent = &client->dev; + indio_dev->name = dev_name(&client->dev); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &si7005_info; + + indio_dev->channels = si7005_channels; + indio_dev->num_channels = ARRAY_SIZE(si7005_channels); + + ret = i2c_smbus_read_byte_data(client, SI7005_ID); + if (ret < 0) + return ret; + if (ret != SI7005_ID_7005 && ret != SI7005_ID_7015) + return -ENODEV; + + ret = i2c_smbus_read_byte_data(client, SI7005_CONFIG); + if (ret < 0) + return ret; + data->config = ret; + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct i2c_device_id si7005_id[] = { + { "si7005", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, si7005_id); + +static struct i2c_driver si7005_driver = { + .driver = { + .name = "si7005", + .owner = THIS_MODULE, + }, + .probe = si7005_probe, + .id_table = si7005_id, +}; +module_i2c_driver(si7005_driver); + +MODULE_AUTHOR("Peter Meerwald "); +MODULE_DESCRIPTION("Silabs Si7005 humidity and temperature sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 663e88a1a3c1..2b0e45133e9d 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -25,6 +25,8 @@ config ADIS16480 Say yes here to build support for Analog Devices ADIS16375, ADIS16480, ADIS16485, ADIS16488 inertial sensors. +source "drivers/iio/imu/inv_mpu6050/Kconfig" + endmenu config IIO_ADIS_LIB @@ -38,5 +40,3 @@ config IIO_ADIS_LIB_BUFFER help A set of buffer helper functions for the Analog Devices ADIS* device family. - -source "drivers/iio/imu/inv_mpu6050/Kconfig" diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index 7c582f7ae34e..433583b6f800 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -281,7 +281,7 @@ static ssize_t adis16400_write_frequency(struct device *dev, st->variant->set_freq(st, val); mutex_unlock(&indio_dev->mlock); - return ret ? ret : len; + return len; } /* Power down the device */ diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index df7f1e1157ae..cb9f96b446a5 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -12,7 +12,6 @@ */ #include -#include #include #include #include @@ -117,7 +116,7 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask) return result; if (en) { - /* Wait for output stablize */ + /* Wait for output stabilize */ msleep(INV_MPU6050_TEMP_UP_TIME); if (INV_MPU6050_BIT_PWR_GYRO_STBY == mask) { /* switch internal clock to PLL */ diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index f38395529a44..0ab382be1e64 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -126,35 +126,35 @@ struct inv_mpu6050_state { #define INV_MPU6050_REG_SAMPLE_RATE_DIV 0x19 #define INV_MPU6050_REG_CONFIG 0x1A #define INV_MPU6050_REG_GYRO_CONFIG 0x1B -#define INV_MPU6050_REG_ACCEL_CONFIG 0x1C +#define INV_MPU6050_REG_ACCEL_CONFIG 0x1C #define INV_MPU6050_REG_FIFO_EN 0x23 -#define INV_MPU6050_BIT_ACCEL_OUT 0x08 -#define INV_MPU6050_BITS_GYRO_OUT 0x70 +#define INV_MPU6050_BIT_ACCEL_OUT 0x08 +#define INV_MPU6050_BITS_GYRO_OUT 0x70 #define INV_MPU6050_REG_INT_ENABLE 0x38 -#define INV_MPU6050_BIT_DATA_RDY_EN 0x01 -#define INV_MPU6050_BIT_DMP_INT_EN 0x02 +#define INV_MPU6050_BIT_DATA_RDY_EN 0x01 +#define INV_MPU6050_BIT_DMP_INT_EN 0x02 #define INV_MPU6050_REG_RAW_ACCEL 0x3B #define INV_MPU6050_REG_TEMPERATURE 0x41 #define INV_MPU6050_REG_RAW_GYRO 0x43 #define INV_MPU6050_REG_USER_CTRL 0x6A -#define INV_MPU6050_BIT_FIFO_RST 0x04 -#define INV_MPU6050_BIT_DMP_RST 0x08 -#define INV_MPU6050_BIT_I2C_MST_EN 0x20 -#define INV_MPU6050_BIT_FIFO_EN 0x40 -#define INV_MPU6050_BIT_DMP_EN 0x80 +#define INV_MPU6050_BIT_FIFO_RST 0x04 +#define INV_MPU6050_BIT_DMP_RST 0x08 +#define INV_MPU6050_BIT_I2C_MST_EN 0x20 +#define INV_MPU6050_BIT_FIFO_EN 0x40 +#define INV_MPU6050_BIT_DMP_EN 0x80 #define INV_MPU6050_REG_PWR_MGMT_1 0x6B -#define INV_MPU6050_BIT_H_RESET 0x80 -#define INV_MPU6050_BIT_SLEEP 0x40 -#define INV_MPU6050_BIT_CLK_MASK 0x7 +#define INV_MPU6050_BIT_H_RESET 0x80 +#define INV_MPU6050_BIT_SLEEP 0x40 +#define INV_MPU6050_BIT_CLK_MASK 0x7 #define INV_MPU6050_REG_PWR_MGMT_2 0x6C -#define INV_MPU6050_BIT_PWR_ACCL_STBY 0x38 -#define INV_MPU6050_BIT_PWR_GYRO_STBY 0x07 +#define INV_MPU6050_BIT_PWR_ACCL_STBY 0x38 +#define INV_MPU6050_BIT_PWR_GYRO_STBY 0x07 #define INV_MPU6050_REG_FIFO_COUNT_H 0x72 #define INV_MPU6050_REG_FIFO_R_W 0x74 @@ -180,10 +180,10 @@ struct inv_mpu6050_state { /* init parameters */ #define INV_MPU6050_INIT_FIFO_RATE 50 -#define INV_MPU6050_TIME_STAMP_TOR 5 -#define INV_MPU6050_MAX_FIFO_RATE 1000 -#define INV_MPU6050_MIN_FIFO_RATE 4 -#define INV_MPU6050_ONE_K_HZ 1000 +#define INV_MPU6050_TIME_STAMP_TOR 5 +#define INV_MPU6050_MAX_FIFO_RATE 1000 +#define INV_MPU6050_MIN_FIFO_RATE 4 +#define INV_MPU6050_ONE_K_HZ 1000 /* scan element definition */ enum inv_mpu6050_scan { diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index 429517117eff..0cd306a72a6e 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -12,7 +12,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index c67d83bdc8f0..e108f2a9d827 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -264,7 +264,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, &indio_dev->dev, &buffer->scan_el_dev_attr_list); if (ret) - goto error_ret; + return ret; attrcount++; ret = __iio_add_chan_devattr("type", chan, @@ -275,7 +275,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, &indio_dev->dev, &buffer->scan_el_dev_attr_list); if (ret) - goto error_ret; + return ret; attrcount++; if (chan->type != IIO_TIMESTAMP) ret = __iio_add_chan_devattr("en", @@ -296,10 +296,9 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, &indio_dev->dev, &buffer->scan_el_dev_attr_list); if (ret) - goto error_ret; + return ret; attrcount++; ret = attrcount; -error_ret: return ret; } @@ -553,13 +552,13 @@ static int __iio_update_buffers(struct iio_dev *indio_dev, if (indio_dev->setup_ops->predisable) { ret = indio_dev->setup_ops->predisable(indio_dev); if (ret) - goto error_ret; + return ret; } indio_dev->currentmode = INDIO_DIRECT_MODE; if (indio_dev->setup_ops->postdisable) { ret = indio_dev->setup_ops->postdisable(indio_dev); if (ret) - goto error_ret; + return ret; } } /* Keep a copy of current setup to allow roll back */ @@ -613,7 +612,7 @@ static int __iio_update_buffers(struct iio_dev *indio_dev, else { kfree(compound_mask); ret = -EINVAL; - goto error_ret; + return ret; } } } else { @@ -696,13 +695,10 @@ error_run_postdisable: if (indio_dev->setup_ops->postdisable) indio_dev->setup_ops->postdisable(indio_dev); error_remove_inserted: - if (insert_buffer) iio_buffer_deactivate(insert_buffer); indio_dev->active_scan_mask = old_mask; kfree(compound_mask); -error_ret: - return ret; } diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index acc911a836ca..ede16aec20fb 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -540,7 +540,7 @@ int __iio_device_attr_init(struct device_attribute *dev_attr, enum iio_shared_by shared_by) { int ret = 0; - char *name_format = NULL; + char *name = NULL; char *full_postfix; sysfs_attr_init(&dev_attr->attr); @@ -558,7 +558,7 @@ int __iio_device_attr_init(struct device_attribute *dev_attr, ->channel2], postfix); } else { - if (chan->extend_name == NULL) + if (chan->extend_name == NULL || shared_by != IIO_SEPARATE) full_postfix = kstrdup(postfix, GFP_KERNEL); else full_postfix = kasprintf(GFP_KERNEL, @@ -572,16 +572,15 @@ int __iio_device_attr_init(struct device_attribute *dev_attr, if (chan->differential) { /* Differential can not have modifier */ switch (shared_by) { case IIO_SHARED_BY_ALL: - name_format = kasprintf(GFP_KERNEL, "%s", full_postfix); + name = kasprintf(GFP_KERNEL, "%s", full_postfix); break; case IIO_SHARED_BY_DIR: - name_format = kasprintf(GFP_KERNEL, "%s_%s", + name = kasprintf(GFP_KERNEL, "%s_%s", iio_direction[chan->output], full_postfix); break; case IIO_SHARED_BY_TYPE: - name_format - = kasprintf(GFP_KERNEL, "%s_%s-%s_%s", + name = kasprintf(GFP_KERNEL, "%s_%s-%s_%s", iio_direction[chan->output], iio_chan_type_name_spec[chan->type], iio_chan_type_name_spec[chan->type], @@ -593,8 +592,7 @@ int __iio_device_attr_init(struct device_attribute *dev_attr, ret = -EINVAL; goto error_free_full_postfix; } - name_format - = kasprintf(GFP_KERNEL, + name = kasprintf(GFP_KERNEL, "%s_%s%d-%s%d_%s", iio_direction[chan->output], iio_chan_type_name_spec[chan->type], @@ -607,16 +605,15 @@ int __iio_device_attr_init(struct device_attribute *dev_attr, } else { /* Single ended */ switch (shared_by) { case IIO_SHARED_BY_ALL: - name_format = kasprintf(GFP_KERNEL, "%s", full_postfix); + name = kasprintf(GFP_KERNEL, "%s", full_postfix); break; case IIO_SHARED_BY_DIR: - name_format = kasprintf(GFP_KERNEL, "%s_%s", + name = kasprintf(GFP_KERNEL, "%s_%s", iio_direction[chan->output], full_postfix); break; case IIO_SHARED_BY_TYPE: - name_format - = kasprintf(GFP_KERNEL, "%s_%s_%s", + name = kasprintf(GFP_KERNEL, "%s_%s_%s", iio_direction[chan->output], iio_chan_type_name_spec[chan->type], full_postfix); @@ -624,33 +621,24 @@ int __iio_device_attr_init(struct device_attribute *dev_attr, case IIO_SEPARATE: if (chan->indexed) - name_format - = kasprintf(GFP_KERNEL, "%s_%s%d_%s", + name = kasprintf(GFP_KERNEL, "%s_%s%d_%s", iio_direction[chan->output], iio_chan_type_name_spec[chan->type], chan->channel, full_postfix); else - name_format - = kasprintf(GFP_KERNEL, "%s_%s_%s", + name = kasprintf(GFP_KERNEL, "%s_%s_%s", iio_direction[chan->output], iio_chan_type_name_spec[chan->type], full_postfix); break; } } - if (name_format == NULL) { + if (name == NULL) { ret = -ENOMEM; goto error_free_full_postfix; } - dev_attr->attr.name = kasprintf(GFP_KERNEL, - name_format, - chan->channel, - chan->channel2); - if (dev_attr->attr.name == NULL) { - ret = -ENOMEM; - goto error_free_name_format; - } + dev_attr->attr.name = name; if (readfunc) { dev_attr->attr.mode |= S_IRUGO; @@ -661,8 +649,7 @@ int __iio_device_attr_init(struct device_attribute *dev_attr, dev_attr->attr.mode |= S_IWUSR; dev_attr->store = writefunc; } -error_free_name_format: - kfree(name_format); + error_free_full_postfix: kfree(full_postfix); @@ -692,10 +679,8 @@ int __iio_add_chan_devattr(const char *postfix, struct iio_dev_attr *iio_attr, *t; iio_attr = kzalloc(sizeof(*iio_attr), GFP_KERNEL); - if (iio_attr == NULL) { - ret = -ENOMEM; - goto error_ret; - } + if (iio_attr == NULL) + return -ENOMEM; ret = __iio_device_attr_init(&iio_attr->dev_attr, postfix, chan, readfunc, writefunc, shared_by); @@ -720,7 +705,6 @@ error_device_attr_deinit: __iio_device_attr_deinit(&iio_attr->dev_attr); error_iio_dev_attr_free: kfree(iio_attr); -error_ret: return ret; } @@ -1134,7 +1118,7 @@ int iio_device_register(struct iio_dev *indio_dev) if (ret) { dev_err(indio_dev->dev.parent, "Failed to register debugfs interfaces\n"); - goto error_ret; + return ret; } ret = iio_device_register_sysfs(indio_dev); if (ret) { @@ -1175,7 +1159,6 @@ error_free_sysfs: iio_device_unregister_sysfs(indio_dev); error_unreg_debugfs: iio_device_unregister_debugfs(indio_dev); -error_ret: return ret; } EXPORT_SYMBOL(iio_device_register); diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index c9c1419fe6e0..ea6e06b9c7d4 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -40,6 +40,7 @@ struct iio_event_interface { struct list_head dev_attr_list; unsigned long flags; struct attribute_group group; + struct mutex read_lock; }; /** @@ -47,16 +48,17 @@ struct iio_event_interface { * @indio_dev: IIO device structure * @ev_code: What event * @timestamp: When the event occurred + * + * Note: The caller must make sure that this function is not running + * concurrently for the same indio_dev more than once. **/ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp) { struct iio_event_interface *ev_int = indio_dev->event_interface; struct iio_event_data ev; - unsigned long flags; int copied; /* Does anyone care? */ - spin_lock_irqsave(&ev_int->wait.lock, flags); if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) { ev.id = ev_code; @@ -64,9 +66,8 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp) copied = kfifo_put(&ev_int->det_events, ev); if (copied != 0) - wake_up_locked_poll(&ev_int->wait, POLLIN); + wake_up_poll(&ev_int->wait, POLLIN); } - spin_unlock_irqrestore(&ev_int->wait.lock, flags); return 0; } @@ -87,10 +88,8 @@ static unsigned int iio_event_poll(struct file *filep, poll_wait(filep, &ev_int->wait, wait); - spin_lock_irq(&ev_int->wait.lock); if (!kfifo_is_empty(&ev_int->det_events)) events = POLLIN | POLLRDNORM; - spin_unlock_irq(&ev_int->wait.lock); return events; } @@ -111,31 +110,40 @@ static ssize_t iio_event_chrdev_read(struct file *filep, if (count < sizeof(struct iio_event_data)) return -EINVAL; - spin_lock_irq(&ev_int->wait.lock); - if (kfifo_is_empty(&ev_int->det_events)) { - if (filep->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto error_unlock; - } - /* Blocking on device; waiting for something to be there */ - ret = wait_event_interruptible_locked_irq(ev_int->wait, + do { + if (kfifo_is_empty(&ev_int->det_events)) { + if (filep->f_flags & O_NONBLOCK) + return -EAGAIN; + + ret = wait_event_interruptible(ev_int->wait, !kfifo_is_empty(&ev_int->det_events) || indio_dev->info == NULL); - if (ret) - goto error_unlock; - if (indio_dev->info == NULL) { - ret = -ENODEV; - goto error_unlock; + if (ret) + return ret; + if (indio_dev->info == NULL) + return -ENODEV; } - /* Single access device so no one else can get the data */ - } - ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied); + if (mutex_lock_interruptible(&ev_int->read_lock)) + return -ERESTARTSYS; + ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied); + mutex_unlock(&ev_int->read_lock); -error_unlock: - spin_unlock_irq(&ev_int->wait.lock); + if (ret) + return ret; - return ret ? ret : copied; + /* + * If we couldn't read anything from the fifo (a different + * thread might have been faster) we either return -EAGAIN if + * the file descriptor is non-blocking, otherwise we go back to + * sleep and wait for more data to arrive. + */ + if (copied == 0 && (filep->f_flags & O_NONBLOCK)) + return -EAGAIN; + + } while (copied == 0); + + return copied; } static int iio_event_chrdev_release(struct inode *inode, struct file *filep) @@ -143,15 +151,7 @@ static int iio_event_chrdev_release(struct inode *inode, struct file *filep) struct iio_dev *indio_dev = filep->private_data; struct iio_event_interface *ev_int = indio_dev->event_interface; - spin_lock_irq(&ev_int->wait.lock); - __clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags); - /* - * In order to maintain a clean state for reopening, - * clear out any awaiting events. The mask will prevent - * any new __iio_push_event calls running. - */ - kfifo_reset_out(&ev_int->det_events); - spin_unlock_irq(&ev_int->wait.lock); + clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags); iio_device_put(indio_dev); @@ -174,22 +174,20 @@ int iio_event_getfd(struct iio_dev *indio_dev) if (ev_int == NULL) return -ENODEV; - spin_lock_irq(&ev_int->wait.lock); - if (__test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) { - spin_unlock_irq(&ev_int->wait.lock); + if (test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) return -EBUSY; - } - spin_unlock_irq(&ev_int->wait.lock); + iio_device_get(indio_dev); fd = anon_inode_getfd("iio:event", &iio_event_chrdev_fileops, indio_dev, O_RDONLY | O_CLOEXEC); if (fd < 0) { - spin_lock_irq(&ev_int->wait.lock); - __clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags); - spin_unlock_irq(&ev_int->wait.lock); + clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags); iio_device_put(indio_dev); + } else { + kfifo_reset_out(&ev_int->det_events); } + return fd; } @@ -366,32 +364,31 @@ static int iio_device_add_event_sysfs(struct iio_dev *indio_dev, ret = iio_device_add_event(indio_dev, chan, i, type, dir, IIO_SEPARATE, &chan->event_spec[i].mask_separate); if (ret < 0) - goto error_ret; + return ret; attrcount += ret; ret = iio_device_add_event(indio_dev, chan, i, type, dir, IIO_SHARED_BY_TYPE, &chan->event_spec[i].mask_shared_by_type); if (ret < 0) - goto error_ret; + return ret; attrcount += ret; ret = iio_device_add_event(indio_dev, chan, i, type, dir, IIO_SHARED_BY_DIR, &chan->event_spec[i].mask_shared_by_dir); if (ret < 0) - goto error_ret; + return ret; attrcount += ret; ret = iio_device_add_event(indio_dev, chan, i, type, dir, IIO_SHARED_BY_ALL, &chan->event_spec[i].mask_shared_by_all); if (ret < 0) - goto error_ret; + return ret; attrcount += ret; } ret = attrcount; -error_ret: return ret; } @@ -425,6 +422,7 @@ static void iio_setup_ev_int(struct iio_event_interface *ev_int) { INIT_KFIFO(ev_int->det_events); init_waitqueue_head(&ev_int->wait); + mutex_init(&ev_int->read_lock); } static const char *iio_event_group_name = "events"; @@ -440,10 +438,8 @@ int iio_device_register_eventset(struct iio_dev *indio_dev) indio_dev->event_interface = kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL); - if (indio_dev->event_interface == NULL) { - ret = -ENOMEM; - goto error_ret; - } + if (indio_dev->event_interface == NULL) + return -ENOMEM; INIT_LIST_HEAD(&indio_dev->event_interface->dev_attr_list); @@ -489,8 +485,6 @@ int iio_device_register_eventset(struct iio_dev *indio_dev) error_free_setup_event_lines: iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list); kfree(indio_dev->event_interface); -error_ret: - return ret; } diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 766fab24b720..3383b025f62e 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -62,10 +62,9 @@ int iio_trigger_register(struct iio_trigger *trig_info) int ret; trig_info->id = ida_simple_get(&iio_trigger_ida, 0, 0, GFP_KERNEL); - if (trig_info->id < 0) { - ret = trig_info->id; - goto error_ret; - } + if (trig_info->id < 0) + return trig_info->id; + /* Set the name used for the sysfs directory etc */ dev_set_name(&trig_info->dev, "trigger%ld", (unsigned long) trig_info->id); @@ -83,7 +82,6 @@ int iio_trigger_register(struct iio_trigger *trig_info) error_unregister_id: ida_simple_remove(&iio_trigger_ida, trig_info->id); -error_ret: return ret; } EXPORT_SYMBOL(iio_trigger_register); @@ -234,13 +232,12 @@ static int iio_trigger_detach_poll_func(struct iio_trigger *trig, if (trig->ops && trig->ops->set_trigger_state && no_other_users) { ret = trig->ops->set_trigger_state(trig, false); if (ret) - goto error_ret; + return ret; } iio_trigger_put_irq(trig, pf->irq); free_irq(pf->irq, pf); module_put(pf->indio_dev->info->driver_module); -error_ret: return ret; } diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index d12b2a0dbfbc..c89740d4748f 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -73,6 +73,20 @@ config HID_SENSOR_ALS Say yes here to build support for the HID SENSOR Ambient light sensor. +config HID_SENSOR_PROX + depends on HID_SENSOR_HUB + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select HID_SENSOR_IIO_COMMON + select HID_SENSOR_IIO_TRIGGER + tristate "HID PROX" + help + Say yes here to build support for the HID SENSOR + Proximity sensor. + + To compile this driver as a module, choose M here: the + module will be called hid-sensor-prox. + config SENSORS_LM3533 tristate "LM3533 ambient light sensor" depends on MFD_LM3533 @@ -90,6 +104,18 @@ config SENSORS_LM3533 changes. The ALS-control output values can be set per zone for the three current output channels. +config LTR501 + tristate "LTR-501ALS-01 light sensor" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + If you say yes here you get support for the Lite-On LTR-501ALS-01 + ambient light and proximity sensor. + + This driver can also be built as a module. If so, the module + will be called ltr501. + config TCS3472 tristate "TAOS TCS3472 color light-to-digital converter" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 60e35ac07ff0..3eb36e5151fa 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -9,7 +9,9 @@ obj-$(CONFIG_CM32181) += cm32181.o obj-$(CONFIG_CM36651) += cm36651.o obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o +obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o +obj-$(CONFIG_LTR501) += ltr501.o obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o obj-$(CONFIG_TCS3472) += tcs3472.o obj-$(CONFIG_TSL4531) += tsl4531.o diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c index f3068477b466..09ad5f1ce539 100644 --- a/drivers/iio/light/adjd_s311.c +++ b/drivers/iio/light/adjd_s311.c @@ -14,7 +14,6 @@ */ #include -#include #include #include #include @@ -120,7 +119,6 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct adjd_s311_data *data = iio_priv(indio_dev); s64 time_ns = iio_get_time_ns(); - int len = 0; int i, j = 0; int ret = adjd_s311_req_data(indio_dev); @@ -135,7 +133,6 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p) goto done; data->buffer[j++] = ret & ADJD_S311_DATA_MASK; - len += 2; } iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, time_ns); diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c new file mode 100644 index 000000000000..1894ab196f97 --- /dev/null +++ b/drivers/iio/light/hid-sensor-prox.c @@ -0,0 +1,375 @@ +/* + * HID Sensors Driver + * Copyright (c) 2014, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../common/hid-sensors/hid-sensor-trigger.h" + +#define CHANNEL_SCAN_INDEX_PRESENCE 0 + +struct prox_state { + struct hid_sensor_hub_callbacks callbacks; + struct hid_sensor_common common_attributes; + struct hid_sensor_hub_attribute_info prox_attr; + u32 human_presence; +}; + +/* Channel definitions */ +static const struct iio_chan_spec prox_channels[] = { + { + .type = IIO_PROXIMITY, + .modified = 1, + .channel2 = IIO_NO_MOD, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS), + .scan_index = CHANNEL_SCAN_INDEX_PRESENCE, + } +}; + +/* Adjust channel real bits based on report descriptor */ +static void prox_adjust_channel_bit_mask(struct iio_chan_spec *channels, + int channel, int size) +{ + channels[channel].scan_type.sign = 's'; + /* Real storage bits will change based on the report desc. */ + channels[channel].scan_type.realbits = size * 8; + /* Maximum size of a sample to capture is u32 */ + channels[channel].scan_type.storagebits = sizeof(u32) * 8; +} + +/* Channel read_raw handler */ +static int prox_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct prox_state *prox_state = iio_priv(indio_dev); + int report_id = -1; + u32 address; + int ret; + int ret_type; + + *val = 0; + *val2 = 0; + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->scan_index) { + case CHANNEL_SCAN_INDEX_PRESENCE: + report_id = prox_state->prox_attr.report_id; + address = + HID_USAGE_SENSOR_HUMAN_PRESENCE; + break; + default: + report_id = -1; + break; + } + if (report_id >= 0) + *val = sensor_hub_input_attr_get_raw_value( + prox_state->common_attributes.hsdev, + HID_USAGE_SENSOR_PROX, address, + report_id); + else { + *val = 0; + return -EINVAL; + } + ret_type = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SCALE: + *val = prox_state->prox_attr.units; + ret_type = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_OFFSET: + *val = hid_sensor_convert_exponent( + prox_state->prox_attr.unit_expo); + ret_type = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hid_sensor_read_samp_freq_value( + &prox_state->common_attributes, val, val2); + ret_type = IIO_VAL_INT_PLUS_MICRO; + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret = hid_sensor_read_raw_hyst_value( + &prox_state->common_attributes, val, val2); + ret_type = IIO_VAL_INT_PLUS_MICRO; + break; + default: + ret_type = -EINVAL; + break; + } + + return ret_type; +} + +/* Channel write_raw handler */ +static int prox_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct prox_state *prox_state = iio_priv(indio_dev); + int ret = 0; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hid_sensor_write_samp_freq_value( + &prox_state->common_attributes, val, val2); + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret = hid_sensor_write_raw_hyst_value( + &prox_state->common_attributes, val, val2); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct iio_info prox_info = { + .driver_module = THIS_MODULE, + .read_raw = &prox_read_raw, + .write_raw = &prox_write_raw, +}; + +/* Function to push data to buffer */ +static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, + int len) +{ + dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); + iio_push_to_buffers(indio_dev, data); +} + +/* Callback handler to send event after all samples are received and captured */ +static int prox_proc_event(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, + void *priv) +{ + struct iio_dev *indio_dev = platform_get_drvdata(priv); + struct prox_state *prox_state = iio_priv(indio_dev); + + dev_dbg(&indio_dev->dev, "prox_proc_event [%d]\n", + prox_state->common_attributes.data_ready); + if (prox_state->common_attributes.data_ready) + hid_sensor_push_data(indio_dev, + &prox_state->human_presence, + sizeof(prox_state->human_presence)); + + return 0; +} + +/* Capture samples in local storage */ +static int prox_capture_sample(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, + size_t raw_len, char *raw_data, + void *priv) +{ + struct iio_dev *indio_dev = platform_get_drvdata(priv); + struct prox_state *prox_state = iio_priv(indio_dev); + int ret = -EINVAL; + + switch (usage_id) { + case HID_USAGE_SENSOR_HUMAN_PRESENCE: + prox_state->human_presence = *(u32 *)raw_data; + ret = 0; + break; + default: + break; + } + + return ret; +} + +/* Parse report which is specific to an usage id*/ +static int prox_parse_report(struct platform_device *pdev, + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + unsigned usage_id, + struct prox_state *st) +{ + int ret; + + ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_HUMAN_PRESENCE, + &st->prox_attr); + if (ret < 0) + return ret; + prox_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_PRESENCE, + st->prox_attr.size); + + dev_dbg(&pdev->dev, "prox %x:%x\n", st->prox_attr.index, + st->prox_attr.report_id); + + /* Set Sensitivity field ids, when there is no individual modifier */ + if (st->common_attributes.sensitivity.index < 0) { + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | + HID_USAGE_SENSOR_DATA_PRESENCE, + &st->common_attributes.sensitivity); + dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", + st->common_attributes.sensitivity.index, + st->common_attributes.sensitivity.report_id); + } + return ret; +} + +/* Function to initialize the processing for usage id */ +static int hid_prox_probe(struct platform_device *pdev) +{ + int ret = 0; + static const char *name = "prox"; + struct iio_dev *indio_dev; + struct prox_state *prox_state; + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_chan_spec *channels; + + indio_dev = devm_iio_device_alloc(&pdev->dev, + sizeof(struct prox_state)); + if (!indio_dev) + return -ENOMEM; + platform_set_drvdata(pdev, indio_dev); + + prox_state = iio_priv(indio_dev); + prox_state->common_attributes.hsdev = hsdev; + prox_state->common_attributes.pdev = pdev; + + ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_PROX, + &prox_state->common_attributes); + if (ret) { + dev_err(&pdev->dev, "failed to setup common attributes\n"); + return ret; + } + + channels = kmemdup(prox_channels, sizeof(prox_channels), GFP_KERNEL); + if (!channels) { + dev_err(&pdev->dev, "failed to duplicate channels\n"); + return -ENOMEM; + } + + ret = prox_parse_report(pdev, hsdev, channels, + HID_USAGE_SENSOR_PROX, prox_state); + if (ret) { + dev_err(&pdev->dev, "failed to setup attributes\n"); + goto error_free_dev_mem; + } + + indio_dev->channels = channels; + indio_dev->num_channels = + ARRAY_SIZE(prox_channels); + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &prox_info; + indio_dev->name = name; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + NULL, NULL); + if (ret) { + dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); + goto error_free_dev_mem; + } + prox_state->common_attributes.data_ready = false; + ret = hid_sensor_setup_trigger(indio_dev, name, + &prox_state->common_attributes); + if (ret) { + dev_err(&pdev->dev, "trigger setup failed\n"); + goto error_unreg_buffer_funcs; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_trigger; + } + + prox_state->callbacks.send_event = prox_proc_event; + prox_state->callbacks.capture_sample = prox_capture_sample; + prox_state->callbacks.pdev = pdev; + ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PROX, + &prox_state->callbacks); + if (ret < 0) { + dev_err(&pdev->dev, "callback reg failed\n"); + goto error_iio_unreg; + } + + return ret; + +error_iio_unreg: + iio_device_unregister(indio_dev); +error_remove_trigger: + hid_sensor_remove_trigger(&prox_state->common_attributes); +error_unreg_buffer_funcs: + iio_triggered_buffer_cleanup(indio_dev); +error_free_dev_mem: + kfree(indio_dev->channels); + return ret; +} + +/* Function to deinitialize the processing for usage id */ +static int hid_prox_remove(struct platform_device *pdev) +{ + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct prox_state *prox_state = iio_priv(indio_dev); + + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PROX); + iio_device_unregister(indio_dev); + hid_sensor_remove_trigger(&prox_state->common_attributes); + iio_triggered_buffer_cleanup(indio_dev); + kfree(indio_dev->channels); + + return 0; +} + +static struct platform_device_id hid_prox_ids[] = { + { + /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ + .name = "HID-SENSOR-200011", + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, hid_prox_ids); + +static struct platform_driver hid_prox_platform_driver = { + .id_table = hid_prox_ids, + .driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, + }, + .probe = hid_prox_probe, + .remove = hid_prox_remove, +}; +module_platform_driver(hid_prox_platform_driver); + +MODULE_DESCRIPTION("HID Sensor Proximity"); +MODULE_AUTHOR("Archana Patni "); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c new file mode 100644 index 000000000000..62b7072af4de --- /dev/null +++ b/drivers/iio/light/ltr501.c @@ -0,0 +1,445 @@ +/* + * ltr501.c - Support for Lite-On LTR501 ambient light and proximity sensor + * + * Copyright 2014 Peter Meerwald + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * 7-bit I2C slave address 0x23 + * + * TODO: interrupt, threshold, measurement rate, IR LED characteristics + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define LTR501_DRV_NAME "ltr501" + +#define LTR501_ALS_CONTR 0x80 /* ALS operation mode, SW reset */ +#define LTR501_PS_CONTR 0x81 /* PS operation mode */ +#define LTR501_PART_ID 0x86 +#define LTR501_MANUFAC_ID 0x87 +#define LTR501_ALS_DATA1 0x88 /* 16-bit, little endian */ +#define LTR501_ALS_DATA0 0x8a /* 16-bit, little endian */ +#define LTR501_ALS_PS_STATUS 0x8c +#define LTR501_PS_DATA 0x8d /* 16-bit, little endian */ + +#define LTR501_ALS_CONTR_SW_RESET BIT(2) +#define LTR501_CONTR_PS_GAIN_MASK (BIT(3) | BIT(2)) +#define LTR501_CONTR_PS_GAIN_SHIFT 2 +#define LTR501_CONTR_ALS_GAIN_MASK BIT(3) +#define LTR501_CONTR_ACTIVE BIT(1) + +#define LTR501_STATUS_ALS_RDY BIT(2) +#define LTR501_STATUS_PS_RDY BIT(0) + +#define LTR501_PS_DATA_MASK 0x7ff + +struct ltr501_data { + struct i2c_client *client; + struct mutex lock_als, lock_ps; + u8 als_contr, ps_contr; +}; + +static int ltr501_drdy(struct ltr501_data *data, u8 drdy_mask) +{ + int tries = 100; + int ret; + + while (tries--) { + ret = i2c_smbus_read_byte_data(data->client, + LTR501_ALS_PS_STATUS); + if (ret < 0) + return ret; + if ((ret & drdy_mask) == drdy_mask) + return 0; + msleep(25); + } + + dev_err(&data->client->dev, "ltr501_drdy() failed, data not ready\n"); + return -EIO; +} + +static int ltr501_read_als(struct ltr501_data *data, __le16 buf[2]) +{ + int ret = ltr501_drdy(data, LTR501_STATUS_ALS_RDY); + if (ret < 0) + return ret; + /* always read both ALS channels in given order */ + return i2c_smbus_read_i2c_block_data(data->client, + LTR501_ALS_DATA1, 2 * sizeof(__le16), (u8 *) buf); +} + +static int ltr501_read_ps(struct ltr501_data *data) +{ + int ret = ltr501_drdy(data, LTR501_STATUS_PS_RDY); + if (ret < 0) + return ret; + return i2c_smbus_read_word_data(data->client, LTR501_PS_DATA); +} + +#define LTR501_INTENSITY_CHANNEL(_idx, _addr, _mod, _shared) { \ + .type = IIO_INTENSITY, \ + .modified = 1, \ + .address = (_addr), \ + .channel2 = (_mod), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = (_shared), \ + .scan_index = (_idx), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + } \ +} + +static const struct iio_chan_spec ltr501_channels[] = { + LTR501_INTENSITY_CHANNEL(0, LTR501_ALS_DATA0, IIO_MOD_LIGHT_BOTH, 0), + LTR501_INTENSITY_CHANNEL(1, LTR501_ALS_DATA1, IIO_MOD_LIGHT_IR, + BIT(IIO_CHAN_INFO_SCALE)), + { + .type = IIO_PROXIMITY, + .address = LTR501_PS_DATA, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .scan_index = 2, + .scan_type = { + .sign = 'u', + .realbits = 11, + .storagebits = 16, + .endianness = IIO_CPU, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const int ltr501_ps_gain[4][2] = { + {1, 0}, {0, 250000}, {0, 125000}, {0, 62500} +}; + +static int ltr501_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ltr501_data *data = iio_priv(indio_dev); + __le16 buf[2]; + int ret, i; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + + switch (chan->type) { + case IIO_INTENSITY: + mutex_lock(&data->lock_als); + ret = ltr501_read_als(data, buf); + mutex_unlock(&data->lock_als); + if (ret < 0) + return ret; + *val = le16_to_cpu(chan->address == LTR501_ALS_DATA1 ? + buf[0] : buf[1]); + return IIO_VAL_INT; + case IIO_PROXIMITY: + mutex_lock(&data->lock_ps); + ret = ltr501_read_ps(data); + mutex_unlock(&data->lock_ps); + if (ret < 0) + return ret; + *val = ret & LTR501_PS_DATA_MASK; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_INTENSITY: + if (data->als_contr & LTR501_CONTR_ALS_GAIN_MASK) { + *val = 0; + *val2 = 5000; + return IIO_VAL_INT_PLUS_MICRO; + } else { + *val = 1; + *val2 = 0; + return IIO_VAL_INT; + } + case IIO_PROXIMITY: + i = (data->ps_contr & LTR501_CONTR_PS_GAIN_MASK) >> + LTR501_CONTR_PS_GAIN_SHIFT; + *val = ltr501_ps_gain[i][0]; + *val2 = ltr501_ps_gain[i][1]; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + } + return -EINVAL; +} + +static int ltr501_get_ps_gain_index(int val, int val2) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ltr501_ps_gain); i++) + if (val == ltr501_ps_gain[i][0] && val2 == ltr501_ps_gain[i][1]) + return i; + + return -1; +} + +static int ltr501_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ltr501_data *data = iio_priv(indio_dev); + int i; + + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_INTENSITY: + if (val == 0 && val2 == 5000) + data->als_contr |= LTR501_CONTR_ALS_GAIN_MASK; + else if (val == 1 && val2 == 0) + data->als_contr &= ~LTR501_CONTR_ALS_GAIN_MASK; + else + return -EINVAL; + return i2c_smbus_write_byte_data(data->client, + LTR501_ALS_CONTR, data->als_contr); + case IIO_PROXIMITY: + i = ltr501_get_ps_gain_index(val, val2); + if (i < 0) + return -EINVAL; + data->ps_contr &= ~LTR501_CONTR_PS_GAIN_MASK; + data->ps_contr |= i << LTR501_CONTR_PS_GAIN_SHIFT; + return i2c_smbus_write_byte_data(data->client, + LTR501_PS_CONTR, data->ps_contr); + default: + return -EINVAL; + } + } + return -EINVAL; +} + +static IIO_CONST_ATTR(in_proximity_scale_available, "1 0.25 0.125 0.0625"); +static IIO_CONST_ATTR(in_intensity_scale_available, "1 0.005"); + +static struct attribute *ltr501_attributes[] = { + &iio_const_attr_in_proximity_scale_available.dev_attr.attr, + &iio_const_attr_in_intensity_scale_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group ltr501_attribute_group = { + .attrs = ltr501_attributes, +}; + +static const struct iio_info ltr501_info = { + .read_raw = ltr501_read_raw, + .write_raw = ltr501_write_raw, + .attrs = <r501_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int ltr501_write_contr(struct i2c_client *client, u8 als_val, u8 ps_val) +{ + int ret = i2c_smbus_write_byte_data(client, LTR501_ALS_CONTR, als_val); + if (ret < 0) + return ret; + + return i2c_smbus_write_byte_data(client, LTR501_PS_CONTR, ps_val); +} + +static irqreturn_t ltr501_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ltr501_data *data = iio_priv(indio_dev); + u16 buf[8]; + __le16 als_buf[2]; + u8 mask = 0; + int j = 0; + int ret; + + memset(buf, 0, sizeof(buf)); + + /* figure out which data needs to be ready */ + if (test_bit(0, indio_dev->active_scan_mask) || + test_bit(1, indio_dev->active_scan_mask)) + mask |= LTR501_STATUS_ALS_RDY; + if (test_bit(2, indio_dev->active_scan_mask)) + mask |= LTR501_STATUS_PS_RDY; + + ret = ltr501_drdy(data, mask); + if (ret < 0) + goto done; + + if (mask & LTR501_STATUS_ALS_RDY) { + ret = i2c_smbus_read_i2c_block_data(data->client, + LTR501_ALS_DATA1, sizeof(als_buf), (u8 *) als_buf); + if (ret < 0) + return ret; + if (test_bit(0, indio_dev->active_scan_mask)) + buf[j++] = le16_to_cpu(als_buf[1]); + if (test_bit(1, indio_dev->active_scan_mask)) + buf[j++] = le16_to_cpu(als_buf[0]); + } + + if (mask & LTR501_STATUS_PS_RDY) { + ret = i2c_smbus_read_word_data(data->client, LTR501_PS_DATA); + if (ret < 0) + goto done; + buf[j++] = ret & LTR501_PS_DATA_MASK; + } + + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns()); + +done: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int ltr501_init(struct ltr501_data *data) +{ + int ret; + + ret = i2c_smbus_read_byte_data(data->client, LTR501_ALS_CONTR); + if (ret < 0) + return ret; + data->als_contr = ret | LTR501_CONTR_ACTIVE; + + ret = i2c_smbus_read_byte_data(data->client, LTR501_PS_CONTR); + if (ret < 0) + return ret; + data->ps_contr = ret | LTR501_CONTR_ACTIVE; + + return ltr501_write_contr(data->client, data->als_contr, + data->ps_contr); +} + +static int ltr501_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ltr501_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + mutex_init(&data->lock_als); + mutex_init(&data->lock_ps); + + ret = i2c_smbus_read_byte_data(data->client, LTR501_PART_ID); + if (ret < 0) + return ret; + if ((ret >> 4) != 0x8) + return -ENODEV; + + indio_dev->dev.parent = &client->dev; + indio_dev->info = <r501_info; + indio_dev->channels = ltr501_channels; + indio_dev->num_channels = ARRAY_SIZE(ltr501_channels); + indio_dev->name = LTR501_DRV_NAME; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = ltr501_init(data); + if (ret < 0) + return ret; + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + ltr501_trigger_handler, NULL); + if (ret) + return ret; + + ret = iio_device_register(indio_dev); + if (ret) + goto error_unreg_buffer; + + return 0; + +error_unreg_buffer: + iio_triggered_buffer_cleanup(indio_dev); + return ret; +} + +static int ltr501_powerdown(struct ltr501_data *data) +{ + return ltr501_write_contr(data->client, + data->als_contr & ~LTR501_CONTR_ACTIVE, + data->ps_contr & ~LTR501_CONTR_ACTIVE); +} + +static int ltr501_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + ltr501_powerdown(iio_priv(indio_dev)); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int ltr501_suspend(struct device *dev) +{ + struct ltr501_data *data = iio_priv(i2c_get_clientdata( + to_i2c_client(dev))); + return ltr501_powerdown(data); +} + +static int ltr501_resume(struct device *dev) +{ + struct ltr501_data *data = iio_priv(i2c_get_clientdata( + to_i2c_client(dev))); + + return ltr501_write_contr(data->client, data->als_contr, + data->ps_contr); +} +#endif + +static SIMPLE_DEV_PM_OPS(ltr501_pm_ops, ltr501_suspend, ltr501_resume); + +static const struct i2c_device_id ltr501_id[] = { + { "ltr501", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ltr501_id); + +static struct i2c_driver ltr501_driver = { + .driver = { + .name = LTR501_DRV_NAME, + .pm = <r501_pm_ops, + .owner = THIS_MODULE, + }, + .probe = ltr501_probe, + .remove = ltr501_remove, + .id_table = ltr501_id, +}; + +module_i2c_driver(ltr501_driver); + +MODULE_AUTHOR("Peter Meerwald "); +MODULE_DESCRIPTION("Lite-On LTR501 ambient light and proximity sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 887fecf1f9bb..fe063a0a21cd 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -179,7 +179,6 @@ static irqreturn_t tcs3472_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct tcs3472_data *data = iio_priv(indio_dev); - int len = 0; int i, j = 0; int ret = tcs3472_req_data(data); @@ -194,7 +193,6 @@ static irqreturn_t tcs3472_trigger_handler(int irq, void *p) goto done; data->buffer[j++] = ret; - len += 2; } iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 05423543f89d..74866d1efd1b 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -513,6 +513,7 @@ static int ak8975_probe(struct i2c_client *client, indio_dev->channels = ak8975_channels; indio_dev->num_channels = ARRAY_SIZE(ak8975_channels); indio_dev->info = &ak8975_info; + indio_dev->name = id->name; indio_dev->modes = INDIO_DIRECT_MODE; err = iio_device_register(indio_dev); diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c index f66955fb3509..8b77782474d7 100644 --- a/drivers/iio/magnetometer/mag3110.c +++ b/drivers/iio/magnetometer/mag3110.c @@ -183,9 +183,17 @@ static int mag3110_read_raw(struct iio_dev *indio_dev, return -EINVAL; } case IIO_CHAN_INFO_SCALE: - *val = 0; - *val2 = 1000; - return IIO_VAL_INT_PLUS_MICRO; + switch (chan->type) { + case IIO_MAGN: + *val = 0; + *val2 = 1000; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_TEMP: + *val = 1000; + return IIO_VAL_INT; + default: + return -EINVAL; + } case IIO_CHAN_INFO_SAMP_FREQ: i = data->ctrl_reg1 >> MAG3110_CTRL_DR_SHIFT; *val = mag3110_samp_freq[i][0]; @@ -270,7 +278,8 @@ static const struct iio_chan_spec mag3110_channels[] = { MAG3110_CHANNEL(Z, 2), { .type = IIO_TEMP, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), .scan_index = 3, .scan_type = { .sign = 's', diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index a8b9cae5c173..d88ff17fedb2 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -5,6 +5,20 @@ menu "Pressure sensors" +config HID_SENSOR_PRESS + depends on HID_SENSOR_HUB + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select HID_SENSOR_IIO_COMMON + select HID_SENSOR_IIO_TRIGGER + tristate "HID PRESS" + help + Say yes here to build support for the HID SENSOR + Pressure driver + + To compile this driver as a module, choose M here: the module + will be called hid-sensor-press. + config MPL3115 tristate "Freescale MPL3115A2 pressure sensor driver" depends on I2C @@ -26,7 +40,7 @@ config IIO_ST_PRESS select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) help Say yes here to build support for STMicroelectronics pressure - sensors: LPS001WP, LPS331AP. + sensors: LPS001WP, LPS25H, LPS331AP. This driver can also be built as a module. If so, these modules will be created: diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile index 42bb9fcf5436..4a57bf65b04b 100644 --- a/drivers/iio/pressure/Makefile +++ b/drivers/iio/pressure/Makefile @@ -3,6 +3,7 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o obj-$(CONFIG_MPL3115) += mpl3115.o obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o st_pressure-y := st_pressure_core.o diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c new file mode 100644 index 000000000000..e0e6409aa94e --- /dev/null +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -0,0 +1,376 @@ +/* + * HID Sensors Driver + * Copyright (c) 2014, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../common/hid-sensors/hid-sensor-trigger.h" + +#define CHANNEL_SCAN_INDEX_PRESSURE 0 + +struct press_state { + struct hid_sensor_hub_callbacks callbacks; + struct hid_sensor_common common_attributes; + struct hid_sensor_hub_attribute_info press_attr; + u32 press_data; +}; + +/* Channel definitions */ +static const struct iio_chan_spec press_channels[] = { + { + .type = IIO_PRESSURE, + .modified = 1, + .channel2 = IIO_NO_MOD, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS), + .scan_index = CHANNEL_SCAN_INDEX_PRESSURE, + } +}; + +/* Adjust channel real bits based on report descriptor */ +static void press_adjust_channel_bit_mask(struct iio_chan_spec *channels, + int channel, int size) +{ + channels[channel].scan_type.sign = 's'; + /* Real storage bits will change based on the report desc. */ + channels[channel].scan_type.realbits = size * 8; + /* Maximum size of a sample to capture is u32 */ + channels[channel].scan_type.storagebits = sizeof(u32) * 8; +} + +/* Channel read_raw handler */ +static int press_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct press_state *press_state = iio_priv(indio_dev); + int report_id = -1; + u32 address; + int ret; + int ret_type; + + *val = 0; + *val2 = 0; + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->scan_index) { + case CHANNEL_SCAN_INDEX_PRESSURE: + report_id = press_state->press_attr.report_id; + address = + HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE; + break; + default: + report_id = -1; + break; + } + if (report_id >= 0) + *val = sensor_hub_input_attr_get_raw_value( + press_state->common_attributes.hsdev, + HID_USAGE_SENSOR_PRESSURE, address, + report_id); + else { + *val = 0; + return -EINVAL; + } + ret_type = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SCALE: + *val = press_state->press_attr.units; + ret_type = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_OFFSET: + *val = hid_sensor_convert_exponent( + press_state->press_attr.unit_expo); + ret_type = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hid_sensor_read_samp_freq_value( + &press_state->common_attributes, val, val2); + ret_type = IIO_VAL_INT_PLUS_MICRO; + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret = hid_sensor_read_raw_hyst_value( + &press_state->common_attributes, val, val2); + ret_type = IIO_VAL_INT_PLUS_MICRO; + break; + default: + ret_type = -EINVAL; + break; + } + + return ret_type; +} + +/* Channel write_raw handler */ +static int press_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct press_state *press_state = iio_priv(indio_dev); + int ret = 0; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hid_sensor_write_samp_freq_value( + &press_state->common_attributes, val, val2); + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret = hid_sensor_write_raw_hyst_value( + &press_state->common_attributes, val, val2); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct iio_info press_info = { + .driver_module = THIS_MODULE, + .read_raw = &press_read_raw, + .write_raw = &press_write_raw, +}; + +/* Function to push data to buffer */ +static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, + int len) +{ + dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); + iio_push_to_buffers(indio_dev, data); +} + +/* Callback handler to send event after all samples are received and captured */ +static int press_proc_event(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, + void *priv) +{ + struct iio_dev *indio_dev = platform_get_drvdata(priv); + struct press_state *press_state = iio_priv(indio_dev); + + dev_dbg(&indio_dev->dev, "press_proc_event [%d]\n", + press_state->common_attributes.data_ready); + if (press_state->common_attributes.data_ready) + hid_sensor_push_data(indio_dev, + &press_state->press_data, + sizeof(press_state->press_data)); + + return 0; +} + +/* Capture samples in local storage */ +static int press_capture_sample(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, + size_t raw_len, char *raw_data, + void *priv) +{ + struct iio_dev *indio_dev = platform_get_drvdata(priv); + struct press_state *press_state = iio_priv(indio_dev); + int ret = -EINVAL; + + switch (usage_id) { + case HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE: + press_state->press_data = *(u32 *)raw_data; + ret = 0; + break; + default: + break; + } + + return ret; +} + +/* Parse report which is specific to an usage id*/ +static int press_parse_report(struct platform_device *pdev, + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + unsigned usage_id, + struct press_state *st) +{ + int ret; + + ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE, + &st->press_attr); + if (ret < 0) + return ret; + press_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_PRESSURE, + st->press_attr.size); + + dev_dbg(&pdev->dev, "press %x:%x\n", st->press_attr.index, + st->press_attr.report_id); + + /* Set Sensitivity field ids, when there is no individual modifier */ + if (st->common_attributes.sensitivity.index < 0) { + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | + HID_USAGE_SENSOR_DATA_ATMOSPHERIC_PRESSURE, + &st->common_attributes.sensitivity); + dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", + st->common_attributes.sensitivity.index, + st->common_attributes.sensitivity.report_id); + } + return ret; +} + +/* Function to initialize the processing for usage id */ +static int hid_press_probe(struct platform_device *pdev) +{ + int ret = 0; + static const char *name = "press"; + struct iio_dev *indio_dev; + struct press_state *press_state; + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_chan_spec *channels; + + indio_dev = devm_iio_device_alloc(&pdev->dev, + sizeof(struct press_state)); + if (!indio_dev) + return -ENOMEM; + platform_set_drvdata(pdev, indio_dev); + + press_state = iio_priv(indio_dev); + press_state->common_attributes.hsdev = hsdev; + press_state->common_attributes.pdev = pdev; + + ret = hid_sensor_parse_common_attributes(hsdev, + HID_USAGE_SENSOR_PRESSURE, + &press_state->common_attributes); + if (ret) { + dev_err(&pdev->dev, "failed to setup common attributes\n"); + return ret; + } + + channels = kmemdup(press_channels, sizeof(press_channels), GFP_KERNEL); + if (!channels) { + dev_err(&pdev->dev, "failed to duplicate channels\n"); + return -ENOMEM; + } + + ret = press_parse_report(pdev, hsdev, channels, + HID_USAGE_SENSOR_PRESSURE, press_state); + if (ret) { + dev_err(&pdev->dev, "failed to setup attributes\n"); + goto error_free_dev_mem; + } + + indio_dev->channels = channels; + indio_dev->num_channels = + ARRAY_SIZE(press_channels); + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &press_info; + indio_dev->name = name; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + NULL, NULL); + if (ret) { + dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); + goto error_free_dev_mem; + } + press_state->common_attributes.data_ready = false; + ret = hid_sensor_setup_trigger(indio_dev, name, + &press_state->common_attributes); + if (ret) { + dev_err(&pdev->dev, "trigger setup failed\n"); + goto error_unreg_buffer_funcs; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_trigger; + } + + press_state->callbacks.send_event = press_proc_event; + press_state->callbacks.capture_sample = press_capture_sample; + press_state->callbacks.pdev = pdev; + ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PRESSURE, + &press_state->callbacks); + if (ret < 0) { + dev_err(&pdev->dev, "callback reg failed\n"); + goto error_iio_unreg; + } + + return ret; + +error_iio_unreg: + iio_device_unregister(indio_dev); +error_remove_trigger: + hid_sensor_remove_trigger(&press_state->common_attributes); +error_unreg_buffer_funcs: + iio_triggered_buffer_cleanup(indio_dev); +error_free_dev_mem: + kfree(indio_dev->channels); + return ret; +} + +/* Function to deinitialize the processing for usage id */ +static int hid_press_remove(struct platform_device *pdev) +{ + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct press_state *press_state = iio_priv(indio_dev); + + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE); + iio_device_unregister(indio_dev); + hid_sensor_remove_trigger(&press_state->common_attributes); + iio_triggered_buffer_cleanup(indio_dev); + kfree(indio_dev->channels); + + return 0; +} + +static struct platform_device_id hid_press_ids[] = { + { + /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ + .name = "HID-SENSOR-200031", + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, hid_press_ids); + +static struct platform_driver hid_press_platform_driver = { + .id_table = hid_press_ids, + .driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, + }, + .probe = hid_press_probe, + .remove = hid_press_remove, +}; +module_platform_driver(hid_press_platform_driver); + +MODULE_DESCRIPTION("HID Sensor Pressure"); +MODULE_AUTHOR("Archana Patni "); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c index ac8c8ab723e5..ba6d0c520e63 100644 --- a/drivers/iio/pressure/mpl3115.c +++ b/drivers/iio/pressure/mpl3115.c @@ -77,7 +77,7 @@ static int mpl3115_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct mpl3115_data *data = iio_priv(indio_dev); - s32 tmp = 0; + __be32 tmp = 0; int ret; switch (mask) { diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h index 049c21acf1f0..242943c0c4e4 100644 --- a/drivers/iio/pressure/st_pressure.h +++ b/drivers/iio/pressure/st_pressure.h @@ -15,6 +15,7 @@ #include #define LPS001WP_PRESS_DEV_NAME "lps001wp" +#define LPS25H_PRESS_DEV_NAME "lps25h" #define LPS331AP_PRESS_DEV_NAME "lps331ap" /** diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 58083f9d51c5..7418768ed49c 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -40,6 +40,9 @@ /* FULLSCALE */ #define ST_PRESS_FS_AVL_1260MB 1260 +#define ST_PRESS_1_OUT_XL_ADDR 0x28 +#define ST_TEMP_1_OUT_L_ADDR 0x2b + /* CUSTOM VALUES FOR LPS331AP SENSOR */ #define ST_PRESS_LPS331AP_WAI_EXP 0xbb #define ST_PRESS_LPS331AP_ODR_ADDR 0x20 @@ -62,8 +65,6 @@ #define ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK 0x20 #define ST_PRESS_LPS331AP_MULTIREAD_BIT true #define ST_PRESS_LPS331AP_TEMP_OFFSET 42500 -#define ST_PRESS_LPS331AP_OUT_XL_ADDR 0x28 -#define ST_TEMP_LPS331AP_OUT_L_ADDR 0x2b /* CUSTOM VALUES FOR LPS001WP SENSOR */ #define ST_PRESS_LPS001WP_WAI_EXP 0xba @@ -80,11 +81,36 @@ #define ST_PRESS_LPS001WP_OUT_L_ADDR 0x28 #define ST_TEMP_LPS001WP_OUT_L_ADDR 0x2a -static const struct iio_chan_spec st_press_lps331ap_channels[] = { +/* CUSTOM VALUES FOR LPS25H SENSOR */ +#define ST_PRESS_LPS25H_WAI_EXP 0xbd +#define ST_PRESS_LPS25H_ODR_ADDR 0x20 +#define ST_PRESS_LPS25H_ODR_MASK 0x70 +#define ST_PRESS_LPS25H_ODR_AVL_1HZ_VAL 0x01 +#define ST_PRESS_LPS25H_ODR_AVL_7HZ_VAL 0x02 +#define ST_PRESS_LPS25H_ODR_AVL_13HZ_VAL 0x03 +#define ST_PRESS_LPS25H_ODR_AVL_25HZ_VAL 0x04 +#define ST_PRESS_LPS25H_PW_ADDR 0x20 +#define ST_PRESS_LPS25H_PW_MASK 0x80 +#define ST_PRESS_LPS25H_FS_ADDR 0x00 +#define ST_PRESS_LPS25H_FS_MASK 0x00 +#define ST_PRESS_LPS25H_FS_AVL_1260_VAL 0x00 +#define ST_PRESS_LPS25H_FS_AVL_1260_GAIN ST_PRESS_KPASCAL_NANO_SCALE +#define ST_PRESS_LPS25H_FS_AVL_TEMP_GAIN ST_PRESS_CELSIUS_NANO_SCALE +#define ST_PRESS_LPS25H_BDU_ADDR 0x20 +#define ST_PRESS_LPS25H_BDU_MASK 0x04 +#define ST_PRESS_LPS25H_DRDY_IRQ_ADDR 0x23 +#define ST_PRESS_LPS25H_DRDY_IRQ_INT1_MASK 0x01 +#define ST_PRESS_LPS25H_DRDY_IRQ_INT2_MASK 0x10 +#define ST_PRESS_LPS25H_MULTIREAD_BIT true +#define ST_PRESS_LPS25H_TEMP_OFFSET 42500 +#define ST_PRESS_LPS25H_OUT_XL_ADDR 0x28 +#define ST_TEMP_LPS25H_OUT_L_ADDR 0x2b + +static const struct iio_chan_spec st_press_1_channels[] = { { .type = IIO_PRESSURE, .channel2 = IIO_NO_MOD, - .address = ST_PRESS_LPS331AP_OUT_XL_ADDR, + .address = ST_PRESS_1_OUT_XL_ADDR, .scan_index = ST_SENSORS_SCAN_X, .scan_type = { .sign = 'u', @@ -99,7 +125,7 @@ static const struct iio_chan_spec st_press_lps331ap_channels[] = { { .type = IIO_TEMP, .channel2 = IIO_NO_MOD, - .address = ST_TEMP_LPS331AP_OUT_L_ADDR, + .address = ST_TEMP_1_OUT_L_ADDR, .scan_index = -1, .scan_type = { .sign = 'u', @@ -156,8 +182,8 @@ static const struct st_sensors st_press_sensors[] = { .sensors_supported = { [0] = LPS331AP_PRESS_DEV_NAME, }, - .ch = (struct iio_chan_spec *)st_press_lps331ap_channels, - .num_ch = ARRAY_SIZE(st_press_lps331ap_channels), + .ch = (struct iio_chan_spec *)st_press_1_channels, + .num_ch = ARRAY_SIZE(st_press_1_channels), .odr = { .addr = ST_PRESS_LPS331AP_ODR_ADDR, .mask = ST_PRESS_LPS331AP_ODR_MASK, @@ -233,6 +259,53 @@ static const struct st_sensors st_press_sensors[] = { .multi_read_bit = ST_PRESS_LPS001WP_MULTIREAD_BIT, .bootime = 2, }, + { + .wai = ST_PRESS_LPS25H_WAI_EXP, + .sensors_supported = { + [0] = LPS25H_PRESS_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_press_1_channels, + .num_ch = ARRAY_SIZE(st_press_1_channels), + .odr = { + .addr = ST_PRESS_LPS25H_ODR_ADDR, + .mask = ST_PRESS_LPS25H_ODR_MASK, + .odr_avl = { + { 1, ST_PRESS_LPS25H_ODR_AVL_1HZ_VAL, }, + { 7, ST_PRESS_LPS25H_ODR_AVL_7HZ_VAL, }, + { 13, ST_PRESS_LPS25H_ODR_AVL_13HZ_VAL, }, + { 25, ST_PRESS_LPS25H_ODR_AVL_25HZ_VAL, }, + }, + }, + .pw = { + .addr = ST_PRESS_LPS25H_PW_ADDR, + .mask = ST_PRESS_LPS25H_PW_MASK, + .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .fs = { + .addr = ST_PRESS_LPS25H_FS_ADDR, + .mask = ST_PRESS_LPS25H_FS_MASK, + .fs_avl = { + [0] = { + .num = ST_PRESS_FS_AVL_1260MB, + .value = ST_PRESS_LPS25H_FS_AVL_1260_VAL, + .gain = ST_PRESS_LPS25H_FS_AVL_1260_GAIN, + .gain2 = ST_PRESS_LPS25H_FS_AVL_TEMP_GAIN, + }, + }, + }, + .bdu = { + .addr = ST_PRESS_LPS25H_BDU_ADDR, + .mask = ST_PRESS_LPS25H_BDU_MASK, + }, + .drdy_irq = { + .addr = ST_PRESS_LPS25H_DRDY_IRQ_ADDR, + .mask_int1 = ST_PRESS_LPS25H_DRDY_IRQ_INT1_MASK, + .mask_int2 = ST_PRESS_LPS25H_DRDY_IRQ_INT2_MASK, + }, + .multi_read_bit = ST_PRESS_LPS25H_MULTIREAD_BIT, + .bootime = 2, + }, }; static int st_press_read_raw(struct iio_dev *indio_dev, diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index 51eab7fcb194..3cd73e39b840 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -50,6 +50,7 @@ static int st_press_i2c_remove(struct i2c_client *client) static const struct i2c_device_id st_press_id_table[] = { { LPS001WP_PRESS_DEV_NAME }, + { LPS25H_PRESS_DEV_NAME }, { LPS331AP_PRESS_DEV_NAME }, {}, }; diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c index 27322af6d665..f45d430ec529 100644 --- a/drivers/iio/pressure/st_pressure_spi.c +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -49,6 +49,7 @@ static int st_press_spi_remove(struct spi_device *spi) static const struct spi_device_id st_press_id_table[] = { { LPS001WP_PRESS_DEV_NAME }, + { LPS25H_PRESS_DEV_NAME }, { LPS331AP_PRESS_DEV_NAME }, {}, }; diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c index d4e15a617c3b..9d38f7b36cd1 100644 --- a/drivers/media/i2c/adv7343.c +++ b/drivers/media/i2c/adv7343.c @@ -26,12 +26,12 @@ #include #include #include +#include #include #include #include #include -#include #include "adv7343_regs.h" @@ -410,7 +410,7 @@ adv7343_get_pdata(struct i2c_client *client) if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; - np = v4l2_of_get_next_endpoint(client->dev.of_node, NULL); + np = of_graph_get_next_endpoint(client->dev.of_node, NULL); if (!np) return NULL; diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index e5ddf47030fd..192c4aad05d6 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,6 @@ #include #include #include -#include #include #include "aptina-pll.h" @@ -943,7 +943,7 @@ mt9p031_get_pdata(struct i2c_client *client) if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; - np = v4l2_of_get_next_endpoint(client->dev.of_node, NULL); + np = of_graph_get_next_endpoint(client->dev.of_node, NULL); if (!np) return NULL; diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index 77e10e0fd8d6..2d768ef67cc5 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -1855,7 +1856,7 @@ static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev) if (ret < 0) return ret; - node_ep = v4l2_of_get_next_endpoint(node, NULL); + node_ep = of_graph_get_next_endpoint(node, NULL); if (!node_ep) { dev_err(dev, "no endpoint defined at node %s\n", node->full_name); diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 83d85df4853a..ca001178c5bf 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -1068,7 +1069,7 @@ tvp514x_get_pdata(struct i2c_client *client) if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; - endpoint = v4l2_of_get_next_endpoint(client->dev.of_node, NULL); + endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL); if (!endpoint) return NULL; diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 912e1cccdd1c..c4e1e2cb3094 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -957,7 +958,7 @@ tvp7002_get_pdata(struct i2c_client *client) if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) return client->dev.platform_data; - endpoint = v4l2_of_get_next_endpoint(client->dev.of_node, NULL); + endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL); if (!endpoint) return NULL; diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 13a4228952e3..9bdfa4599bc3 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -24,13 +24,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include #include "media-dev.h" @@ -167,10 +167,10 @@ static int fimc_is_parse_sensor_config(struct fimc_is_sensor *sensor, u32 tmp = 0; int ret; - np = v4l2_of_get_next_endpoint(np, NULL); + np = of_graph_get_next_endpoint(np, NULL); if (!np) return -ENXIO; - np = v4l2_of_get_remote_port(np); + np = of_graph_get_remote_port(np); if (!np) return -ENXIO; diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index c1bce170df6f..04d6ecdd314c 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -468,12 +469,12 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, return 0; v4l2_of_parse_endpoint(ep, &endpoint); - if (WARN_ON(endpoint.port == 0) || index >= FIMC_MAX_SENSORS) + if (WARN_ON(endpoint.base.port == 0) || index >= FIMC_MAX_SENSORS) return -EINVAL; - pd->mux_id = (endpoint.port - 1) & 0x1; + pd->mux_id = (endpoint.base.port - 1) & 0x1; - rem = v4l2_of_get_remote_port_parent(ep); + rem = of_graph_get_remote_port_parent(ep); of_node_put(ep); if (rem == NULL) { v4l2_info(&fmd->v4l2_dev, "Remote device at %s not found\n", @@ -493,13 +494,13 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, return -EINVAL; } - if (fimc_input_is_parallel(endpoint.port)) { + if (fimc_input_is_parallel(endpoint.base.port)) { if (endpoint.bus_type == V4L2_MBUS_PARALLEL) pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_601; else pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_656; pd->flags = endpoint.bus.parallel.flags; - } else if (fimc_input_is_mipi_csi(endpoint.port)) { + } else if (fimc_input_is_mipi_csi(endpoint.base.port)) { /* * MIPI CSI-2: only input mux selection and * the sensor's clock frequency is needed. @@ -507,7 +508,7 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, pd->sensor_bus_type = FIMC_BUS_TYPE_MIPI_CSI2; } else { v4l2_err(&fmd->v4l2_dev, "Wrong port id (%u) at node %s\n", - endpoint.port, rem->full_name); + endpoint.base.port, rem->full_name); } /* * For FIMC-IS handled sensors, that are placed under i2c-isp device diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index f3c3591fdc5d..3678ba59725c 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -762,7 +763,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev, &state->max_num_lanes)) return -EINVAL; - node = v4l2_of_get_next_endpoint(node, NULL); + node = of_graph_get_next_endpoint(node, NULL); if (!node) { dev_err(&pdev->dev, "No port node at %s\n", pdev->dev.of_node->full_name); @@ -771,7 +772,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev, /* Get port node and validate MIPI-CSI channel id. */ v4l2_of_parse_endpoint(node, &endpoint); - state->index = endpoint.port - FIMC_INPUT_MIPI_CSI2_0; + state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0; if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES) return -ENXIO; diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c index 42e3e8a5e361..b4ed9a955fbe 100644 --- a/drivers/media/v4l2-core/v4l2-of.c +++ b/drivers/media/v4l2-core/v4l2-of.c @@ -127,17 +127,9 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node, int v4l2_of_parse_endpoint(const struct device_node *node, struct v4l2_of_endpoint *endpoint) { - struct device_node *port_node = of_get_parent(node); - - memset(endpoint, 0, offsetof(struct v4l2_of_endpoint, head)); - - endpoint->local_node = node; - /* - * It doesn't matter whether the two calls below succeed. - * If they don't then the default value 0 is used. - */ - of_property_read_u32(port_node, "reg", &endpoint->port); - of_property_read_u32(node, "reg", &endpoint->id); + of_graph_parse_endpoint(node, &endpoint->base); + endpoint->bus_type = 0; + memset(&endpoint->bus, 0, sizeof(endpoint->bus)); v4l2_of_parse_csi_bus(node, endpoint); /* @@ -147,125 +139,6 @@ int v4l2_of_parse_endpoint(const struct device_node *node, if (endpoint->bus.mipi_csi2.flags == 0) v4l2_of_parse_parallel_bus(node, endpoint); - of_node_put(port_node); - return 0; } EXPORT_SYMBOL(v4l2_of_parse_endpoint); - -/** - * v4l2_of_get_next_endpoint() - get next endpoint node - * @parent: pointer to the parent device node - * @prev: previous endpoint node, or NULL to get first - * - * Return: An 'endpoint' node pointer with refcount incremented. Refcount - * of the passed @prev node is not decremented, the caller have to use - * of_node_put() on it when done. - */ -struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent, - struct device_node *prev) -{ - struct device_node *endpoint; - struct device_node *port = NULL; - - if (!parent) - return NULL; - - if (!prev) { - struct device_node *node; - /* - * It's the first call, we have to find a port subnode - * within this node or within an optional 'ports' node. - */ - node = of_get_child_by_name(parent, "ports"); - if (node) - parent = node; - - port = of_get_child_by_name(parent, "port"); - - if (port) { - /* Found a port, get an endpoint. */ - endpoint = of_get_next_child(port, NULL); - of_node_put(port); - } else { - endpoint = NULL; - } - - if (!endpoint) - pr_err("%s(): no endpoint nodes specified for %s\n", - __func__, parent->full_name); - of_node_put(node); - } else { - port = of_get_parent(prev); - if (!port) - /* Hm, has someone given us the root node ?... */ - return NULL; - - /* Avoid dropping prev node refcount to 0. */ - of_node_get(prev); - endpoint = of_get_next_child(port, prev); - if (endpoint) { - of_node_put(port); - return endpoint; - } - - /* No more endpoints under this port, try the next one. */ - do { - port = of_get_next_child(parent, port); - if (!port) - return NULL; - } while (of_node_cmp(port->name, "port")); - - /* Pick up the first endpoint in this port. */ - endpoint = of_get_next_child(port, NULL); - of_node_put(port); - } - - return endpoint; -} -EXPORT_SYMBOL(v4l2_of_get_next_endpoint); - -/** - * v4l2_of_get_remote_port_parent() - get remote port's parent node - * @node: pointer to a local endpoint device_node - * - * Return: Remote device node associated with remote endpoint node linked - * to @node. Use of_node_put() on it when done. - */ -struct device_node *v4l2_of_get_remote_port_parent( - const struct device_node *node) -{ - struct device_node *np; - unsigned int depth; - - /* Get remote endpoint node. */ - np = of_parse_phandle(node, "remote-endpoint", 0); - - /* Walk 3 levels up only if there is 'ports' node. */ - for (depth = 3; depth && np; depth--) { - np = of_get_next_parent(np); - if (depth == 2 && of_node_cmp(np->name, "ports")) - break; - } - return np; -} -EXPORT_SYMBOL(v4l2_of_get_remote_port_parent); - -/** - * v4l2_of_get_remote_port() - get remote port node - * @node: pointer to a local endpoint device_node - * - * Return: Remote port node associated with remote endpoint node linked - * to @node. Use of_node_put() on it when done. - */ -struct device_node *v4l2_of_get_remote_port(const struct device_node *node) -{ - struct device_node *np; - - /* Get remote endpoint node. */ - np = of_parse_phandle(node, "remote-endpoint", 0); - if (!np) - return NULL; - return of_get_next_parent(np); -} -EXPORT_SYMBOL(v4l2_of_get_remote_port); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 809afebe0dad..1cb74085e410 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -526,4 +526,5 @@ source "drivers/misc/mei/Kconfig" source "drivers/misc/vmw_vmci/Kconfig" source "drivers/misc/mic/Kconfig" source "drivers/misc/genwqe/Kconfig" +source "drivers/misc/echo/Kconfig" endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 99b9424ce31d..7eb4b69580c0 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -54,3 +54,4 @@ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o obj-y += mic/ obj-$(CONFIG_GENWQE) += genwqe/ +obj-$(CONFIG_ECHO) += echo/ diff --git a/drivers/staging/echo/Kconfig b/drivers/misc/echo/Kconfig similarity index 100% rename from drivers/staging/echo/Kconfig rename to drivers/misc/echo/Kconfig diff --git a/drivers/staging/echo/Makefile b/drivers/misc/echo/Makefile similarity index 100% rename from drivers/staging/echo/Makefile rename to drivers/misc/echo/Makefile diff --git a/drivers/staging/echo/echo.c b/drivers/misc/echo/echo.c similarity index 100% rename from drivers/staging/echo/echo.c rename to drivers/misc/echo/echo.c diff --git a/drivers/staging/echo/echo.h b/drivers/misc/echo/echo.h similarity index 100% rename from drivers/staging/echo/echo.h rename to drivers/misc/echo/echo.h diff --git a/drivers/staging/echo/fir.h b/drivers/misc/echo/fir.h similarity index 100% rename from drivers/staging/echo/fir.h rename to drivers/misc/echo/fir.h diff --git a/drivers/staging/echo/oslec.h b/drivers/misc/echo/oslec.h similarity index 100% rename from drivers/staging/echo/oslec.h rename to drivers/misc/echo/oslec.h diff --git a/drivers/of/base.c b/drivers/of/base.c index 1b95a405628f..5f81bfea5246 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -2014,3 +2015,153 @@ struct device_node *of_find_next_cache_node(const struct device_node *np) return NULL; } + +/** + * of_graph_parse_endpoint() - parse common endpoint node properties + * @node: pointer to endpoint device_node + * @endpoint: pointer to the OF endpoint data structure + * + * The caller should hold a reference to @node. + */ +int of_graph_parse_endpoint(const struct device_node *node, + struct of_endpoint *endpoint) +{ + struct device_node *port_node = of_get_parent(node); + + WARN_ONCE(!port_node, "%s(): endpoint %s has no parent node\n", + __func__, node->full_name); + + memset(endpoint, 0, sizeof(*endpoint)); + + endpoint->local_node = node; + /* + * It doesn't matter whether the two calls below succeed. + * If they don't then the default value 0 is used. + */ + of_property_read_u32(port_node, "reg", &endpoint->port); + of_property_read_u32(node, "reg", &endpoint->id); + + of_node_put(port_node); + + return 0; +} +EXPORT_SYMBOL(of_graph_parse_endpoint); + +/** + * of_graph_get_next_endpoint() - get next endpoint node + * @parent: pointer to the parent device node + * @prev: previous endpoint node, or NULL to get first + * + * Return: An 'endpoint' node pointer with refcount incremented. Refcount + * of the passed @prev node is not decremented, the caller have to use + * of_node_put() on it when done. + */ +struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, + struct device_node *prev) +{ + struct device_node *endpoint; + struct device_node *port = NULL; + + if (!parent) + return NULL; + + if (!prev) { + struct device_node *node; + /* + * It's the first call, we have to find a port subnode + * within this node or within an optional 'ports' node. + */ + node = of_get_child_by_name(parent, "ports"); + if (node) + parent = node; + + port = of_get_child_by_name(parent, "port"); + + if (port) { + /* Found a port, get an endpoint. */ + endpoint = of_get_next_child(port, NULL); + of_node_put(port); + } else { + endpoint = NULL; + } + + if (!endpoint) + pr_err("%s(): no endpoint nodes specified for %s\n", + __func__, parent->full_name); + of_node_put(node); + + return endpoint; + } + + port = of_get_parent(prev); + if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n", + __func__, prev->full_name)) + return NULL; + + /* Avoid dropping prev node refcount to 0. */ + of_node_get(prev); + endpoint = of_get_next_child(port, prev); + if (endpoint) { + of_node_put(port); + return endpoint; + } + + /* No more endpoints under this port, try the next one. */ + do { + port = of_get_next_child(parent, port); + if (!port) + return NULL; + } while (of_node_cmp(port->name, "port")); + + /* Pick up the first endpoint in this port. */ + endpoint = of_get_next_child(port, NULL); + of_node_put(port); + + return endpoint; +} +EXPORT_SYMBOL(of_graph_get_next_endpoint); + +/** + * of_graph_get_remote_port_parent() - get remote port's parent node + * @node: pointer to a local endpoint device_node + * + * Return: Remote device node associated with remote endpoint node linked + * to @node. Use of_node_put() on it when done. + */ +struct device_node *of_graph_get_remote_port_parent( + const struct device_node *node) +{ + struct device_node *np; + unsigned int depth; + + /* Get remote endpoint node. */ + np = of_parse_phandle(node, "remote-endpoint", 0); + + /* Walk 3 levels up only if there is 'ports' node. */ + for (depth = 3; depth && np; depth--) { + np = of_get_next_parent(np); + if (depth == 2 && of_node_cmp(np->name, "ports")) + break; + } + return np; +} +EXPORT_SYMBOL(of_graph_get_remote_port_parent); + +/** + * of_graph_get_remote_port() - get remote port node + * @node: pointer to a local endpoint device_node + * + * Return: Remote port node associated with remote endpoint node linked + * to @node. Use of_node_put() on it when done. + */ +struct device_node *of_graph_get_remote_port(const struct device_node *node) +{ + struct device_node *np; + + /* Get remote endpoint node. */ + np = of_parse_phandle(node, "remote-endpoint", 0); + if (!np) + return NULL; + return of_get_next_parent(np); +} +EXPORT_SYMBOL(of_graph_get_remote_port); diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 99375f0a9440..47cf17543008 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -34,8 +34,6 @@ source "drivers/staging/winbond/Kconfig" source "drivers/staging/wlan-ng/Kconfig" -source "drivers/staging/echo/Kconfig" - source "drivers/staging/comedi/Kconfig" source "drivers/staging/olpc_dcon/Kconfig" @@ -82,8 +80,6 @@ source "drivers/staging/wlags49_h2/Kconfig" source "drivers/staging/wlags49_h25/Kconfig" -source "drivers/staging/sm7xxfb/Kconfig" - source "drivers/staging/crystalhd/Kconfig" source "drivers/staging/cxt1e1/Kconfig" @@ -128,8 +124,6 @@ source "drivers/staging/imx-drm/Kconfig" source "drivers/staging/dgrp/Kconfig" -source "drivers/staging/sb105x/Kconfig" - source "drivers/staging/fwserial/Kconfig" source "drivers/staging/goldfish/Kconfig" @@ -146,4 +140,10 @@ source "drivers/staging/dgnc/Kconfig" source "drivers/staging/dgap/Kconfig" +source "drivers/staging/gs_fpgaboot/Kconfig" + +source "drivers/staging/nokia_h4p/Kconfig" + +source "drivers/staging/unisys/Kconfig" + endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index ddc3c4a5d39d..d12f6189db46 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_SLICOSS) += slicoss/ obj-$(CONFIG_USBIP_CORE) += usbip/ obj-$(CONFIG_W35UND) += winbond/ obj-$(CONFIG_PRISM2_USB) += wlan-ng/ -obj-$(CONFIG_ECHO) += echo/ obj-$(CONFIG_COMEDI) += comedi/ obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/ obj-$(CONFIG_PANEL) += panel/ @@ -35,7 +34,6 @@ obj-$(CONFIG_DX_SEP) += sep/ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ -obj-$(CONFIG_FB_SM7XX) += sm7xxfb/ obj-$(CONFIG_CRYSTALHD) += crystalhd/ obj-$(CONFIG_CXT1E1) += cxt1e1/ obj-$(CONFIG_FB_XGI) += xgifb/ @@ -57,7 +55,6 @@ obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/ obj-$(CONFIG_CED1401) += ced1401/ obj-$(CONFIG_DRM_IMX) += imx-drm/ obj-$(CONFIG_DGRP) += dgrp/ -obj-$(CONFIG_SB105X) += sb105x/ obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/ obj-$(CONFIG_GOLDFISH) += goldfish/ obj-$(CONFIG_LUSTRE_FS) += lustre/ @@ -65,3 +62,6 @@ obj-$(CONFIG_XILLYBUS) += xillybus/ obj-$(CONFIG_DGNC) += dgnc/ obj-$(CONFIG_DGAP) += dgap/ obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand/ +obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/ +obj-$(CONFIG_BT_NOKIA_H4P) += nokia_h4p/ +obj-$(CONFIG_UNISYSSPAR) += unisys/ diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index b91c758883bf..ab28d2b5e308 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -20,6 +20,19 @@ config ANDROID_BINDER_IPC Android process, using Binder to identify, invoke and pass arguments between said processes. +config ANDROID_BINDER_IPC_32BIT + bool + depends on !64BIT && ANDROID_BINDER_IPC + default y + ---help--- + The Binder API has been changed to support both 32 and 64bit + applications in a mixed environment. + + Enable this to support an old 32-bit Android user-space (v4.4 and + earlier). + + Note that enabling this will break newer Android user-space. + config ASHMEM bool "Enable the Anonymous Shared Memory Subsystem" default n diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h index 4fd32f337f9c..495b20cf3bf6 100644 --- a/drivers/staging/android/android_alarm.h +++ b/drivers/staging/android/android_alarm.h @@ -16,50 +16,10 @@ #ifndef _LINUX_ANDROID_ALARM_H #define _LINUX_ANDROID_ALARM_H -#include -#include #include +#include -enum android_alarm_type { - /* return code bit numbers or set alarm arg */ - ANDROID_ALARM_RTC_WAKEUP, - ANDROID_ALARM_RTC, - ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, - ANDROID_ALARM_ELAPSED_REALTIME, - ANDROID_ALARM_SYSTEMTIME, - - ANDROID_ALARM_TYPE_COUNT, - - /* return code bit numbers */ - /* ANDROID_ALARM_TIME_CHANGE = 16 */ -}; - -enum android_alarm_return_flags { - ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP, - ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC, - ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK = - 1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, - ANDROID_ALARM_ELAPSED_REALTIME_MASK = - 1U << ANDROID_ALARM_ELAPSED_REALTIME, - ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME, - ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16 -}; - -/* Disable alarm */ -#define ANDROID_ALARM_CLEAR(type) _IO('a', 0 | ((type) << 4)) - -/* Ack last alarm and wait for next */ -#define ANDROID_ALARM_WAIT _IO('a', 1) - -#define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size) -/* Set alarm */ -#define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec) -#define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec) -#define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec) -#define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec) -#define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0))) -#define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4) - +#include "uapi/android_alarm.h" #ifdef CONFIG_COMPAT #define ANDROID_ALARM_SET_COMPAT(type) ALARM_IOW(2, type, \ diff --git a/drivers/staging/android/ashmem.h b/drivers/staging/android/ashmem.h index 8dc0f0d3adf3..5abcfd7aa706 100644 --- a/drivers/staging/android/ashmem.h +++ b/drivers/staging/android/ashmem.h @@ -16,35 +16,7 @@ #include #include -#define ASHMEM_NAME_LEN 256 - -#define ASHMEM_NAME_DEF "dev/ashmem" - -/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */ -#define ASHMEM_NOT_PURGED 0 -#define ASHMEM_WAS_PURGED 1 - -/* Return values from ASHMEM_GET_PIN_STATUS: Is the mapping pinned? */ -#define ASHMEM_IS_UNPINNED 0 -#define ASHMEM_IS_PINNED 1 - -struct ashmem_pin { - __u32 offset; /* offset into region, in bytes, page-aligned */ - __u32 len; /* length forward from offset, in bytes, page-aligned */ -}; - -#define __ASHMEMIOC 0x77 - -#define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN]) -#define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN]) -#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t) -#define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4) -#define ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned long) -#define ASHMEM_GET_PROT_MASK _IO(__ASHMEMIOC, 6) -#define ASHMEM_PIN _IOW(__ASHMEMIOC, 7, struct ashmem_pin) -#define ASHMEM_UNPIN _IOW(__ASHMEMIOC, 8, struct ashmem_pin) -#define ASHMEM_GET_PIN_STATUS _IO(__ASHMEMIOC, 9) -#define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10) +#include "uapi/ashmem.h" /* support of 32bit userspace on 64bit platforms */ #ifdef CONFIG_COMPAT diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index 1432d956769c..cfe4bc8f05cb 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -228,8 +228,8 @@ struct binder_node { int internal_strong_refs; int local_weak_refs; int local_strong_refs; - void __user *ptr; - void __user *cookie; + binder_uintptr_t ptr; + binder_uintptr_t cookie; unsigned has_strong_ref:1; unsigned pending_strong_ref:1; unsigned has_weak_ref:1; @@ -242,7 +242,7 @@ struct binder_node { struct binder_ref_death { struct binder_work work; - void __user *cookie; + binder_uintptr_t cookie; }; struct binder_ref { @@ -515,14 +515,14 @@ static void binder_insert_allocated_buffer(struct binder_proc *proc, } static struct binder_buffer *binder_buffer_lookup(struct binder_proc *proc, - void __user *user_ptr) + uintptr_t user_ptr) { struct rb_node *n = proc->allocated_buffers.rb_node; struct binder_buffer *buffer; struct binder_buffer *kern_ptr; - kern_ptr = user_ptr - proc->user_buffer_offset - - offsetof(struct binder_buffer, data); + kern_ptr = (struct binder_buffer *)(user_ptr - proc->user_buffer_offset + - offsetof(struct binder_buffer, data)); while (n) { buffer = rb_entry(n, struct binder_buffer, rb_node); @@ -856,7 +856,7 @@ static void binder_free_buf(struct binder_proc *proc, } static struct binder_node *binder_get_node(struct binder_proc *proc, - void __user *ptr) + binder_uintptr_t ptr) { struct rb_node *n = proc->nodes.rb_node; struct binder_node *node; @@ -875,8 +875,8 @@ static struct binder_node *binder_get_node(struct binder_proc *proc, } static struct binder_node *binder_new_node(struct binder_proc *proc, - void __user *ptr, - void __user *cookie) + binder_uintptr_t ptr, + binder_uintptr_t cookie) { struct rb_node **p = &proc->nodes.rb_node; struct rb_node *parent = NULL; @@ -908,9 +908,9 @@ static struct binder_node *binder_new_node(struct binder_proc *proc, INIT_LIST_HEAD(&node->work.entry); INIT_LIST_HEAD(&node->async_todo); binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%p c%p created\n", + "%d:%d node %d u%016llx c%016llx created\n", proc->pid, current->pid, node->debug_id, - node->ptr, node->cookie); + (u64)node->ptr, (u64)node->cookie); return node; } @@ -1226,9 +1226,9 @@ static void binder_send_failed_reply(struct binder_transaction *t, static void binder_transaction_buffer_release(struct binder_proc *proc, struct binder_buffer *buffer, - size_t *failed_at) + binder_size_t *failed_at) { - size_t *offp, *off_end; + binder_size_t *offp, *off_end; int debug_id = buffer->debug_id; binder_debug(BINDER_DEBUG_TRANSACTION, @@ -1239,7 +1239,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, if (buffer->target_node) binder_dec_node(buffer->target_node, 1, 0); - offp = (size_t *)(buffer->data + ALIGN(buffer->data_size, sizeof(void *))); + offp = (binder_size_t *)(buffer->data + + ALIGN(buffer->data_size, sizeof(void *))); if (failed_at) off_end = failed_at; else @@ -1249,8 +1250,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, if (*offp > buffer->data_size - sizeof(*fp) || buffer->data_size < sizeof(*fp) || !IS_ALIGNED(*offp, sizeof(u32))) { - pr_err("transaction release %d bad offset %zd, size %zd\n", - debug_id, *offp, buffer->data_size); + pr_err("transaction release %d bad offset %lld, size %zd\n", + debug_id, (u64)*offp, buffer->data_size); continue; } fp = (struct flat_binder_object *)(buffer->data + *offp); @@ -1259,13 +1260,13 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, case BINDER_TYPE_WEAK_BINDER: { struct binder_node *node = binder_get_node(proc, fp->binder); if (node == NULL) { - pr_err("transaction release %d bad node %p\n", - debug_id, fp->binder); + pr_err("transaction release %d bad node %016llx\n", + debug_id, (u64)fp->binder); break; } binder_debug(BINDER_DEBUG_TRANSACTION, - " node %d u%p\n", - node->debug_id, node->ptr); + " node %d u%016llx\n", + node->debug_id, (u64)node->ptr); binder_dec_node(node, fp->type == BINDER_TYPE_BINDER, 0); } break; case BINDER_TYPE_HANDLE: @@ -1303,7 +1304,7 @@ static void binder_transaction(struct binder_proc *proc, { struct binder_transaction *t; struct binder_work *tcomplete; - size_t *offp, *off_end; + binder_size_t *offp, *off_end; struct binder_proc *target_proc; struct binder_thread *target_thread = NULL; struct binder_node *target_node = NULL; @@ -1432,18 +1433,20 @@ static void binder_transaction(struct binder_proc *proc, if (reply) binder_debug(BINDER_DEBUG_TRANSACTION, - "%d:%d BC_REPLY %d -> %d:%d, data %p-%p size %zd-%zd\n", + "%d:%d BC_REPLY %d -> %d:%d, data %016llx-%016llx size %lld-%lld\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_thread->pid, - tr->data.ptr.buffer, tr->data.ptr.offsets, - tr->data_size, tr->offsets_size); + (u64)tr->data.ptr.buffer, + (u64)tr->data.ptr.offsets, + (u64)tr->data_size, (u64)tr->offsets_size); else binder_debug(BINDER_DEBUG_TRANSACTION, - "%d:%d BC_TRANSACTION %d -> %d - node %d, data %p-%p size %zd-%zd\n", + "%d:%d BC_TRANSACTION %d -> %d - node %d, data %016llx-%016llx size %lld-%lld\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_node->debug_id, - tr->data.ptr.buffer, tr->data.ptr.offsets, - tr->data_size, tr->offsets_size); + (u64)tr->data.ptr.buffer, + (u64)tr->data.ptr.offsets, + (u64)tr->data_size, (u64)tr->offsets_size); if (!reply && !(tr->flags & TF_ONE_WAY)) t->from = thread; @@ -1472,23 +1475,26 @@ static void binder_transaction(struct binder_proc *proc, if (target_node) binder_inc_node(target_node, 1, 0, NULL); - offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *))); + offp = (binder_size_t *)(t->buffer->data + + ALIGN(tr->data_size, sizeof(void *))); - if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) { + if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t) + tr->data.ptr.buffer, tr->data_size)) { binder_user_error("%d:%d got transaction with invalid data ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed; } - if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) { + if (copy_from_user(offp, (const void __user *)(uintptr_t) + tr->data.ptr.offsets, tr->offsets_size)) { binder_user_error("%d:%d got transaction with invalid offsets ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed; } - if (!IS_ALIGNED(tr->offsets_size, sizeof(size_t))) { - binder_user_error("%d:%d got transaction with invalid offsets size, %zd\n", - proc->pid, thread->pid, tr->offsets_size); + if (!IS_ALIGNED(tr->offsets_size, sizeof(binder_size_t))) { + binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n", + proc->pid, thread->pid, (u64)tr->offsets_size); return_error = BR_FAILED_REPLY; goto err_bad_offset; } @@ -1498,8 +1504,8 @@ static void binder_transaction(struct binder_proc *proc, if (*offp > t->buffer->data_size - sizeof(*fp) || t->buffer->data_size < sizeof(*fp) || !IS_ALIGNED(*offp, sizeof(u32))) { - binder_user_error("%d:%d got transaction with invalid offset, %zd\n", - proc->pid, thread->pid, *offp); + binder_user_error("%d:%d got transaction with invalid offset, %lld\n", + proc->pid, thread->pid, (u64)*offp); return_error = BR_FAILED_REPLY; goto err_bad_offset; } @@ -1519,10 +1525,10 @@ static void binder_transaction(struct binder_proc *proc, node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); } if (fp->cookie != node->cookie) { - binder_user_error("%d:%d sending u%p node %d, cookie mismatch %p != %p\n", + binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, - fp->binder, node->debug_id, - fp->cookie, node->cookie); + (u64)fp->binder, node->debug_id, + (u64)fp->cookie, (u64)node->cookie); goto err_binder_get_ref_for_node_failed; } ref = binder_get_ref_for_node(target_proc, node); @@ -1540,9 +1546,9 @@ static void binder_transaction(struct binder_proc *proc, trace_binder_transaction_node_to_ref(t, node, ref); binder_debug(BINDER_DEBUG_TRANSACTION, - " node %d u%p -> ref %d desc %d\n", - node->debug_id, node->ptr, ref->debug_id, - ref->desc); + " node %d u%016llx -> ref %d desc %d\n", + node->debug_id, (u64)node->ptr, + ref->debug_id, ref->desc); } break; case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { @@ -1564,9 +1570,9 @@ static void binder_transaction(struct binder_proc *proc, binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL); trace_binder_transaction_ref_to_node(t, ref); binder_debug(BINDER_DEBUG_TRANSACTION, - " ref %d desc %d -> node %d u%p\n", + " ref %d desc %d -> node %d u%016llx\n", ref->debug_id, ref->desc, ref->node->debug_id, - ref->node->ptr); + (u64)ref->node->ptr); } else { struct binder_ref *new_ref; new_ref = binder_get_ref_for_node(target_proc, ref->node); @@ -1682,9 +1688,9 @@ err_dead_binder: err_invalid_target_handle: err_no_context_mgr_node: binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "%d:%d transaction failed %d, size %zd-%zd\n", + "%d:%d transaction failed %d, size %lld-%lld\n", proc->pid, thread->pid, return_error, - tr->data_size, tr->offsets_size); + (u64)tr->data_size, (u64)tr->offsets_size); { struct binder_transaction_log_entry *fe; @@ -1702,9 +1708,11 @@ err_no_context_mgr_node: static int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, - void __user *buffer, size_t size, size_t *consumed) + binder_uintptr_t binder_buffer, size_t size, + binder_size_t *consumed) { uint32_t cmd; + void __user *buffer = (void __user *)(uintptr_t)binder_buffer; void __user *ptr = buffer + *consumed; void __user *end = buffer + size; @@ -1773,33 +1781,33 @@ static int binder_thread_write(struct binder_proc *proc, } case BC_INCREFS_DONE: case BC_ACQUIRE_DONE: { - void __user *node_ptr; - void __user *cookie; + binder_uintptr_t node_ptr; + binder_uintptr_t cookie; struct binder_node *node; - if (get_user(node_ptr, (void * __user *)ptr)) + if (get_user(node_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); - if (get_user(cookie, (void * __user *)ptr)) + ptr += sizeof(binder_uintptr_t); + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); node = binder_get_node(proc, node_ptr); if (node == NULL) { - binder_user_error("%d:%d %s u%p no match\n", + binder_user_error("%d:%d %s u%016llx no match\n", proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", - node_ptr); + (u64)node_ptr); break; } if (cookie != node->cookie) { - binder_user_error("%d:%d %s u%p node %d cookie mismatch %p != %p\n", + binder_user_error("%d:%d %s u%016llx node %d cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", - node_ptr, node->debug_id, - cookie, node->cookie); + (u64)node_ptr, node->debug_id, + (u64)cookie, (u64)node->cookie); break; } if (cmd == BC_ACQUIRE_DONE) { @@ -1835,27 +1843,28 @@ static int binder_thread_write(struct binder_proc *proc, return -EINVAL; case BC_FREE_BUFFER: { - void __user *data_ptr; + binder_uintptr_t data_ptr; struct binder_buffer *buffer; - if (get_user(data_ptr, (void * __user *)ptr)) + if (get_user(data_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); buffer = binder_buffer_lookup(proc, data_ptr); if (buffer == NULL) { - binder_user_error("%d:%d BC_FREE_BUFFER u%p no match\n", - proc->pid, thread->pid, data_ptr); + binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n", + proc->pid, thread->pid, (u64)data_ptr); break; } if (!buffer->allow_user_free) { - binder_user_error("%d:%d BC_FREE_BUFFER u%p matched unreturned buffer\n", - proc->pid, thread->pid, data_ptr); + binder_user_error("%d:%d BC_FREE_BUFFER u%016llx matched unreturned buffer\n", + proc->pid, thread->pid, (u64)data_ptr); break; } binder_debug(BINDER_DEBUG_FREE_BUFFER, - "%d:%d BC_FREE_BUFFER u%p found buffer %d for %s transaction\n", - proc->pid, thread->pid, data_ptr, buffer->debug_id, + "%d:%d BC_FREE_BUFFER u%016llx found buffer %d for %s transaction\n", + proc->pid, thread->pid, (u64)data_ptr, + buffer->debug_id, buffer->transaction ? "active" : "finished"); if (buffer->transaction) { @@ -1925,16 +1934,16 @@ static int binder_thread_write(struct binder_proc *proc, case BC_REQUEST_DEATH_NOTIFICATION: case BC_CLEAR_DEATH_NOTIFICATION: { uint32_t target; - void __user *cookie; + binder_uintptr_t cookie; struct binder_ref *ref; struct binder_ref_death *death; if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (get_user(cookie, (void __user * __user *)ptr)) + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); ref = binder_get_ref(proc, target); if (ref == NULL) { binder_user_error("%d:%d %s invalid ref %d\n", @@ -1947,12 +1956,12 @@ static int binder_thread_write(struct binder_proc *proc, } binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, - "%d:%d %s %p ref %d desc %d s %d w %d for node %d\n", + "%d:%d %s %016llx ref %d desc %d s %d w %d for node %d\n", proc->pid, thread->pid, cmd == BC_REQUEST_DEATH_NOTIFICATION ? "BC_REQUEST_DEATH_NOTIFICATION" : "BC_CLEAR_DEATH_NOTIFICATION", - cookie, ref->debug_id, ref->desc, + (u64)cookie, ref->debug_id, ref->desc, ref->strong, ref->weak, ref->node->debug_id); if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { @@ -1990,9 +1999,10 @@ static int binder_thread_write(struct binder_proc *proc, } death = ref->death; if (death->cookie != cookie) { - binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %p != %p\n", + binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, - death->cookie, cookie); + (u64)death->cookie, + (u64)cookie); break; } ref->death = NULL; @@ -2012,9 +2022,9 @@ static int binder_thread_write(struct binder_proc *proc, } break; case BC_DEAD_BINDER_DONE: { struct binder_work *w; - void __user *cookie; + binder_uintptr_t cookie; struct binder_ref_death *death = NULL; - if (get_user(cookie, (void __user * __user *)ptr)) + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(void *); @@ -2026,11 +2036,12 @@ static int binder_thread_write(struct binder_proc *proc, } } binder_debug(BINDER_DEBUG_DEAD_BINDER, - "%d:%d BC_DEAD_BINDER_DONE %p found %p\n", - proc->pid, thread->pid, cookie, death); + "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n", + proc->pid, thread->pid, (u64)cookie, + death); if (death == NULL) { - binder_user_error("%d:%d BC_DEAD_BINDER_DONE %p not found\n", - proc->pid, thread->pid, cookie); + binder_user_error("%d:%d BC_DEAD_BINDER_DONE %016llx not found\n", + proc->pid, thread->pid, (u64)cookie); break; } @@ -2082,9 +2093,10 @@ static int binder_has_thread_work(struct binder_thread *thread) static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, - void __user *buffer, size_t size, - size_t *consumed, int non_block) + binder_uintptr_t binder_buffer, size_t size, + binder_size_t *consumed, int non_block) { + void __user *buffer = (void __user *)(uintptr_t)binder_buffer; void __user *ptr = buffer + *consumed; void __user *end = buffer + size; @@ -2229,32 +2241,40 @@ retry: if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (put_user(node->ptr, (void * __user *)ptr)) + if (put_user(node->ptr, + (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); - if (put_user(node->cookie, (void * __user *)ptr)) + ptr += sizeof(binder_uintptr_t); + if (put_user(node->cookie, + (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); binder_stat_br(proc, thread, cmd); binder_debug(BINDER_DEBUG_USER_REFS, - "%d:%d %s %d u%p c%p\n", - proc->pid, thread->pid, cmd_name, node->debug_id, node->ptr, node->cookie); + "%d:%d %s %d u%016llx c%016llx\n", + proc->pid, thread->pid, cmd_name, + node->debug_id, + (u64)node->ptr, (u64)node->cookie); } else { list_del_init(&w->entry); if (!weak && !strong) { binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%p c%p deleted\n", - proc->pid, thread->pid, node->debug_id, - node->ptr, node->cookie); + "%d:%d node %d u%016llx c%016llx deleted\n", + proc->pid, thread->pid, + node->debug_id, + (u64)node->ptr, + (u64)node->cookie); rb_erase(&node->rb_node, &proc->nodes); kfree(node); binder_stats_deleted(BINDER_STAT_NODE); } else { binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%p c%p state unchanged\n", - proc->pid, thread->pid, node->debug_id, node->ptr, - node->cookie); + "%d:%d node %d u%016llx c%016llx state unchanged\n", + proc->pid, thread->pid, + node->debug_id, + (u64)node->ptr, + (u64)node->cookie); } } } break; @@ -2272,17 +2292,18 @@ retry: if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (put_user(death->cookie, (void * __user *)ptr)) + if (put_user(death->cookie, + (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); binder_stat_br(proc, thread, cmd); binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, - "%d:%d %s %p\n", + "%d:%d %s %016llx\n", proc->pid, thread->pid, cmd == BR_DEAD_BINDER ? "BR_DEAD_BINDER" : "BR_CLEAR_DEATH_NOTIFICATION_DONE", - death->cookie); + (u64)death->cookie); if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) { list_del(&w->entry); @@ -2312,8 +2333,8 @@ retry: binder_set_nice(target_node->min_priority); cmd = BR_TRANSACTION; } else { - tr.target.ptr = NULL; - tr.cookie = NULL; + tr.target.ptr = 0; + tr.cookie = 0; cmd = BR_REPLY; } tr.code = t->code; @@ -2330,8 +2351,9 @@ retry: tr.data_size = t->buffer->data_size; tr.offsets_size = t->buffer->offsets_size; - tr.data.ptr.buffer = (void *)t->buffer->data + - proc->user_buffer_offset; + tr.data.ptr.buffer = (binder_uintptr_t)( + (uintptr_t)t->buffer->data + + proc->user_buffer_offset); tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *)); @@ -2346,14 +2368,14 @@ retry: trace_binder_transaction_received(t); binder_stat_br(proc, thread, cmd); binder_debug(BINDER_DEBUG_TRANSACTION, - "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %p-%p\n", + "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n", proc->pid, thread->pid, (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : "BR_REPLY", t->debug_id, t->from ? t->from->proc->pid : 0, t->from ? t->from->pid : 0, cmd, t->buffer->data_size, t->buffer->offsets_size, - tr.data.ptr.buffer, tr.data.ptr.offsets); + (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets); list_del(&t->work.entry); t->buffer->allow_user_free = 1; @@ -2423,8 +2445,8 @@ static void binder_release_work(struct list_head *list) death = container_of(w, struct binder_ref_death, work); binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, - "undelivered death notification, %p\n", - death->cookie); + "undelivered death notification, %016llx\n", + (u64)death->cookie); kfree(death); binder_stats_deleted(BINDER_STAT_DEATH); } break; @@ -2580,12 +2602,16 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) goto err; } binder_debug(BINDER_DEBUG_READ_WRITE, - "%d:%d write %zd at %016lx, read %zd at %016lx\n", - proc->pid, thread->pid, bwr.write_size, - bwr.write_buffer, bwr.read_size, bwr.read_buffer); + "%d:%d write %lld at %016llx, read %lld at %016llx\n", + proc->pid, thread->pid, + (u64)bwr.write_size, (u64)bwr.write_buffer, + (u64)bwr.read_size, (u64)bwr.read_buffer); if (bwr.write_size > 0) { - ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed); + ret = binder_thread_write(proc, thread, + bwr.write_buffer, + bwr.write_size, + &bwr.write_consumed); trace_binder_write_done(ret); if (ret < 0) { bwr.read_consumed = 0; @@ -2595,7 +2621,10 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } } if (bwr.read_size > 0) { - ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); + ret = binder_thread_read(proc, thread, bwr.read_buffer, + bwr.read_size, + &bwr.read_consumed, + filp->f_flags & O_NONBLOCK); trace_binder_read_done(ret); if (!list_empty(&proc->todo)) wake_up_interruptible(&proc->wait); @@ -2606,9 +2635,10 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } } binder_debug(BINDER_DEBUG_READ_WRITE, - "%d:%d wrote %zd of %zd, read return %zd of %zd\n", - proc->pid, thread->pid, bwr.write_consumed, bwr.write_size, - bwr.read_consumed, bwr.read_size); + "%d:%d wrote %lld of %lld, read return %lld of %lld\n", + proc->pid, thread->pid, + (u64)bwr.write_consumed, (u64)bwr.write_size, + (u64)bwr.read_consumed, (u64)bwr.read_size); if (copy_to_user(ubuf, &bwr, sizeof(bwr))) { ret = -EFAULT; goto err; @@ -2637,7 +2667,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } } else binder_context_mgr_uid = current->cred->euid; - binder_context_mgr_node = binder_new_node(proc, NULL, NULL); + binder_context_mgr_node = binder_new_node(proc, 0, 0); if (binder_context_mgr_node == NULL) { ret = -ENOMEM; goto err; @@ -3132,8 +3162,9 @@ static void print_binder_work(struct seq_file *m, const char *prefix, break; case BINDER_WORK_NODE: node = container_of(w, struct binder_node, work); - seq_printf(m, "%snode work %d: u%p c%p\n", - prefix, node->debug_id, node->ptr, node->cookie); + seq_printf(m, "%snode work %d: u%016llx c%016llx\n", + prefix, node->debug_id, + (u64)node->ptr, (u64)node->cookie); break; case BINDER_WORK_DEAD_BINDER: seq_printf(m, "%shas dead binder\n", prefix); @@ -3193,8 +3224,8 @@ static void print_binder_node(struct seq_file *m, struct binder_node *node) hlist_for_each_entry(ref, &node->refs, node_entry) count++; - seq_printf(m, " node %d: u%p c%p hs %d hw %d ls %d lw %d is %d iw %d", - node->debug_id, node->ptr, node->cookie, + seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d", + node->debug_id, (u64)node->ptr, (u64)node->cookie, node->has_strong_ref, node->has_weak_ref, node->local_strong_refs, node->local_weak_refs, node->internal_strong_refs, count); @@ -3496,6 +3527,7 @@ static const struct file_operations binder_fops = { .owner = THIS_MODULE, .poll = binder_poll, .unlocked_ioctl = binder_ioctl, + .compat_ioctl = binder_ioctl, .mmap = binder_mmap, .open = binder_open, .flush = binder_flush, diff --git a/drivers/staging/android/binder.h b/drivers/staging/android/binder.h index cbe345168067..eb0834656dfe 100644 --- a/drivers/staging/android/binder.h +++ b/drivers/staging/android/binder.h @@ -20,311 +20,11 @@ #ifndef _LINUX_BINDER_H #define _LINUX_BINDER_H -#include +#ifdef CONFIG_ANDROID_BINDER_IPC_32BIT +#define BINDER_IPC_32BIT 1 +#endif -#define B_PACK_CHARS(c1, c2, c3, c4) \ - ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4)) -#define B_TYPE_LARGE 0x85 - -enum { - BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE), - BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE), - BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE), - BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE), - BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE), -}; - -enum { - FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff, - FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100, -}; - -/* - * This is the flattened representation of a Binder object for transfer - * between processes. The 'offsets' supplied as part of a binder transaction - * contains offsets into the data where these structures occur. The Binder - * driver takes care of re-writing the structure type and data as it moves - * between processes. - */ -struct flat_binder_object { - /* 8 bytes for large_flat_header. */ - __u32 type; - __u32 flags; - - /* 8 bytes of data. */ - union { - void __user *binder; /* local object */ - __u32 handle; /* remote object */ - }; - - /* extra data associated with local object */ - void __user *cookie; -}; - -/* - * On 64-bit platforms where user code may run in 32-bits the driver must - * translate the buffer (and local binder) addresses appropriately. - */ - -struct binder_write_read { - size_t write_size; /* bytes to write */ - size_t write_consumed; /* bytes consumed by driver */ - unsigned long write_buffer; - size_t read_size; /* bytes to read */ - size_t read_consumed; /* bytes consumed by driver */ - unsigned long read_buffer; -}; - -/* Use with BINDER_VERSION, driver fills in fields. */ -struct binder_version { - /* driver protocol version -- increment with incompatible change */ - __s32 protocol_version; -}; - -/* This is the current protocol version. */ -#define BINDER_CURRENT_PROTOCOL_VERSION 7 - -#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) -#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) -#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) -#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32) -#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32) -#define BINDER_THREAD_EXIT _IOW('b', 8, __s32) -#define BINDER_VERSION _IOWR('b', 9, struct binder_version) - -/* - * NOTE: Two special error codes you should check for when calling - * in to the driver are: - * - * EINTR -- The operation has been interupted. This should be - * handled by retrying the ioctl() until a different error code - * is returned. - * - * ECONNREFUSED -- The driver is no longer accepting operations - * from your process. That is, the process is being destroyed. - * You should handle this by exiting from your process. Note - * that once this error code is returned, all further calls to - * the driver from any thread will return this same code. - */ - -enum transaction_flags { - TF_ONE_WAY = 0x01, /* this is a one-way call: async, no return */ - TF_ROOT_OBJECT = 0x04, /* contents are the component's root object */ - TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */ - TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */ -}; - -struct binder_transaction_data { - /* The first two are only used for bcTRANSACTION and brTRANSACTION, - * identifying the target and contents of the transaction. - */ - union { - __u32 handle; /* target descriptor of command transaction */ - void *ptr; /* target descriptor of return transaction */ - } target; - void *cookie; /* target object cookie */ - __u32 code; /* transaction command */ - - /* General information about the transaction. */ - __u32 flags; - pid_t sender_pid; - uid_t sender_euid; - size_t data_size; /* number of bytes of data */ - size_t offsets_size; /* number of bytes of offsets */ - - /* If this transaction is inline, the data immediately - * follows here; otherwise, it ends with a pointer to - * the data buffer. - */ - union { - struct { - /* transaction data */ - const void __user *buffer; - /* offsets from buffer to flat_binder_object structs */ - const void __user *offsets; - } ptr; - __u8 buf[8]; - } data; -}; - -struct binder_ptr_cookie { - void *ptr; - void *cookie; -}; - -struct binder_pri_desc { - __s32 priority; - __u32 desc; -}; - -struct binder_pri_ptr_cookie { - __s32 priority; - void *ptr; - void *cookie; -}; - -enum binder_driver_return_protocol { - BR_ERROR = _IOR('r', 0, __s32), - /* - * int: error code - */ - - BR_OK = _IO('r', 1), - /* No parameters! */ - - BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data), - BR_REPLY = _IOR('r', 3, struct binder_transaction_data), - /* - * binder_transaction_data: the received command. - */ - - BR_ACQUIRE_RESULT = _IOR('r', 4, __s32), - /* - * not currently supported - * int: 0 if the last bcATTEMPT_ACQUIRE was not successful. - * Else the remote object has acquired a primary reference. - */ - - BR_DEAD_REPLY = _IO('r', 5), - /* - * The target of the last transaction (either a bcTRANSACTION or - * a bcATTEMPT_ACQUIRE) is no longer with us. No parameters. - */ - - BR_TRANSACTION_COMPLETE = _IO('r', 6), - /* - * No parameters... always refers to the last transaction requested - * (including replies). Note that this will be sent even for - * asynchronous transactions. - */ - - BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie), - BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie), - BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie), - BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie), - /* - * void *: ptr to binder - * void *: cookie for binder - */ - - BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cookie), - /* - * not currently supported - * int: priority - * void *: ptr to binder - * void *: cookie for binder - */ - - BR_NOOP = _IO('r', 12), - /* - * No parameters. Do nothing and examine the next command. It exists - * primarily so that we can replace it with a BR_SPAWN_LOOPER command. - */ - - BR_SPAWN_LOOPER = _IO('r', 13), - /* - * No parameters. The driver has determined that a process has no - * threads waiting to service incoming transactions. When a process - * receives this command, it must spawn a new service thread and - * register it via bcENTER_LOOPER. - */ - - BR_FINISHED = _IO('r', 14), - /* - * not currently supported - * stop threadpool thread - */ - - BR_DEAD_BINDER = _IOR('r', 15, void *), - /* - * void *: cookie - */ - BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, void *), - /* - * void *: cookie - */ - - BR_FAILED_REPLY = _IO('r', 17), - /* - * The the last transaction (either a bcTRANSACTION or - * a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters. - */ -}; - -enum binder_driver_command_protocol { - BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data), - BC_REPLY = _IOW('c', 1, struct binder_transaction_data), - /* - * binder_transaction_data: the sent command. - */ - - BC_ACQUIRE_RESULT = _IOW('c', 2, __s32), - /* - * not currently supported - * int: 0 if the last BR_ATTEMPT_ACQUIRE was not successful. - * Else you have acquired a primary reference on the object. - */ - - BC_FREE_BUFFER = _IOW('c', 3, void *), - /* - * void *: ptr to transaction data received on a read - */ - - BC_INCREFS = _IOW('c', 4, __u32), - BC_ACQUIRE = _IOW('c', 5, __u32), - BC_RELEASE = _IOW('c', 6, __u32), - BC_DECREFS = _IOW('c', 7, __u32), - /* - * int: descriptor - */ - - BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie), - BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie), - /* - * void *: ptr to binder - * void *: cookie for binder - */ - - BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc), - /* - * not currently supported - * int: priority - * int: descriptor - */ - - BC_REGISTER_LOOPER = _IO('c', 11), - /* - * No parameters. - * Register a spawned looper thread with the device. - */ - - BC_ENTER_LOOPER = _IO('c', 12), - BC_EXIT_LOOPER = _IO('c', 13), - /* - * No parameters. - * These two commands are sent as an application-level thread - * enters and exits the binder loop, respectively. They are - * used so the binder can have an accurate count of the number - * of looping threads it has available. - */ - - BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_ptr_cookie), - /* - * void *: ptr to binder - * void *: cookie - */ - - BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_ptr_cookie), - /* - * void *: ptr to binder - * void *: cookie - */ - - BC_DEAD_BINDER_DONE = _IOW('c', 16, void *), - /* - * void *: cookie - */ -}; +#include "uapi/binder.h" #endif /* _LINUX_BINDER_H */ diff --git a/drivers/staging/android/binder_trace.h b/drivers/staging/android/binder_trace.h index 82a567c2af67..7f20f3dc8369 100644 --- a/drivers/staging/android/binder_trace.h +++ b/drivers/staging/android/binder_trace.h @@ -152,7 +152,7 @@ TRACE_EVENT(binder_transaction_node_to_ref, TP_STRUCT__entry( __field(int, debug_id) __field(int, node_debug_id) - __field(void __user *, node_ptr) + __field(binder_uintptr_t, node_ptr) __field(int, ref_debug_id) __field(uint32_t, ref_desc) ), @@ -163,8 +163,9 @@ TRACE_EVENT(binder_transaction_node_to_ref, __entry->ref_debug_id = ref->debug_id; __entry->ref_desc = ref->desc; ), - TP_printk("transaction=%d node=%d src_ptr=0x%p ==> dest_ref=%d dest_desc=%d", - __entry->debug_id, __entry->node_debug_id, __entry->node_ptr, + TP_printk("transaction=%d node=%d src_ptr=0x%016llx ==> dest_ref=%d dest_desc=%d", + __entry->debug_id, __entry->node_debug_id, + (u64)__entry->node_ptr, __entry->ref_debug_id, __entry->ref_desc) ); @@ -177,7 +178,7 @@ TRACE_EVENT(binder_transaction_ref_to_node, __field(int, ref_debug_id) __field(uint32_t, ref_desc) __field(int, node_debug_id) - __field(void __user *, node_ptr) + __field(binder_uintptr_t, node_ptr) ), TP_fast_assign( __entry->debug_id = t->debug_id; @@ -186,9 +187,10 @@ TRACE_EVENT(binder_transaction_ref_to_node, __entry->node_debug_id = ref->node->debug_id; __entry->node_ptr = ref->node->ptr; ), - TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%p", + TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%016llx", __entry->debug_id, __entry->node_debug_id, - __entry->ref_debug_id, __entry->ref_desc, __entry->node_ptr) + __entry->ref_debug_id, __entry->ref_desc, + (u64)__entry->node_ptr) ); TRACE_EVENT(binder_transaction_ref_to_ref, diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 574066ff73f8..3d5bf1472236 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -16,6 +16,7 @@ */ #include +#include #include #include #include @@ -55,10 +56,12 @@ struct ion_device { struct mutex buffer_lock; struct rw_semaphore lock; struct plist_head heaps; - long (*custom_ioctl) (struct ion_client *client, unsigned int cmd, - unsigned long arg); + long (*custom_ioctl)(struct ion_client *client, unsigned int cmd, + unsigned long arg); struct rb_root clients; struct dentry *debug_root; + struct dentry *heaps_debug_root; + struct dentry *clients_debug_root; }; /** @@ -69,6 +72,8 @@ struct ion_device { * @idr: an idr space for allocating handle ids * @lock: lock protecting the tree of handles * @name: used for debugging + * @display_name: used for debugging (unique version of @name) + * @display_serial: used for debugging (to make display_name unique) * @task: used for debugging * * A client represents a list of buffers this client may access. @@ -82,6 +87,8 @@ struct ion_client { struct idr idr; struct mutex lock; const char *name; + char *display_name; + int display_serial; struct task_struct *task; pid_t pid; struct dentry *debug_root; @@ -208,7 +215,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, if (IS_ERR(table)) { heap->ops->free(buffer); kfree(buffer); - return ERR_PTR(PTR_ERR(table)); + return ERR_CAST(table); } buffer->sg_table = table; if (ion_buffer_fault_user_mappings(buffer)) { @@ -429,7 +436,7 @@ static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle) { WARN_ON(!mutex_is_locked(&client->lock)); - return (idr_find(&client->idr, handle->id) == handle); + return idr_find(&client->idr, handle->id) == handle; } static int ion_handle_add(struct ion_client *client, struct ion_handle *handle) @@ -501,7 +508,7 @@ struct ion_handle *ion_alloc(struct ion_client *client, size_t len, return ERR_PTR(-ENODEV); if (IS_ERR(buffer)) - return ERR_PTR(PTR_ERR(buffer)); + return ERR_CAST(buffer); handle = ion_handle_create(client, buffer); @@ -708,6 +715,21 @@ static const struct file_operations debug_client_fops = { .release = single_release, }; +static int ion_get_client_serial(const struct rb_root *root, + const unsigned char *name) +{ + int serial = -1; + struct rb_node *node; + for (node = rb_first(root); node; node = rb_next(node)) { + struct ion_client *client = rb_entry(node, struct ion_client, + node); + if (strcmp(client->name, name)) + continue; + serial = max(serial, client->display_serial); + } + return serial + 1; +} + struct ion_client *ion_client_create(struct ion_device *dev, const char *name) { @@ -716,9 +738,13 @@ struct ion_client *ion_client_create(struct ion_device *dev, struct rb_node **p; struct rb_node *parent = NULL; struct ion_client *entry; - char debug_name[64]; pid_t pid; + if (!name) { + pr_err("%s: Name cannot be null\n", __func__); + return ERR_PTR(-EINVAL); + } + get_task_struct(current->group_leader); task_lock(current->group_leader); pid = task_pid_nr(current->group_leader); @@ -733,21 +759,27 @@ struct ion_client *ion_client_create(struct ion_device *dev, task_unlock(current->group_leader); client = kzalloc(sizeof(struct ion_client), GFP_KERNEL); - if (!client) { - if (task) - put_task_struct(current->group_leader); - return ERR_PTR(-ENOMEM); - } + if (!client) + goto err_put_task_struct; client->dev = dev; client->handles = RB_ROOT; idr_init(&client->idr); mutex_init(&client->lock); - client->name = name; client->task = task; client->pid = pid; + client->name = kstrdup(name, GFP_KERNEL); + if (!client->name) + goto err_free_client; down_write(&dev->lock); + client->display_serial = ion_get_client_serial(&dev->clients, name); + client->display_name = kasprintf( + GFP_KERNEL, "%s-%d", name, client->display_serial); + if (!client->display_name) { + up_write(&dev->lock); + goto err_free_client_name; + } p = &dev->clients.rb_node; while (*p) { parent = *p; @@ -761,13 +793,28 @@ struct ion_client *ion_client_create(struct ion_device *dev, rb_link_node(&client->node, parent, p); rb_insert_color(&client->node, &dev->clients); - snprintf(debug_name, 64, "%u", client->pid); - client->debug_root = debugfs_create_file(debug_name, 0664, - dev->debug_root, client, - &debug_client_fops); + client->debug_root = debugfs_create_file(client->display_name, 0664, + dev->clients_debug_root, + client, &debug_client_fops); + if (!client->debug_root) { + char buf[256], *path; + path = dentry_path(dev->clients_debug_root, buf, 256); + pr_err("Failed to create client debugfs at %s/%s\n", + path, client->display_name); + } + up_write(&dev->lock); return client; + +err_free_client_name: + kfree(client->name); +err_free_client: + kfree(client); +err_put_task_struct: + if (task) + put_task_struct(current->group_leader); + return ERR_PTR(-ENOMEM); } EXPORT_SYMBOL(ion_client_create); @@ -792,6 +839,8 @@ void ion_client_destroy(struct ion_client *client) debugfs_remove_recursive(client->debug_root); up_write(&dev->lock); + kfree(client->display_name); + kfree(client->name); kfree(client); } EXPORT_SYMBOL(ion_client_destroy); @@ -954,8 +1003,8 @@ static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) int ret = 0; if (!buffer->heap->ops->map_user) { - pr_err("%s: this heap does not define a method for mapping " - "to userspace\n", __func__); + pr_err("%s: this heap does not define a method for mapping to userspace\n", + __func__); return -EINVAL; } @@ -1017,9 +1066,7 @@ static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start, mutex_lock(&buffer->lock); vaddr = ion_buffer_kmap_get(buffer); mutex_unlock(&buffer->lock); - if (IS_ERR(vaddr)) - return PTR_ERR(vaddr); - return 0; + return PTR_ERR_OR_ZERO(vaddr); } static void ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf, size_t start, @@ -1100,7 +1147,7 @@ struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd) dmabuf = dma_buf_get(fd); if (IS_ERR(dmabuf)) - return ERR_PTR(PTR_ERR(dmabuf)); + return ERR_CAST(dmabuf); /* if this memory came from ion */ if (dmabuf->ops != &dma_buf_ops) { @@ -1293,9 +1340,11 @@ static int ion_open(struct inode *inode, struct file *file) struct miscdevice *miscdev = file->private_data; struct ion_device *dev = container_of(miscdev, struct ion_device, dev); struct ion_client *client; + char debug_name[64]; pr_debug("%s: %d\n", __func__, __LINE__); - client = ion_client_create(dev, "user"); + snprintf(debug_name, 64, "%u", task_pid_nr(current->group_leader)); + client = ion_client_create(dev, debug_name); if (IS_ERR(client)) return PTR_ERR(client); file->private_data = client; @@ -1338,7 +1387,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) size_t total_orphaned_size = 0; seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size"); - seq_printf(s, "----------------------------------------------------\n"); + seq_puts(s, "----------------------------------------------------\n"); for (n = rb_first(&dev->clients); n; n = rb_next(n)) { struct ion_client *client = rb_entry(n, struct ion_client, @@ -1357,9 +1406,8 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) client->pid, size); } } - seq_printf(s, "----------------------------------------------------\n"); - seq_printf(s, "orphaned allocations (info is from last known client):" - "\n"); + seq_puts(s, "----------------------------------------------------\n"); + seq_puts(s, "orphaned allocations (info is from last known client):\n"); mutex_lock(&dev->buffer_lock); for (n = rb_first(&dev->buffers); n; n = rb_next(n)) { struct ion_buffer *buffer = rb_entry(n, struct ion_buffer, @@ -1376,14 +1424,14 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) } } mutex_unlock(&dev->buffer_lock); - seq_printf(s, "----------------------------------------------------\n"); + seq_puts(s, "----------------------------------------------------\n"); seq_printf(s, "%16.s %16zu\n", "total orphaned", total_orphaned_size); seq_printf(s, "%16.s %16zu\n", "total ", total_size); if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) seq_printf(s, "%16.s %16zu\n", "deferred free", heap->free_list_size); - seq_printf(s, "----------------------------------------------------\n"); + seq_puts(s, "----------------------------------------------------\n"); if (heap->debug_show) heap->debug_show(heap, s, unused); @@ -1443,6 +1491,8 @@ DEFINE_SIMPLE_ATTRIBUTE(debug_shrink_fops, debug_shrink_get, void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) { + struct dentry *debug_file; + if (!heap->ops->allocate || !heap->ops->free || !heap->ops->map_dma || !heap->ops->unmap_dma) pr_err("%s: can not add heap with invalid ops struct.\n", @@ -1451,21 +1501,40 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) ion_heap_init_deferred_free(heap); + if ((heap->flags & ION_HEAP_FLAG_DEFER_FREE) || heap->ops->shrink) + ion_heap_init_shrinker(heap); + heap->dev = dev; down_write(&dev->lock); /* use negative heap->id to reverse the priority -- when traversing the list later attempt higher id numbers first */ plist_node_init(&heap->node, -heap->id); plist_add(&heap->node, &dev->heaps); - debugfs_create_file(heap->name, 0664, dev->debug_root, heap, - &debug_heap_fops); + debug_file = debugfs_create_file(heap->name, 0664, + dev->heaps_debug_root, heap, + &debug_heap_fops); + + if (!debug_file) { + char buf[256], *path; + path = dentry_path(dev->heaps_debug_root, buf, 256); + pr_err("Failed to create heap debugfs at %s/%s\n", + path, heap->name); + } + #ifdef DEBUG_HEAP_SHRINKER if (heap->shrinker.shrink) { char debug_name[64]; snprintf(debug_name, 64, "%s_shrink", heap->name); - debugfs_create_file(debug_name, 0644, dev->debug_root, heap, - &debug_shrink_fops); + debug_file = debugfs_create_file( + debug_name, 0644, dev->heaps_debug_root, heap, + &debug_shrink_fops); + if (!debug_file) { + char buf[256], *path; + path = dentry_path(dev->heaps_debug_root, buf, 256); + pr_err("Failed to create heap shrinker debugfs at %s/%s\n", + path, debug_name); + } } #endif up_write(&dev->lock); @@ -1494,8 +1563,21 @@ struct ion_device *ion_device_create(long (*custom_ioctl) } idev->debug_root = debugfs_create_dir("ion", NULL); - if (!idev->debug_root) - pr_err("ion: failed to create debug files.\n"); + if (!idev->debug_root) { + pr_err("ion: failed to create debugfs root directory.\n"); + goto debugfs_done; + } + idev->heaps_debug_root = debugfs_create_dir("heaps", idev->debug_root); + if (!idev->heaps_debug_root) { + pr_err("ion: failed to create debugfs heaps directory.\n"); + goto debugfs_done; + } + idev->clients_debug_root = debugfs_create_dir("clients", + idev->debug_root); + if (!idev->clients_debug_root) + pr_err("ion: failed to create debugfs clients directory.\n"); + +debugfs_done: idev->custom_ioctl = custom_ioctl; idev->buffers = RB_ROOT; @@ -1509,6 +1591,7 @@ struct ion_device *ion_device_create(long (*custom_ioctl) void ion_device_destroy(struct ion_device *dev) { misc_deregister(&dev->dev); + debugfs_remove_recursive(dev->debug_root); /* XXX need to free the heaps and clients ? */ kfree(dev); } @@ -1527,8 +1610,7 @@ void __init ion_reserve(struct ion_platform_data *data) data->heaps[i].align, MEMBLOCK_ALLOC_ANYWHERE); if (!paddr) { - pr_err("%s: error allocating memblock for " - "heap %d\n", + pr_err("%s: error allocating memblock for heap %d\n", __func__, i); continue; } diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index f0f98897e4b9..ce68ecfed31f 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -135,7 +135,7 @@ static int ion_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer, struct device *dev = cma_heap->dev; struct ion_cma_buffer_info *info = buffer->priv_virt; - dev_dbg(dev, "Return buffer %p physical address 0x%pa\n", buffer, + dev_dbg(dev, "Return buffer %p physical address %pa\n", buffer, &info->handle); *addr = info->handle; diff --git a/drivers/staging/android/ion/ion_dummy_driver.c b/drivers/staging/android/ion/ion_dummy_driver.c index 01cdc8aee898..3a45e79fe444 100644 --- a/drivers/staging/android/ion/ion_dummy_driver.c +++ b/drivers/staging/android/ion/ion_dummy_driver.c @@ -25,13 +25,13 @@ #include "ion.h" #include "ion_priv.h" -struct ion_device *idev; -struct ion_heap **heaps; +static struct ion_device *idev; +static struct ion_heap **heaps; -void *carveout_ptr; -void *chunk_ptr; +static void *carveout_ptr; +static void *chunk_ptr; -struct ion_platform_heap dummy_heaps[] = { +static struct ion_platform_heap dummy_heaps[] = { { .id = ION_HEAP_TYPE_SYSTEM, .type = ION_HEAP_TYPE_SYSTEM, @@ -58,7 +58,7 @@ struct ion_platform_heap dummy_heaps[] = { }, }; -struct ion_platform_data dummy_ion_pdata = { +static struct ion_platform_data dummy_ion_pdata = { .nr = ARRAY_SIZE(dummy_heaps), .heaps = dummy_heaps, }; diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c index 37e64d51394c..bdc6a28ba8c9 100644 --- a/drivers/staging/android/ion/ion_heap.c +++ b/drivers/staging/android/ion/ion_heap.c @@ -178,7 +178,8 @@ size_t ion_heap_freelist_size(struct ion_heap *heap) return size; } -size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size) +static size_t _ion_heap_freelist_drain(struct ion_heap *heap, size_t size, + bool skip_pools) { struct ion_buffer *buffer; size_t total_drained = 0; @@ -197,6 +198,8 @@ size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size) list); list_del(&buffer->list); heap->free_list_size -= buffer->size; + if (skip_pools) + buffer->private_flags |= ION_PRIV_FLAG_SHRINKER_FREE; total_drained += buffer->size; spin_unlock(&heap->free_lock); ion_buffer_destroy(buffer); @@ -207,6 +210,16 @@ size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size) return total_drained; } +size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size) +{ + return _ion_heap_freelist_drain(heap, size, false); +} + +size_t ion_heap_freelist_shrink(struct ion_heap *heap, size_t size) +{ + return _ion_heap_freelist_drain(heap, size, true); +} + static int ion_heap_deferred_free(void *data) { struct ion_heap *heap = data; @@ -246,12 +259,62 @@ int ion_heap_init_deferred_free(struct ion_heap *heap) if (IS_ERR(heap->task)) { pr_err("%s: creating thread for deferred free failed\n", __func__); - return PTR_RET(heap->task); + return PTR_ERR_OR_ZERO(heap->task); } sched_setscheduler(heap->task, SCHED_IDLE, ¶m); return 0; } +static unsigned long ion_heap_shrink_count(struct shrinker *shrinker, + struct shrink_control *sc) +{ + struct ion_heap *heap = container_of(shrinker, struct ion_heap, + shrinker); + int total = 0; + + total = ion_heap_freelist_size(heap) / PAGE_SIZE; + if (heap->ops->shrink) + total += heap->ops->shrink(heap, sc->gfp_mask, 0); + return total; +} + +static unsigned long ion_heap_shrink_scan(struct shrinker *shrinker, + struct shrink_control *sc) +{ + struct ion_heap *heap = container_of(shrinker, struct ion_heap, + shrinker); + int freed = 0; + int to_scan = sc->nr_to_scan; + + if (to_scan == 0) + return 0; + + /* + * shrink the free list first, no point in zeroing the memory if we're + * just going to reclaim it. Also, skip any possible page pooling. + */ + if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) + freed = ion_heap_freelist_shrink(heap, to_scan * PAGE_SIZE) / + PAGE_SIZE; + + to_scan -= freed; + if (to_scan <= 0) + return freed; + + if (heap->ops->shrink) + freed += heap->ops->shrink(heap, sc->gfp_mask, to_scan); + return freed; +} + +void ion_heap_init_shrinker(struct ion_heap *heap) +{ + heap->shrinker.count_objects = ion_heap_shrink_count; + heap->shrinker.scan_objects = ion_heap_shrink_scan; + heap->shrinker.seeks = DEFAULT_SEEKS; + heap->shrinker.batch = 0; + register_shrinker(&heap->shrinker); +} + struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data) { struct ion_heap *heap = NULL; diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index fa693c23681a..ecb5fc34ec5c 100644 --- a/drivers/staging/android/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -130,8 +130,7 @@ static int ion_page_pool_total(struct ion_page_pool *pool, bool high) int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, int nr_to_scan) { - int nr_freed = 0; - int i; + int freed; bool high; high = !!(gfp_mask & __GFP_HIGHMEM); @@ -139,7 +138,7 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, if (nr_to_scan == 0) return ion_page_pool_total(pool, high); - for (i = 0; i < nr_to_scan; i++) { + for (freed = 0; freed < nr_to_scan; freed++) { struct page *page; mutex_lock(&pool->mutex); @@ -153,10 +152,9 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, } mutex_unlock(&pool->mutex); ion_page_pool_free_pages(pool, page); - nr_freed += (1 << pool->order); } - return nr_freed; + return freed; } struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order) diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index fc2e4fccf69d..1eba3f2076a9 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -38,6 +38,7 @@ struct ion_buffer *ion_handle_buffer(struct ion_handle *handle); * @dev: back pointer to the ion_device * @heap: back pointer to the heap the buffer came from * @flags: buffer specific flags + * @private_flags: internal buffer specific flags * @size: size of the buffer * @priv_virt: private data to the buffer representable as * a void * @@ -66,6 +67,7 @@ struct ion_buffer { struct ion_device *dev; struct ion_heap *heap; unsigned long flags; + unsigned long private_flags; size_t size; union { void *priv_virt; @@ -98,22 +100,27 @@ void ion_buffer_destroy(struct ion_buffer *buffer); * @map_user map memory to userspace * * allocate, phys, and map_user return 0 on success, -errno on error. - * map_dma and map_kernel return pointer on success, ERR_PTR on error. + * map_dma and map_kernel return pointer on success, ERR_PTR on + * error. @free will be called with ION_PRIV_FLAG_SHRINKER_FREE set in + * the buffer's private_flags when called from a shrinker. In that + * case, the pages being free'd must be truly free'd back to the + * system, not put in a page pool or otherwise cached. */ struct ion_heap_ops { - int (*allocate) (struct ion_heap *heap, - struct ion_buffer *buffer, unsigned long len, - unsigned long align, unsigned long flags); - void (*free) (struct ion_buffer *buffer); - int (*phys) (struct ion_heap *heap, struct ion_buffer *buffer, - ion_phys_addr_t *addr, size_t *len); - struct sg_table *(*map_dma) (struct ion_heap *heap, - struct ion_buffer *buffer); - void (*unmap_dma) (struct ion_heap *heap, struct ion_buffer *buffer); - void * (*map_kernel) (struct ion_heap *heap, struct ion_buffer *buffer); - void (*unmap_kernel) (struct ion_heap *heap, struct ion_buffer *buffer); - int (*map_user) (struct ion_heap *mapper, struct ion_buffer *buffer, - struct vm_area_struct *vma); + int (*allocate)(struct ion_heap *heap, + struct ion_buffer *buffer, unsigned long len, + unsigned long align, unsigned long flags); + void (*free)(struct ion_buffer *buffer); + int (*phys)(struct ion_heap *heap, struct ion_buffer *buffer, + ion_phys_addr_t *addr, size_t *len); + struct sg_table * (*map_dma)(struct ion_heap *heap, + struct ion_buffer *buffer); + void (*unmap_dma)(struct ion_heap *heap, struct ion_buffer *buffer); + void * (*map_kernel)(struct ion_heap *heap, struct ion_buffer *buffer); + void (*unmap_kernel)(struct ion_heap *heap, struct ion_buffer *buffer); + int (*map_user)(struct ion_heap *mapper, struct ion_buffer *buffer, + struct vm_area_struct *vma); + int (*shrink)(struct ion_heap *heap, gfp_t gfp_mask, int nr_to_scan); }; /** @@ -121,6 +128,17 @@ struct ion_heap_ops { */ #define ION_HEAP_FLAG_DEFER_FREE (1 << 0) +/** + * private flags - flags internal to ion + */ +/* + * Buffer is being freed from a shrinker function. Skip any possible + * heap-specific caching mechanism (e.g. page pools). Guarantees that + * any buffer storage that came from the system allocator will be + * returned to the system allocator. + */ +#define ION_PRIV_FLAG_SHRINKER_FREE (1 << 0) + /** * struct ion_heap - represents a heap in the system * @node: rb node to put the heap on the device's tree of heaps @@ -132,10 +150,7 @@ struct ion_heap_ops { * allocating. These are specified by platform data and * MUST be unique * @name: used for debugging - * @shrinker: a shrinker for the heap, if the heap caches system - * memory, it must define a shrinker to return it on low - * memory conditions, this includes system memory cached - * in the deferred free lists for heaps that support it + * @shrinker: a shrinker for the heap * @free_list: free list head if deferred free is used * @free_list_size size of the deferred free list in bytes * @lock: protects the free list @@ -218,6 +233,16 @@ int ion_heap_map_user(struct ion_heap *, struct ion_buffer *, int ion_heap_buffer_zero(struct ion_buffer *buffer); int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot); +/** + * ion_heap_init_shrinker + * @heap: the heap + * + * If a heap sets the ION_HEAP_FLAG_DEFER_FREE flag or defines the shrink op + * this function will be called to setup a shrinker to shrink the freelists + * and call the heap's shrink op. + */ +void ion_heap_init_shrinker(struct ion_heap *heap); + /** * ion_heap_init_deferred_free -- initialize deferred free functionality * @heap: the heap @@ -249,6 +274,29 @@ void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer *buffer); */ size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size); +/** + * ion_heap_freelist_shrink - drain the deferred free + * list, skipping any heap-specific + * pooling or caching mechanisms + * + * @heap: the heap + * @size: amount of memory to drain in bytes + * + * Drains the indicated amount of memory from the deferred freelist immediately. + * Returns the total amount freed. The total freed may be higher depending + * on the size of the items in the list, or lower if there is insufficient + * total memory on the freelist. + * + * Unlike with @ion_heap_freelist_drain, don't put any pages back into + * page pools or otherwise cache the pages. Everything must be + * genuinely free'd back to the system. If you're free'ing from a + * shrinker you probably want to use this. Note that this relies on + * the heap.ops.free callback honoring the ION_PRIV_FLAG_SHRINKER_FREE + * flag. + */ +size_t ion_heap_freelist_shrink(struct ion_heap *heap, + size_t size); + /** * ion_heap_freelist_size - returns the size of the freelist in bytes * @heap: the heap @@ -305,13 +353,8 @@ void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, * @low_count: number of lowmem items in the pool * @high_items: list of highmem items * @low_items: list of lowmem items - * @shrinker: a shrinker for the items * @mutex: lock protecting this struct and especially the count * item list - * @alloc: function to be used to allocate pageory when the pool - * is empty - * @free: function to be used to free pageory back to the system - * when the shrinker fires * @gfp_mask: gfp_mask to use from alloc * @order: order of pages in the pool * @list: plist node for list of pools diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 9849f3963e75..c92363356ae1 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -90,7 +90,7 @@ static void free_buffer_page(struct ion_system_heap *heap, { bool cached = ion_buffer_cached(buffer); - if (!cached) { + if (!cached && !(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)) { struct ion_page_pool *pool = heap->pools[order_to_index(order)]; ion_page_pool_free(pool, page); } else { @@ -209,7 +209,7 @@ static void ion_system_heap_free(struct ion_buffer *buffer) /* uncached pages come from the page pools, zero them before returning for security purposes (other allocations are zerod at alloc time */ - if (!cached) + if (!cached && !(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)) ion_heap_buffer_zero(buffer); for_each_sg(table->sgl, sg, table->nents, i) @@ -231,6 +231,23 @@ static void ion_system_heap_unmap_dma(struct ion_heap *heap, return; } +static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask, + int nr_to_scan) +{ + struct ion_system_heap *sys_heap; + int nr_total = 0; + int i; + + sys_heap = container_of(heap, struct ion_system_heap, heap); + + for (i = 0; i < num_orders; i++) { + struct ion_page_pool *pool = sys_heap->pools[i]; + nr_total += ion_page_pool_shrink(pool, gfp_mask, nr_to_scan); + } + + return nr_total; +} + static struct ion_heap_ops system_heap_ops = { .allocate = ion_system_heap_allocate, .free = ion_system_heap_free, @@ -239,67 +256,9 @@ static struct ion_heap_ops system_heap_ops = { .map_kernel = ion_heap_map_kernel, .unmap_kernel = ion_heap_unmap_kernel, .map_user = ion_heap_map_user, + .shrink = ion_system_heap_shrink, }; -static unsigned long ion_system_heap_shrink_count(struct shrinker *shrinker, - struct shrink_control *sc) -{ - struct ion_heap *heap = container_of(shrinker, struct ion_heap, - shrinker); - struct ion_system_heap *sys_heap = container_of(heap, - struct ion_system_heap, - heap); - int nr_total = 0; - int i; - - /* total number of items is whatever the page pools are holding - plus whatever's in the freelist */ - for (i = 0; i < num_orders; i++) { - struct ion_page_pool *pool = sys_heap->pools[i]; - nr_total += ion_page_pool_shrink(pool, sc->gfp_mask, 0); - } - nr_total += ion_heap_freelist_size(heap) / PAGE_SIZE; - return nr_total; - -} - -static unsigned long ion_system_heap_shrink_scan(struct shrinker *shrinker, - struct shrink_control *sc) -{ - - struct ion_heap *heap = container_of(shrinker, struct ion_heap, - shrinker); - struct ion_system_heap *sys_heap = container_of(heap, - struct ion_system_heap, - heap); - int nr_freed = 0; - int i; - - if (sc->nr_to_scan == 0) - goto end; - - /* shrink the free list first, no point in zeroing the memory if - we're just going to reclaim it */ - nr_freed += ion_heap_freelist_drain(heap, sc->nr_to_scan * PAGE_SIZE) / - PAGE_SIZE; - - if (nr_freed >= sc->nr_to_scan) - goto end; - - for (i = 0; i < num_orders; i++) { - struct ion_page_pool *pool = sys_heap->pools[i]; - - nr_freed += ion_page_pool_shrink(pool, sc->gfp_mask, - sc->nr_to_scan); - if (nr_freed >= sc->nr_to_scan) - break; - } - -end: - return nr_freed; - -} - static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, void *unused) { @@ -347,11 +306,6 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused) heap->pools[i] = pool; } - heap->heap.shrinker.scan_objects = ion_system_heap_shrink_scan; - heap->heap.shrinker.count_objects = ion_system_heap_shrink_count; - heap->heap.shrinker.seeks = DEFAULT_SEEKS; - heap->heap.shrinker.batch = 0; - register_shrinker(&heap->heap.shrinker); heap->heap.debug_show = ion_system_heap_debug_show; return &heap->heap; err_create_pool: diff --git a/drivers/staging/android/ion/tegra/tegra_ion.c b/drivers/staging/android/ion/tegra/tegra_ion.c index 3474c65f87fa..11c7cceb3c7d 100644 --- a/drivers/staging/android/ion/tegra/tegra_ion.c +++ b/drivers/staging/android/ion/tegra/tegra_ion.c @@ -32,13 +32,13 @@ static int tegra_ion_probe(struct platform_device *pdev) num_heaps = pdata->nr; - heaps = kzalloc(sizeof(struct ion_heap *) * pdata->nr, GFP_KERNEL); + heaps = devm_kzalloc(&pdev->dev, + sizeof(struct ion_heap *) * pdata->nr, + GFP_KERNEL); idev = ion_device_create(NULL); - if (IS_ERR_OR_NULL(idev)) { - kfree(heaps); + if (IS_ERR_OR_NULL(idev)) return PTR_ERR(idev); - } /* create the heaps as specified in the board file */ for (i = 0; i < num_heaps; i++) { @@ -58,7 +58,6 @@ err: if (heaps[i]) ion_heap_destroy(heaps[i]); } - kfree(heaps); return err; } @@ -70,7 +69,6 @@ static int tegra_ion_remove(struct platform_device *pdev) ion_device_destroy(idev); for (i = 0; i < num_heaps; i++) ion_heap_destroy(heaps[i]); - kfree(heaps); return 0; } diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 6f094b37f1f1..b545d3d1da3e 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -88,7 +88,8 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) int array_size = ARRAY_SIZE(lowmem_adj); int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages; int other_file = global_page_state(NR_FILE_PAGES) - - global_page_state(NR_SHMEM); + global_page_state(NR_SHMEM) - + total_swapcache_pages(); if (lowmem_adj_size < array_size) array_size = lowmem_adj_size; @@ -159,8 +160,8 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) selected->pid, selected->comm, selected_oom_score_adj, selected_tasksize); lowmem_deathpending_timeout = jiffies + HZ; - send_sig(SIGKILL, selected, 0); set_tsk_thread_flag(selected, TIF_MEMDIE); + send_sig(SIGKILL, selected, 0); rem += selected_tasksize; } diff --git a/drivers/staging/android/sw_sync.h b/drivers/staging/android/sw_sync.h index 5aaf71d6974b..1a50669ec8a9 100644 --- a/drivers/staging/android/sw_sync.h +++ b/drivers/staging/android/sw_sync.h @@ -18,10 +18,9 @@ #define _LINUX_SW_SYNC_H #include - -#ifdef __KERNEL__ - +#include #include "sync.h" +#include "uapi/sw_sync.h" struct sw_sync_timeline { struct sync_timeline obj; @@ -57,19 +56,4 @@ static inline struct sync_pt *sw_sync_pt_create(struct sw_sync_timeline *obj, } #endif /* IS_ENABLED(CONFIG_SW_SYNC) */ -#endif /* __KERNEL __ */ - -struct sw_sync_create_fence_data { - __u32 value; - char name[32]; - __s32 fence; /* fd of new fence */ -}; - -#define SW_SYNC_IOC_MAGIC 'W' - -#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\ - struct sw_sync_create_fence_data) -#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32) - - #endif /* _LINUX_SW_SYNC_H */ diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h index 62e2255b1c1e..eaf57cccf626 100644 --- a/drivers/staging/android/sync.h +++ b/drivers/staging/android/sync.h @@ -14,14 +14,14 @@ #define _LINUX_SYNC_H #include -#ifdef __KERNEL__ - #include #include #include #include #include +#include "uapi/sync.h" + struct sync_timeline; struct sync_pt; struct sync_fence; @@ -53,7 +53,7 @@ struct sync_timeline_ops { const char *driver_name; /* required */ - struct sync_pt *(*dup)(struct sync_pt *pt); + struct sync_pt * (*dup)(struct sync_pt *pt); /* required */ int (*has_signaled)(struct sync_pt *pt); @@ -341,86 +341,4 @@ int sync_fence_cancel_async(struct sync_fence *fence, */ int sync_fence_wait(struct sync_fence *fence, long timeout); -#endif /* __KERNEL__ */ - -/** - * struct sync_merge_data - data passed to merge ioctl - * @fd2: file descriptor of second fence - * @name: name of new fence - * @fence: returns the fd of the new fence to userspace - */ -struct sync_merge_data { - __s32 fd2; /* fd of second fence */ - char name[32]; /* name of new fence */ - __s32 fence; /* fd on newly created fence */ -}; - -/** - * struct sync_pt_info - detailed sync_pt information - * @len: length of sync_pt_info including any driver_data - * @obj_name: name of parent sync_timeline - * @driver_name: name of driver implementing the parent - * @status: status of the sync_pt 0:active 1:signaled <0:error - * @timestamp_ns: timestamp of status change in nanoseconds - * @driver_data: any driver dependent data - */ -struct sync_pt_info { - __u32 len; - char obj_name[32]; - char driver_name[32]; - __s32 status; - __u64 timestamp_ns; - - __u8 driver_data[0]; -}; - -/** - * struct sync_fence_info_data - data returned from fence info ioctl - * @len: ioctl caller writes the size of the buffer its passing in. - * ioctl returns length of sync_fence_data returned to userspace - * including pt_info. - * @name: name of fence - * @status: status of fence. 1: signaled 0:active <0:error - * @pt_info: a sync_pt_info struct for every sync_pt in the fence - */ -struct sync_fence_info_data { - __u32 len; - char name[32]; - __s32 status; - - __u8 pt_info[0]; -}; - -#define SYNC_IOC_MAGIC '>' - -/** - * DOC: SYNC_IOC_WAIT - wait for a fence to signal - * - * pass timeout in milliseconds. Waits indefinitely timeout < 0. - */ -#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32) - -/** - * DOC: SYNC_IOC_MERGE - merge two fences - * - * Takes a struct sync_merge_data. Creates a new fence containing copies of - * the sync_pts in both the calling fd and sync_merge_data.fd2. Returns the - * new fence's fd in sync_merge_data.fence - */ -#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data) - -/** - * DOC: SYNC_IOC_FENCE_INFO - get detailed information on a fence - * - * Takes a struct sync_fence_info_data with extra space allocated for pt_info. - * Caller should write the size of the buffer into len. On return, len is - * updated to reflect the total size of the sync_fence_info_data including - * pt_info. - * - * pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence. - * To iterate over the sync_pt_infos, use the sync_pt_info.len field. - */ -#define SYNC_IOC_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2,\ - struct sync_fence_info_data) - #endif /* _LINUX_SYNC_H */ diff --git a/drivers/staging/android/timed_gpio.c b/drivers/staging/android/timed_gpio.c index e81451425c01..0c7fdc83b336 100644 --- a/drivers/staging/android/timed_gpio.c +++ b/drivers/staging/android/timed_gpio.c @@ -90,8 +90,9 @@ static int timed_gpio_probe(struct platform_device *pdev) if (!pdata) return -EBUSY; - gpio_data = kzalloc(sizeof(struct timed_gpio_data) * pdata->num_gpios, - GFP_KERNEL); + gpio_data = devm_kzalloc(&pdev->dev, + sizeof(struct timed_gpio_data) * pdata->num_gpios, + GFP_KERNEL); if (!gpio_data) return -ENOMEM; @@ -131,7 +132,6 @@ err_out: timed_output_dev_unregister(&gpio_data[i].dev); gpio_free(gpio_data[i].gpio); } - kfree(gpio_data); return ret; } @@ -147,8 +147,6 @@ static int timed_gpio_remove(struct platform_device *pdev) gpio_free(gpio_data[i].gpio); } - kfree(gpio_data); - return 0; } diff --git a/drivers/staging/android/timed_output.h b/drivers/staging/android/timed_output.h index 905c7cc9588e..13d2ca51cbe8 100644 --- a/drivers/staging/android/timed_output.h +++ b/drivers/staging/android/timed_output.h @@ -20,10 +20,10 @@ struct timed_output_dev { const char *name; /* enable the output and set the timer */ - void (*enable)(struct timed_output_dev *sdev, int timeout); + void (*enable)(struct timed_output_dev *sdev, int timeout); /* returns the current number of milliseconds remaining on the timer */ - int (*get_time)(struct timed_output_dev *sdev); + int (*get_time)(struct timed_output_dev *sdev); /* private data */ struct device *dev; diff --git a/drivers/staging/android/uapi/android_alarm.h b/drivers/staging/android/uapi/android_alarm.h new file mode 100644 index 000000000000..aa013f6f5f3a --- /dev/null +++ b/drivers/staging/android/uapi/android_alarm.h @@ -0,0 +1,62 @@ +/* drivers/staging/android/uapi/android_alarm.h + * + * Copyright (C) 2006-2007 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _UAPI_LINUX_ANDROID_ALARM_H +#define _UAPI_LINUX_ANDROID_ALARM_H + +#include +#include + +enum android_alarm_type { + /* return code bit numbers or set alarm arg */ + ANDROID_ALARM_RTC_WAKEUP, + ANDROID_ALARM_RTC, + ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, + ANDROID_ALARM_ELAPSED_REALTIME, + ANDROID_ALARM_SYSTEMTIME, + + ANDROID_ALARM_TYPE_COUNT, + + /* return code bit numbers */ + /* ANDROID_ALARM_TIME_CHANGE = 16 */ +}; + +enum android_alarm_return_flags { + ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP, + ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC, + ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK = + 1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, + ANDROID_ALARM_ELAPSED_REALTIME_MASK = + 1U << ANDROID_ALARM_ELAPSED_REALTIME, + ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME, + ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16 +}; + +/* Disable alarm */ +#define ANDROID_ALARM_CLEAR(type) _IO('a', 0 | ((type) << 4)) + +/* Ack last alarm and wait for next */ +#define ANDROID_ALARM_WAIT _IO('a', 1) + +#define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size) +/* Set alarm */ +#define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec) +#define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec) +#define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec) +#define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec) +#define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0))) +#define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4) + +#endif diff --git a/drivers/staging/android/uapi/ashmem.h b/drivers/staging/android/uapi/ashmem.h new file mode 100644 index 000000000000..ba4743c71d6b --- /dev/null +++ b/drivers/staging/android/uapi/ashmem.h @@ -0,0 +1,47 @@ +/* + * drivers/staging/android/uapi/ashmem.h + * + * Copyright 2008 Google Inc. + * Author: Robert Love + * + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. + */ + +#ifndef _UAPI_LINUX_ASHMEM_H +#define _UAPI_LINUX_ASHMEM_H + +#include + +#define ASHMEM_NAME_LEN 256 + +#define ASHMEM_NAME_DEF "dev/ashmem" + +/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */ +#define ASHMEM_NOT_PURGED 0 +#define ASHMEM_WAS_PURGED 1 + +/* Return values from ASHMEM_GET_PIN_STATUS: Is the mapping pinned? */ +#define ASHMEM_IS_UNPINNED 0 +#define ASHMEM_IS_PINNED 1 + +struct ashmem_pin { + __u32 offset; /* offset into region, in bytes, page-aligned */ + __u32 len; /* length forward from offset, in bytes, page-aligned */ +}; + +#define __ASHMEMIOC 0x77 + +#define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN]) +#define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN]) +#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t) +#define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4) +#define ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned long) +#define ASHMEM_GET_PROT_MASK _IO(__ASHMEMIOC, 6) +#define ASHMEM_PIN _IOW(__ASHMEMIOC, 7, struct ashmem_pin) +#define ASHMEM_UNPIN _IOW(__ASHMEMIOC, 8, struct ashmem_pin) +#define ASHMEM_GET_PIN_STATUS _IO(__ASHMEMIOC, 9) +#define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10) + +#endif /* _UAPI_LINUX_ASHMEM_H */ diff --git a/drivers/staging/android/uapi/binder.h b/drivers/staging/android/uapi/binder.h new file mode 100644 index 000000000000..904adb7600cf --- /dev/null +++ b/drivers/staging/android/uapi/binder.h @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2008 Google, Inc. + * + * Based on, but no longer compatible with, the original + * OpenBinder.org binder driver interface, which is: + * + * Copyright (c) 2005 Palmsource, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _UAPI_LINUX_BINDER_H +#define _UAPI_LINUX_BINDER_H + +#include + +#define B_PACK_CHARS(c1, c2, c3, c4) \ + ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4)) +#define B_TYPE_LARGE 0x85 + +enum { + BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE), + BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE), + BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE), + BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE), + BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE), +}; + +enum { + FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff, + FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100, +}; + +#ifdef BINDER_IPC_32BIT +typedef __u32 binder_size_t; +typedef __u32 binder_uintptr_t; +#else +typedef __u64 binder_size_t; +typedef __u64 binder_uintptr_t; +#endif + +/* + * This is the flattened representation of a Binder object for transfer + * between processes. The 'offsets' supplied as part of a binder transaction + * contains offsets into the data where these structures occur. The Binder + * driver takes care of re-writing the structure type and data as it moves + * between processes. + */ +struct flat_binder_object { + /* 8 bytes for large_flat_header. */ + __u32 type; + __u32 flags; + + /* 8 bytes of data. */ + union { + binder_uintptr_t binder; /* local object */ + __u32 handle; /* remote object */ + }; + + /* extra data associated with local object */ + binder_uintptr_t cookie; +}; + +/* + * On 64-bit platforms where user code may run in 32-bits the driver must + * translate the buffer (and local binder) addresses appropriately. + */ + +struct binder_write_read { + binder_size_t write_size; /* bytes to write */ + binder_size_t write_consumed; /* bytes consumed by driver */ + binder_uintptr_t write_buffer; + binder_size_t read_size; /* bytes to read */ + binder_size_t read_consumed; /* bytes consumed by driver */ + binder_uintptr_t read_buffer; +}; + +/* Use with BINDER_VERSION, driver fills in fields. */ +struct binder_version { + /* driver protocol version -- increment with incompatible change */ + __s32 protocol_version; +}; + +/* This is the current protocol version. */ +#ifdef BINDER_IPC_32BIT +#define BINDER_CURRENT_PROTOCOL_VERSION 7 +#else +#define BINDER_CURRENT_PROTOCOL_VERSION 8 +#endif + +#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) +#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) +#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) +#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32) +#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32) +#define BINDER_THREAD_EXIT _IOW('b', 8, __s32) +#define BINDER_VERSION _IOWR('b', 9, struct binder_version) + +/* + * NOTE: Two special error codes you should check for when calling + * in to the driver are: + * + * EINTR -- The operation has been interupted. This should be + * handled by retrying the ioctl() until a different error code + * is returned. + * + * ECONNREFUSED -- The driver is no longer accepting operations + * from your process. That is, the process is being destroyed. + * You should handle this by exiting from your process. Note + * that once this error code is returned, all further calls to + * the driver from any thread will return this same code. + */ + +enum transaction_flags { + TF_ONE_WAY = 0x01, /* this is a one-way call: async, no return */ + TF_ROOT_OBJECT = 0x04, /* contents are the component's root object */ + TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */ + TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */ +}; + +struct binder_transaction_data { + /* The first two are only used for bcTRANSACTION and brTRANSACTION, + * identifying the target and contents of the transaction. + */ + union { + /* target descriptor of command transaction */ + __u32 handle; + /* target descriptor of return transaction */ + binder_uintptr_t ptr; + } target; + binder_uintptr_t cookie; /* target object cookie */ + __u32 code; /* transaction command */ + + /* General information about the transaction. */ + __u32 flags; + pid_t sender_pid; + uid_t sender_euid; + binder_size_t data_size; /* number of bytes of data */ + binder_size_t offsets_size; /* number of bytes of offsets */ + + /* If this transaction is inline, the data immediately + * follows here; otherwise, it ends with a pointer to + * the data buffer. + */ + union { + struct { + /* transaction data */ + binder_uintptr_t buffer; + /* offsets from buffer to flat_binder_object structs */ + binder_uintptr_t offsets; + } ptr; + __u8 buf[8]; + } data; +}; + +struct binder_ptr_cookie { + binder_uintptr_t ptr; + binder_uintptr_t cookie; +}; + +struct binder_handle_cookie { + __u32 handle; + binder_uintptr_t cookie; +} __attribute__((packed)); + +struct binder_pri_desc { + __s32 priority; + __u32 desc; +}; + +struct binder_pri_ptr_cookie { + __s32 priority; + binder_uintptr_t ptr; + binder_uintptr_t cookie; +}; + +enum binder_driver_return_protocol { + BR_ERROR = _IOR('r', 0, __s32), + /* + * int: error code + */ + + BR_OK = _IO('r', 1), + /* No parameters! */ + + BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data), + BR_REPLY = _IOR('r', 3, struct binder_transaction_data), + /* + * binder_transaction_data: the received command. + */ + + BR_ACQUIRE_RESULT = _IOR('r', 4, __s32), + /* + * not currently supported + * int: 0 if the last bcATTEMPT_ACQUIRE was not successful. + * Else the remote object has acquired a primary reference. + */ + + BR_DEAD_REPLY = _IO('r', 5), + /* + * The target of the last transaction (either a bcTRANSACTION or + * a bcATTEMPT_ACQUIRE) is no longer with us. No parameters. + */ + + BR_TRANSACTION_COMPLETE = _IO('r', 6), + /* + * No parameters... always refers to the last transaction requested + * (including replies). Note that this will be sent even for + * asynchronous transactions. + */ + + BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie), + BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie), + BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie), + BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie), + /* + * void *: ptr to binder + * void *: cookie for binder + */ + + BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cookie), + /* + * not currently supported + * int: priority + * void *: ptr to binder + * void *: cookie for binder + */ + + BR_NOOP = _IO('r', 12), + /* + * No parameters. Do nothing and examine the next command. It exists + * primarily so that we can replace it with a BR_SPAWN_LOOPER command. + */ + + BR_SPAWN_LOOPER = _IO('r', 13), + /* + * No parameters. The driver has determined that a process has no + * threads waiting to service incoming transactions. When a process + * receives this command, it must spawn a new service thread and + * register it via bcENTER_LOOPER. + */ + + BR_FINISHED = _IO('r', 14), + /* + * not currently supported + * stop threadpool thread + */ + + BR_DEAD_BINDER = _IOR('r', 15, binder_uintptr_t), + /* + * void *: cookie + */ + BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, binder_uintptr_t), + /* + * void *: cookie + */ + + BR_FAILED_REPLY = _IO('r', 17), + /* + * The the last transaction (either a bcTRANSACTION or + * a bcATTEMPT_ACQUIRE) failed (e.g. out of memory). No parameters. + */ +}; + +enum binder_driver_command_protocol { + BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data), + BC_REPLY = _IOW('c', 1, struct binder_transaction_data), + /* + * binder_transaction_data: the sent command. + */ + + BC_ACQUIRE_RESULT = _IOW('c', 2, __s32), + /* + * not currently supported + * int: 0 if the last BR_ATTEMPT_ACQUIRE was not successful. + * Else you have acquired a primary reference on the object. + */ + + BC_FREE_BUFFER = _IOW('c', 3, binder_uintptr_t), + /* + * void *: ptr to transaction data received on a read + */ + + BC_INCREFS = _IOW('c', 4, __u32), + BC_ACQUIRE = _IOW('c', 5, __u32), + BC_RELEASE = _IOW('c', 6, __u32), + BC_DECREFS = _IOW('c', 7, __u32), + /* + * int: descriptor + */ + + BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie), + BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie), + /* + * void *: ptr to binder + * void *: cookie for binder + */ + + BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc), + /* + * not currently supported + * int: priority + * int: descriptor + */ + + BC_REGISTER_LOOPER = _IO('c', 11), + /* + * No parameters. + * Register a spawned looper thread with the device. + */ + + BC_ENTER_LOOPER = _IO('c', 12), + BC_EXIT_LOOPER = _IO('c', 13), + /* + * No parameters. + * These two commands are sent as an application-level thread + * enters and exits the binder loop, respectively. They are + * used so the binder can have an accurate count of the number + * of looping threads it has available. + */ + + BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, + struct binder_handle_cookie), + /* + * int: handle + * void *: cookie + */ + + BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, + struct binder_handle_cookie), + /* + * int: handle + * void *: cookie + */ + + BC_DEAD_BINDER_DONE = _IOW('c', 16, binder_uintptr_t), + /* + * void *: cookie + */ +}; + +#endif /* _UAPI_LINUX_BINDER_H */ + diff --git a/drivers/staging/android/uapi/sw_sync.h b/drivers/staging/android/uapi/sw_sync.h new file mode 100644 index 000000000000..9b5d4869505c --- /dev/null +++ b/drivers/staging/android/uapi/sw_sync.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2012 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _UAPI_LINUX_SW_SYNC_H +#define _UAPI_LINUX_SW_SYNC_H + +#include + +struct sw_sync_create_fence_data { + __u32 value; + char name[32]; + __s32 fence; /* fd of new fence */ +}; + +#define SW_SYNC_IOC_MAGIC 'W' + +#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\ + struct sw_sync_create_fence_data) +#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32) + +#endif /* _UAPI_LINUX_SW_SYNC_H */ diff --git a/drivers/staging/android/uapi/sync.h b/drivers/staging/android/uapi/sync.h new file mode 100644 index 000000000000..e964c751f6b8 --- /dev/null +++ b/drivers/staging/android/uapi/sync.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2012 Google, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _UAPI_LINUX_SYNC_H +#define _UAPI_LINUX_SYNC_H + +#include +#include + +/** + * struct sync_merge_data - data passed to merge ioctl + * @fd2: file descriptor of second fence + * @name: name of new fence + * @fence: returns the fd of the new fence to userspace + */ +struct sync_merge_data { + __s32 fd2; /* fd of second fence */ + char name[32]; /* name of new fence */ + __s32 fence; /* fd on newly created fence */ +}; + +/** + * struct sync_pt_info - detailed sync_pt information + * @len: length of sync_pt_info including any driver_data + * @obj_name: name of parent sync_timeline + * @driver_name: name of driver implementing the parent + * @status: status of the sync_pt 0:active 1:signaled <0:error + * @timestamp_ns: timestamp of status change in nanoseconds + * @driver_data: any driver dependent data + */ +struct sync_pt_info { + __u32 len; + char obj_name[32]; + char driver_name[32]; + __s32 status; + __u64 timestamp_ns; + + __u8 driver_data[0]; +}; + +/** + * struct sync_fence_info_data - data returned from fence info ioctl + * @len: ioctl caller writes the size of the buffer its passing in. + * ioctl returns length of sync_fence_data returned to userspace + * including pt_info. + * @name: name of fence + * @status: status of fence. 1: signaled 0:active <0:error + * @pt_info: a sync_pt_info struct for every sync_pt in the fence + */ +struct sync_fence_info_data { + __u32 len; + char name[32]; + __s32 status; + + __u8 pt_info[0]; +}; + +#define SYNC_IOC_MAGIC '>' + +/** + * DOC: SYNC_IOC_WAIT - wait for a fence to signal + * + * pass timeout in milliseconds. Waits indefinitely timeout < 0. + */ +#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32) + +/** + * DOC: SYNC_IOC_MERGE - merge two fences + * + * Takes a struct sync_merge_data. Creates a new fence containing copies of + * the sync_pts in both the calling fd and sync_merge_data.fd2. Returns the + * new fence's fd in sync_merge_data.fence + */ +#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data) + +/** + * DOC: SYNC_IOC_FENCE_INFO - get detailed information on a fence + * + * Takes a struct sync_fence_info_data with extra space allocated for pt_info. + * Caller should write the size of the buffer into len. On return, len is + * updated to reflect the total size of the sync_fence_info_data including + * pt_info. + * + * pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence. + * To iterate over the sync_pt_infos, use the sync_pt_info.len field. + */ +#define SYNC_IOC_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2,\ + struct sync_fence_info_data) + +#endif /* _UAPI_LINUX_SYNC_H */ diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h index f0d6f0c38207..1b2d9f3bd55a 100644 --- a/drivers/staging/bcm/Adapter.h +++ b/drivers/staging/bcm/Adapter.h @@ -37,8 +37,10 @@ struct bcm_link_request { union u_ip_address { struct { - ULONG ulIpv4Addr[MAX_IP_RANGE_LENGTH]; /* Source Ip Address Range */ - ULONG ulIpv4Mask[MAX_IP_RANGE_LENGTH]; /* Source Ip Mask Address Range */ + /* Source Ip Address Range */ + ULONG ulIpv4Addr[MAX_IP_RANGE_LENGTH]; + /* Source Ip Mask Address Range */ + ULONG ulIpv4Mask[MAX_IP_RANGE_LENGTH]; }; struct { ULONG ulIpv6Addr[MAX_IP_RANGE_LENGTH * 4]; /* Source Ip Address Range */ diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c index f1b6de0293c8..ae7490b4d70e 100644 --- a/drivers/staging/bcm/Bcmchar.c +++ b/drivers/staging/bcm/Bcmchar.c @@ -150,15 +150,2146 @@ static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size, return PktLen; } +static int bcm_char_ioctl_reg_read_private(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_rdm_buffer sRdmBuffer = {0}; + struct bcm_ioctl_buffer IoBuffer; + PCHAR temp_buff; + INT Status = STATUS_FAILURE; + UINT Bufflen; + u16 temp_value; + int bytes; + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(sRdmBuffer)) + return -EINVAL; + + if (copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, + IoBuffer.InputLength)) + return -EFAULT; + + if (IoBuffer.OutputLength > USHRT_MAX || + IoBuffer.OutputLength == 0) { + return -EINVAL; + } + + Bufflen = IoBuffer.OutputLength; + temp_value = 4 - (Bufflen % 4); + Bufflen += temp_value % 4; + + temp_buff = kmalloc(Bufflen, GFP_KERNEL); + if (!temp_buff) + return -ENOMEM; + + bytes = rdmalt(Adapter, (UINT)sRdmBuffer.Register, + (PUINT)temp_buff, Bufflen); + if (bytes > 0) { + Status = STATUS_SUCCESS; + if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, bytes)) { + kfree(temp_buff); + return -EFAULT; + } + } else { + Status = bytes; + } + + kfree(temp_buff); + return Status; +} + +static int bcm_char_ioctl_reg_write_private(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_wrm_buffer sWrmBuffer = {0}; + struct bcm_ioctl_buffer IoBuffer; + UINT uiTempVar = 0; + INT Status; + + /* Copy Ioctl Buffer structure */ + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(sWrmBuffer)) + return -EINVAL; + + /* Get WrmBuffer structure */ + if (copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, + IoBuffer.InputLength)) + return -EFAULT; + + uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK; + if (!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) && + ((uiTempVar == EEPROM_REJECT_REG_1) || + (uiTempVar == EEPROM_REJECT_REG_2) || + (uiTempVar == EEPROM_REJECT_REG_3) || + (uiTempVar == EEPROM_REJECT_REG_4))) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "EEPROM Access Denied, not in VSG Mode\n"); + return -EFAULT; + } + + Status = wrmalt(Adapter, (UINT)sWrmBuffer.Register, + (PUINT)sWrmBuffer.Data, sizeof(ULONG)); + + if (Status == STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, "WRM Done\n"); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, "WRM Failed\n"); + Status = -EFAULT; + } + return Status; +} + +static int bcm_char_ioctl_eeprom_reg_read(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_rdm_buffer sRdmBuffer = {0}; + struct bcm_ioctl_buffer IoBuffer; + PCHAR temp_buff = NULL; + UINT uiTempVar = 0; + INT Status; + int bytes; + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Device in Idle Mode, Blocking Rdms\n"); + return -EACCES; + } + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(sRdmBuffer)) + return -EINVAL; + + if (copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, + IoBuffer.InputLength)) + return -EFAULT; + + if (IoBuffer.OutputLength > USHRT_MAX || + IoBuffer.OutputLength == 0) { + return -EINVAL; + } + + temp_buff = kmalloc(IoBuffer.OutputLength, GFP_KERNEL); + if (!temp_buff) + return STATUS_FAILURE; + + if ((((ULONG)sRdmBuffer.Register & 0x0F000000) != 0x0F000000) || + ((ULONG)sRdmBuffer.Register & 0x3)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "RDM Done On invalid Address : %x Access Denied.\n", + (int)sRdmBuffer.Register); + + kfree(temp_buff); + return -EINVAL; + } + + uiTempVar = sRdmBuffer.Register & EEPROM_REJECT_MASK; + bytes = rdmaltWithLock(Adapter, (UINT)sRdmBuffer.Register, + (PUINT)temp_buff, IoBuffer.OutputLength); + + if (bytes > 0) { + Status = STATUS_SUCCESS; + if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, bytes)) { + kfree(temp_buff); + return -EFAULT; + } + } else { + Status = bytes; + } + + kfree(temp_buff); + return Status; +} + +static int bcm_char_ioctl_eeprom_reg_write(void __user *argp, + struct bcm_mini_adapter *Adapter, UINT cmd) +{ + struct bcm_wrm_buffer sWrmBuffer = {0}; + struct bcm_ioctl_buffer IoBuffer; + UINT uiTempVar = 0; + INT Status; + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Device in Idle Mode, Blocking Wrms\n"); + return -EACCES; + } + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(sWrmBuffer)) + return -EINVAL; + + /* Get WrmBuffer structure */ + if (copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, + IoBuffer.InputLength)) + return -EFAULT; + + if ((((ULONG)sWrmBuffer.Register & 0x0F000000) != 0x0F000000) || + ((ULONG)sWrmBuffer.Register & 0x3)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "WRM Done On invalid Address : %x Access Denied.\n", + (int)sWrmBuffer.Register); + return -EINVAL; + } + + uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK; + if (!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) && + ((uiTempVar == EEPROM_REJECT_REG_1) || + (uiTempVar == EEPROM_REJECT_REG_2) || + (uiTempVar == EEPROM_REJECT_REG_3) || + (uiTempVar == EEPROM_REJECT_REG_4)) && + (cmd == IOCTL_BCM_REGISTER_WRITE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "EEPROM Access Denied, not in VSG Mode\n"); + return -EFAULT; + } + + Status = wrmaltWithLock(Adapter, (UINT)sWrmBuffer.Register, + (PUINT)sWrmBuffer.Data, + sWrmBuffer.Length); + + if (Status == STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, OSAL_DBG, + DBG_LVL_ALL, "WRM Done\n"); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, "WRM Failed\n"); + Status = -EFAULT; + } + return Status; +} + +static int bcm_char_ioctl_gpio_set_request(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_gpio_info gpio_info = {0}; + struct bcm_ioctl_buffer IoBuffer; + UCHAR ucResetValue[4]; + UINT value = 0; + UINT uiBit = 0; + UINT uiOperation = 0; + INT Status; + int bytes; + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, + "GPIO Can't be set/clear in Low power Mode"); + return -EACCES; + } + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(gpio_info)) + return -EINVAL; + + if (copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength)) + return -EFAULT; + + uiBit = gpio_info.uiGpioNumber; + uiOperation = gpio_info.uiGpioValue; + value = (1< is not correspond to LED !!!", + value); + return -EINVAL; + } + + /* Set - setting 1 */ + if (uiOperation) { + /* Set the gpio output register */ + Status = wrmaltWithLock(Adapter, + BCM_GPIO_OUTPUT_SET_REG, + (PUINT)(&value), sizeof(UINT)); + + if (Status == STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + OSAL_DBG, DBG_LVL_ALL, + "Set the GPIO bit\n"); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + OSAL_DBG, DBG_LVL_ALL, + "Failed to set the %dth GPIO\n", + uiBit); + return Status; + } + } else { + /* Set the gpio output register */ + Status = wrmaltWithLock(Adapter, + BCM_GPIO_OUTPUT_CLR_REG, + (PUINT)(&value), sizeof(UINT)); + + if (Status == STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + OSAL_DBG, DBG_LVL_ALL, + "Set the GPIO bit\n"); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + OSAL_DBG, DBG_LVL_ALL, + "Failed to clear the %dth GPIO\n", + uiBit); + return Status; + } + } + + bytes = rdmaltWithLock(Adapter, (UINT)GPIO_MODE_REGISTER, + (PUINT)ucResetValue, sizeof(UINT)); + if (bytes < 0) { + Status = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "GPIO_MODE_REGISTER read failed"); + return Status; + } else { + Status = STATUS_SUCCESS; + } + + /* Set the gpio mode register to output */ + *(UINT *)ucResetValue |= (1<IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, + "GPIO Can't be set/clear in Low power Mode"); + return -EACCES; + } + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(threadReq)) + return -EINVAL; + + if (copy_from_user(&threadReq, IoBuffer.InputBuffer, IoBuffer.InputLength)) + return -EFAULT; + + /* if LED thread is running(Actively or Inactively) + * set it state to make inactive + */ + if (Adapter->LEDInfo.led_thread_running) { + if (threadReq.ThreadState == LED_THREAD_ACTIVATION_REQ) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + OSAL_DBG, DBG_LVL_ALL, + "Activating thread req"); + Adapter->DriverState = LED_THREAD_ACTIVE; + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + OSAL_DBG, DBG_LVL_ALL, + "DeActivating Thread req....."); + Adapter->DriverState = LED_THREAD_INACTIVE; + } + + /* signal thread. */ + wake_up(&Adapter->LEDInfo.notify_led_event); + } + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_gpio_status_request(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_gpio_info gpio_info = {0}; + struct bcm_ioctl_buffer IoBuffer; + ULONG uiBit = 0; + UCHAR ucRead[4]; + INT Status; + int bytes; + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) + return -EACCES; + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(gpio_info)) + return -EINVAL; + + if (copy_from_user(&gpio_info, IoBuffer.InputBuffer, + IoBuffer.InputLength)) + return -EFAULT; + + uiBit = gpio_info.uiGpioNumber; + + /* Set the gpio output register */ + bytes = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER, + (PUINT)ucRead, sizeof(UINT)); + + if (bytes < 0) { + Status = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "RDM Failed\n"); + return Status; + } else { + Status = STATUS_SUCCESS; + } + return Status; +} + +static int bcm_char_ioctl_gpio_multi_request(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_gpio_multi_info gpio_multi_info[MAX_IDX]; + struct bcm_gpio_multi_info *pgpio_multi_info = + (struct bcm_gpio_multi_info *)gpio_multi_info; + struct bcm_ioctl_buffer IoBuffer; + UCHAR ucResetValue[4]; + INT Status = STATUS_FAILURE; + int bytes; + + memset(pgpio_multi_info, 0, MAX_IDX * sizeof(struct bcm_gpio_multi_info)); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) + return -EINVAL; + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(gpio_multi_info)) + return -EINVAL; + if (IoBuffer.OutputLength > sizeof(gpio_multi_info)) + IoBuffer.OutputLength = sizeof(gpio_multi_info); + + if (copy_from_user(&gpio_multi_info, IoBuffer.InputBuffer, + IoBuffer.InputLength)) + return -EFAULT; + + if (IsReqGpioIsLedInNVM(Adapter, + pgpio_multi_info[WIMAX_IDX].uiGPIOMask) == false) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, + "Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!", + pgpio_multi_info[WIMAX_IDX].uiGPIOMask, + Adapter->gpioBitMap); + return -EINVAL; + } + + /* Set the gpio output register */ + if ((pgpio_multi_info[WIMAX_IDX].uiGPIOMask) & + (pgpio_multi_info[WIMAX_IDX].uiGPIOCommand)) { + /* Set 1's in GPIO OUTPUT REGISTER */ + *(UINT *)ucResetValue = pgpio_multi_info[WIMAX_IDX].uiGPIOMask & + pgpio_multi_info[WIMAX_IDX].uiGPIOCommand & + pgpio_multi_info[WIMAX_IDX].uiGPIOValue; + + if (*(UINT *) ucResetValue) + Status = wrmaltWithLock(Adapter, + BCM_GPIO_OUTPUT_SET_REG, + (PUINT)ucResetValue, sizeof(ULONG)); + + if (Status != STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "WRM to BCM_GPIO_OUTPUT_SET_REG Failed."); + return Status; + } + + /* Clear to 0's in GPIO OUTPUT REGISTER */ + *(UINT *)ucResetValue = (pgpio_multi_info[WIMAX_IDX].uiGPIOMask & + pgpio_multi_info[WIMAX_IDX].uiGPIOCommand & + (~(pgpio_multi_info[WIMAX_IDX].uiGPIOValue))); + + if (*(UINT *) ucResetValue) + Status = wrmaltWithLock(Adapter, + BCM_GPIO_OUTPUT_CLR_REG, (PUINT)ucResetValue, + sizeof(ULONG)); + + if (Status != STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "WRM to BCM_GPIO_OUTPUT_CLR_REG Failed."); + return Status; + } + } + + if (pgpio_multi_info[WIMAX_IDX].uiGPIOMask) { + bytes = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER, + (PUINT)ucResetValue, sizeof(UINT)); + + if (bytes < 0) { + Status = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "RDM to GPIO_PIN_STATE_REGISTER Failed."); + return Status; + } else { + Status = STATUS_SUCCESS; + } + + pgpio_multi_info[WIMAX_IDX].uiGPIOValue = (*(UINT *)ucResetValue & + pgpio_multi_info[WIMAX_IDX].uiGPIOMask); + } + + Status = copy_to_user(IoBuffer.OutputBuffer, &gpio_multi_info, + IoBuffer.OutputLength); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Failed while copying Content to IOBufer for user space err:%d", + Status); + return -EFAULT; + } + return Status; +} + +static int bcm_char_ioctl_gpio_mode_request(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_gpio_multi_mode gpio_multi_mode[MAX_IDX]; + struct bcm_gpio_multi_mode *pgpio_multi_mode = + (struct bcm_gpio_multi_mode *)gpio_multi_mode; + struct bcm_ioctl_buffer IoBuffer; + UCHAR ucResetValue[4]; + INT Status; + int bytes; + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) + return -EINVAL; + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(gpio_multi_mode)) + return -EINVAL; + if (IoBuffer.OutputLength > sizeof(gpio_multi_mode)) + IoBuffer.OutputLength = sizeof(gpio_multi_mode); + + if (copy_from_user(&gpio_multi_mode, IoBuffer.InputBuffer, + IoBuffer.InputLength)) + return -EFAULT; + + bytes = rdmaltWithLock(Adapter, (UINT)GPIO_MODE_REGISTER, + (PUINT)ucResetValue, sizeof(UINT)); + + if (bytes < 0) { + Status = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Read of GPIO_MODE_REGISTER failed"); + return Status; + } else { + Status = STATUS_SUCCESS; + } + + /* Validating the request */ + if (IsReqGpioIsLedInNVM(Adapter, + pgpio_multi_mode[WIMAX_IDX].uiGPIOMask) == false) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!", + pgpio_multi_mode[WIMAX_IDX].uiGPIOMask, + Adapter->gpioBitMap); + return -EINVAL; + } + + if (pgpio_multi_mode[WIMAX_IDX].uiGPIOMask) { + /* write all OUT's (1's) */ + *(UINT *) ucResetValue |= (pgpio_multi_mode[WIMAX_IDX].uiGPIOMode & + pgpio_multi_mode[WIMAX_IDX].uiGPIOMask); + + /* write all IN's (0's) */ + *(UINT *) ucResetValue &= ~((~pgpio_multi_mode[WIMAX_IDX].uiGPIOMode) & + pgpio_multi_mode[WIMAX_IDX].uiGPIOMask); + + /* Currently implemented return the modes of all GPIO's + * else needs to bit AND with mask + */ + pgpio_multi_mode[WIMAX_IDX].uiGPIOMode = *(UINT *)ucResetValue; + + Status = wrmaltWithLock(Adapter, GPIO_MODE_REGISTER, + (PUINT)ucResetValue, sizeof(ULONG)); + if (Status == STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "WRM to GPIO_MODE_REGISTER Done"); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "WRM to GPIO_MODE_REGISTER Failed"); + return -EFAULT; + } + } else { + /* if uiGPIOMask is 0 then return mode register configuration */ + pgpio_multi_mode[WIMAX_IDX].uiGPIOMode = *(UINT *)ucResetValue; + } + + Status = copy_to_user(IoBuffer.OutputBuffer, &gpio_multi_mode, + IoBuffer.OutputLength); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Failed while copying Content to IOBufer for user space err:%d", + Status); + return -EFAULT; + } + return Status; +} + +static int bcm_char_ioctl_misc_request(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_ioctl_buffer IoBuffer; + PVOID pvBuffer = NULL; + INT Status; + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength < sizeof(struct bcm_link_request)) + return -EINVAL; + + if (IoBuffer.InputLength > MAX_CNTL_PKT_SIZE) + return -EINVAL; + + pvBuffer = memdup_user(IoBuffer.InputBuffer, + IoBuffer.InputLength); + if (IS_ERR(pvBuffer)) + return PTR_ERR(pvBuffer); + + down(&Adapter->LowPowerModeSync); + Status = wait_event_interruptible_timeout(Adapter->lowpower_mode_wait_queue, + !Adapter->bPreparingForLowPowerMode, + (1 * HZ)); + if (Status == -ERESTARTSYS) + goto cntrlEnd; + + if (Adapter->bPreparingForLowPowerMode) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Preparing Idle Mode is still True - Hence Rejecting control message\n"); + Status = STATUS_FAILURE; + goto cntrlEnd; + } + Status = CopyBufferToControlPacket(Adapter, (PVOID)pvBuffer); + +cntrlEnd: + up(&Adapter->LowPowerModeSync); + kfree(pvBuffer); + return Status; +} + +static int bcm_char_ioctl_buffer_download_start( + struct bcm_mini_adapter *Adapter) +{ + INT Status; + + if (down_trylock(&Adapter->NVMRdmWrmLock)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_CHIP_RESET not allowed as EEPROM Read/Write is in progress\n"); + return -EACCES; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Starting the firmware download PID =0x%x!!!!\n", current->pid); + + if (down_trylock(&Adapter->fw_download_sema)) + return -EBUSY; + + Adapter->bBinDownloaded = false; + Adapter->fw_download_process_pid = current->pid; + Adapter->bCfgDownloaded = false; + Adapter->fw_download_done = false; + netif_carrier_off(Adapter->dev); + netif_stop_queue(Adapter->dev); + Status = reset_card_proc(Adapter); + if (Status) { + pr_err(PFX "%s: reset_card_proc Failed!\n", Adapter->dev->name); + up(&Adapter->fw_download_sema); + up(&Adapter->NVMRdmWrmLock); + return Status; + } + mdelay(10); + + up(&Adapter->NVMRdmWrmLock); + return Status; +} + +static int bcm_char_ioctl_buffer_download(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_firmware_info *psFwInfo = NULL; + struct bcm_ioctl_buffer IoBuffer; + INT Status; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Starting the firmware download PID =0x%x!!!!\n", current->pid); + + if (!down_trylock(&Adapter->fw_download_sema)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Invalid way to download buffer. Use Start and then call this!!!\n"); + up(&Adapter->fw_download_sema); + return -EINVAL; + } + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) { + up(&Adapter->fw_download_sema); + return -EFAULT; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Length for FW DLD is : %lx\n", IoBuffer.InputLength); + + if (IoBuffer.InputLength > sizeof(struct bcm_firmware_info)) { + up(&Adapter->fw_download_sema); + return -EINVAL; + } + + psFwInfo = kmalloc(sizeof(*psFwInfo), GFP_KERNEL); + if (!psFwInfo) { + up(&Adapter->fw_download_sema); + return -ENOMEM; + } + + if (copy_from_user(psFwInfo, IoBuffer.InputBuffer, + IoBuffer.InputLength)) { + up(&Adapter->fw_download_sema); + kfree(psFwInfo); + return -EFAULT; + } + + if (!psFwInfo->pvMappedFirmwareAddress || + (psFwInfo->u32FirmwareLength == 0)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Something else is wrong %lu\n", + psFwInfo->u32FirmwareLength); + up(&Adapter->fw_download_sema); + kfree(psFwInfo); + Status = -EINVAL; + return Status; + } + + Status = bcm_ioctl_fw_download(Adapter, psFwInfo); + + if (Status != STATUS_SUCCESS) { + if (psFwInfo->u32StartingAddress == CONFIG_BEGIN_ADDR) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "IOCTL: Configuration File Upload Failed\n"); + else + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "IOCTL: Firmware File Upload Failed\n"); + + /* up(&Adapter->fw_download_sema); */ + + if (Adapter->LEDInfo.led_thread_running & + BCM_LED_THREAD_RUNNING_ACTIVELY) { + Adapter->DriverState = DRIVER_INIT; + Adapter->LEDInfo.bLedInitDone = false; + wake_up(&Adapter->LEDInfo.notify_led_event); + } + } + + if (Status != STATUS_SUCCESS) + up(&Adapter->fw_download_sema); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, OSAL_DBG, DBG_LVL_ALL, + "IOCTL: Firmware File Uploaded\n"); + kfree(psFwInfo); + return Status; +} + +static int bcm_char_ioctl_buffer_download_stop(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + INT Status; + int timeout = 0; + + if (!down_trylock(&Adapter->fw_download_sema)) { + up(&Adapter->fw_download_sema); + return -EINVAL; + } + + if (down_trylock(&Adapter->NVMRdmWrmLock)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "FW download blocked as EEPROM Read/Write is in progress\n"); + up(&Adapter->fw_download_sema); + return -EACCES; + } + + Adapter->bBinDownloaded = TRUE; + Adapter->bCfgDownloaded = TRUE; + atomic_set(&Adapter->CurrNumFreeTxDesc, 0); + Adapter->CurrNumRecvDescs = 0; + Adapter->downloadDDR = 0; + + /* setting the Mips to Run */ + Status = run_card_proc(Adapter); + + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Firm Download Failed\n"); + up(&Adapter->fw_download_sema); + up(&Adapter->NVMRdmWrmLock); + return Status; + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, "Firm Download Over...\n"); + } + + mdelay(10); + + /* Wait for MailBox Interrupt */ + if (StartInterruptUrb((struct bcm_interface_adapter *)Adapter->pvInterfaceAdapter)) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Unable to send interrupt...\n"); + + timeout = 5*HZ; + Adapter->waiting_to_fw_download_done = false; + wait_event_timeout(Adapter->ioctl_fw_dnld_wait_queue, + Adapter->waiting_to_fw_download_done, timeout); + Adapter->fw_download_process_pid = INVALID_PID; + Adapter->fw_download_done = TRUE; + atomic_set(&Adapter->CurrNumFreeTxDesc, 0); + Adapter->CurrNumRecvDescs = 0; + Adapter->PrevNumRecvDescs = 0; + atomic_set(&Adapter->cntrlpktCnt, 0); + Adapter->LinkUpStatus = 0; + Adapter->LinkStatus = 0; + + if (Adapter->LEDInfo.led_thread_running & + BCM_LED_THREAD_RUNNING_ACTIVELY) { + Adapter->DriverState = FW_DOWNLOAD_DONE; + wake_up(&Adapter->LEDInfo.notify_led_event); + } + + if (!timeout) + Status = -ENODEV; + + up(&Adapter->fw_download_sema); + up(&Adapter->NVMRdmWrmLock); + return Status; +} + +static int bcm_char_ioctl_chip_reset(struct bcm_mini_adapter *Adapter) +{ + INT Status; + INT NVMAccess; + + NVMAccess = down_trylock(&Adapter->NVMRdmWrmLock); + if (NVMAccess) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + " IOCTL_BCM_CHIP_RESET not allowed as EEPROM Read/Write is in progress\n"); + return -EACCES; + } + + down(&Adapter->RxAppControlQueuelock); + Status = reset_card_proc(Adapter); + flushAllAppQ(); + up(&Adapter->RxAppControlQueuelock); + up(&Adapter->NVMRdmWrmLock); + ResetCounters(Adapter); + return Status; +} + +static int bcm_char_ioctl_qos_threshold(ULONG arg, + struct bcm_mini_adapter *Adapter) +{ + USHORT uiLoopIndex; + + for (uiLoopIndex = 0; uiLoopIndex < NO_OF_QUEUES; uiLoopIndex++) { + if (get_user(Adapter->PackInfo[uiLoopIndex].uiThreshold, + (unsigned long __user *)arg)) { + return -EFAULT; + } + } + return 0; +} + +static int bcm_char_ioctl_switch_transfer_mode(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + UINT uiData = 0; + + if (copy_from_user(&uiData, argp, sizeof(UINT))) + return -EFAULT; + + if (uiData) { + /* Allow All Packets */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_SWITCH_TRANSFER_MODE: ETH_PACKET_TUNNELING_MODE\n"); + Adapter->TransferMode = ETH_PACKET_TUNNELING_MODE; + } else { + /* Allow IP only Packets */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_SWITCH_TRANSFER_MODE: IP_PACKET_ONLY_MODE\n"); + Adapter->TransferMode = IP_PACKET_ONLY_MODE; + } + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_get_driver_version(void __user *argp) +{ + struct bcm_ioctl_buffer IoBuffer; + ulong len; + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + len = min_t(ulong, IoBuffer.OutputLength, strlen(DRV_VERSION) + 1); + + if (copy_to_user(IoBuffer.OutputBuffer, DRV_VERSION, len)) + return -EFAULT; + + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_get_current_status(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_link_state link_state; + struct bcm_ioctl_buffer IoBuffer; + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "copy_from_user failed..\n"); + return -EFAULT; + } + + if (IoBuffer.OutputLength != sizeof(link_state)) + return -EINVAL; + + memset(&link_state, 0, sizeof(link_state)); + link_state.bIdleMode = Adapter->IdleMode; + link_state.bShutdownMode = Adapter->bShutStatus; + link_state.ucLinkStatus = Adapter->LinkStatus; + + if (copy_to_user(IoBuffer.OutputBuffer, &link_state, min_t(size_t, + sizeof(link_state), IoBuffer.OutputLength))) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy_to_user Failed..\n"); + return -EFAULT; + } + return STATUS_SUCCESS; +} + + +static int bcm_char_ioctl_set_mac_tracing(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_ioctl_buffer IoBuffer; + UINT tracing_flag; + + /* copy ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (copy_from_user(&tracing_flag, IoBuffer.InputBuffer, sizeof(UINT))) + return -EFAULT; + + if (tracing_flag) + Adapter->pTarangs->MacTracingEnabled = TRUE; + else + Adapter->pTarangs->MacTracingEnabled = false; + + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_get_dsx_indication(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_ioctl_buffer IoBuffer; + ULONG ulSFId = 0; + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.OutputLength < sizeof(struct bcm_add_indication_alt)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Mismatch req: %lx needed is =0x%zx!!!", + IoBuffer.OutputLength, + sizeof(struct bcm_add_indication_alt)); + return -EINVAL; + } + + if (copy_from_user(&ulSFId, IoBuffer.InputBuffer, sizeof(ulSFId))) + return -EFAULT; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Get DSX Data SF ID is =%lx\n", ulSFId); + get_dsx_sf_data_to_application(Adapter, ulSFId, IoBuffer.OutputBuffer); + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_get_host_mibs(void __user *argp, + struct bcm_mini_adapter *Adapter, struct bcm_tarang_data *pTarang) +{ + struct bcm_ioctl_buffer IoBuffer; + INT Status = STATUS_FAILURE; + PVOID temp_buff; + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.OutputLength != sizeof(struct bcm_host_stats_mibs)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Length Check failed %lu %zd\n", IoBuffer.OutputLength, + sizeof(struct bcm_host_stats_mibs)); + return -EINVAL; + } + + /* FIXME: HOST_STATS are too big for kmalloc (122048)! */ + temp_buff = kzalloc(sizeof(struct bcm_host_stats_mibs), GFP_KERNEL); + if (!temp_buff) + return STATUS_FAILURE; + + Status = ProcessGetHostMibs(Adapter, temp_buff); + GetDroppedAppCntrlPktMibs(temp_buff, pTarang); + + if (Status != STATUS_FAILURE) { + if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, + sizeof(struct bcm_host_stats_mibs))) { + kfree(temp_buff); + return -EFAULT; + } + } + + kfree(temp_buff); + return Status; +} + +static int bcm_char_ioctl_bulk_wrm(void __user *argp, + struct bcm_mini_adapter *Adapter, UINT cmd) +{ + struct bcm_bulk_wrm_buffer *pBulkBuffer; + struct bcm_ioctl_buffer IoBuffer; + UINT uiTempVar = 0; + INT Status = STATUS_FAILURE; + PCHAR pvBuffer = NULL; + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, + "Device in Idle/Shutdown Mode, Blocking Wrms\n"); + return -EACCES; + } + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength < sizeof(ULONG) * 2) + return -EINVAL; + + pvBuffer = memdup_user(IoBuffer.InputBuffer, + IoBuffer.InputLength); + if (IS_ERR(pvBuffer)) + return PTR_ERR(pvBuffer); + + pBulkBuffer = (struct bcm_bulk_wrm_buffer *)pvBuffer; + + if (((ULONG)pBulkBuffer->Register & 0x0F000000) != 0x0F000000 || + ((ULONG)pBulkBuffer->Register & 0x3)) { + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, + "WRM Done On invalid Address : %x Access Denied.\n", + (int)pBulkBuffer->Register); + kfree(pvBuffer); + return -EINVAL; + } + + uiTempVar = pBulkBuffer->Register & EEPROM_REJECT_MASK; + if (!((Adapter->pstargetparams->m_u32Customize)&VSG_MODE) && + ((uiTempVar == EEPROM_REJECT_REG_1) || + (uiTempVar == EEPROM_REJECT_REG_2) || + (uiTempVar == EEPROM_REJECT_REG_3) || + (uiTempVar == EEPROM_REJECT_REG_4)) && + (cmd == IOCTL_BCM_REGISTER_WRITE)) { + + kfree(pvBuffer); + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, + "EEPROM Access Denied, not in VSG Mode\n"); + return -EFAULT; + } + + if (pBulkBuffer->SwapEndian == false) + Status = wrmWithLock(Adapter, (UINT)pBulkBuffer->Register, + (PCHAR)pBulkBuffer->Values, + IoBuffer.InputLength - 2*sizeof(ULONG)); + else + Status = wrmaltWithLock(Adapter, (UINT)pBulkBuffer->Register, + (PUINT)pBulkBuffer->Values, + IoBuffer.InputLength - 2*sizeof(ULONG)); + + if (Status != STATUS_SUCCESS) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM Failed\n"); + + kfree(pvBuffer); + return Status; +} + +static int bcm_char_ioctl_get_nvm_size(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_ioctl_buffer IoBuffer; + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (Adapter->eNVMType == NVM_EEPROM || Adapter->eNVMType == NVM_FLASH) { + if (copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiNVMDSDSize, + sizeof(UINT))) + return -EFAULT; + } + + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_cal_init(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_ioctl_buffer IoBuffer; + UINT uiSectorSize = 0; + INT Status = STATUS_FAILURE; + + if (Adapter->eNVMType == NVM_FLASH) { + if (copy_from_user(&IoBuffer, argp, + sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (copy_from_user(&uiSectorSize, IoBuffer.InputBuffer, + sizeof(UINT))) + return -EFAULT; + + if ((uiSectorSize < MIN_SECTOR_SIZE) || + (uiSectorSize > MAX_SECTOR_SIZE)) { + if (copy_to_user(IoBuffer.OutputBuffer, + &Adapter->uiSectorSize, sizeof(UINT))) + return -EFAULT; + } else { + if (IsFlash2x(Adapter)) { + if (copy_to_user(IoBuffer.OutputBuffer, + &Adapter->uiSectorSize, sizeof(UINT))) + return -EFAULT; + } else { + if ((TRUE == Adapter->bShutStatus) || + (TRUE == Adapter->IdleMode)) { + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_PRINTK, 0, 0, + "Device is in Idle/Shutdown Mode\n"); + return -EACCES; + } + + Adapter->uiSectorSize = uiSectorSize; + BcmUpdateSectorSize(Adapter, + Adapter->uiSectorSize); + } + } + Status = STATUS_SUCCESS; + } else { + Status = STATUS_FAILURE; + } + return Status; +} + +static int bcm_char_ioctl_set_debug(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ +#ifdef DEBUG + struct bcm_ioctl_buffer IoBuffer; + struct bcm_user_debug_state sUserDebugState; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "In SET_DEBUG ioctl\n"); + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (copy_from_user(&sUserDebugState, IoBuffer.InputBuffer, + sizeof(struct bcm_user_debug_state))) + return -EFAULT; + + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, + "IOCTL_BCM_SET_DEBUG: OnOff=%d Type = 0x%x ", + sUserDebugState.OnOff, sUserDebugState.Type); + /* sUserDebugState.Subtype <<= 1; */ + sUserDebugState.Subtype = 1 << sUserDebugState.Subtype; + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, + "actual Subtype=0x%x\n", sUserDebugState.Subtype); + + /* Update new 'DebugState' in the Adapter */ + Adapter->stDebugState.type |= sUserDebugState.Type; + /* Subtype: A bitmap of 32 bits for Subtype per Type. + * Valid indexes in 'subtype' array: 1,2,4,8 + * corresponding to valid Type values. Hence we can use the 'Type' field + * as the index value, ignoring the array entries 0,3,5,6,7 ! + */ + if (sUserDebugState.OnOff) + Adapter->stDebugState.subtype[sUserDebugState.Type] |= + sUserDebugState.Subtype; + else + Adapter->stDebugState.subtype[sUserDebugState.Type] &= + ~sUserDebugState.Subtype; + + BCM_SHOW_DEBUG_BITMAP(Adapter); +#endif + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_nvm_rw(void __user *argp, + struct bcm_mini_adapter *Adapter, UINT cmd) +{ + struct bcm_nvm_readwrite stNVMReadWrite; + struct timeval tv0, tv1; + struct bcm_ioctl_buffer IoBuffer; + PUCHAR pReadData = NULL; + ULONG ulDSDMagicNumInUsrBuff = 0; + INT Status = STATUS_FAILURE; + + memset(&tv0, 0, sizeof(struct timeval)); + memset(&tv1, 0, sizeof(struct timeval)); + if ((Adapter->eNVMType == NVM_FLASH) && + (Adapter->uiFlashLayoutMajorVersion == 0)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "The Flash Control Section is Corrupted. Hence Rejection on NVM Read/Write\n"); + return -EFAULT; + } + + if (IsFlash2x(Adapter)) { + if ((Adapter->eActiveDSD != DSD0) && + (Adapter->eActiveDSD != DSD1) && + (Adapter->eActiveDSD != DSD2)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "No DSD is active..hence NVM Command is blocked"); + return STATUS_FAILURE; + } + } + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (copy_from_user(&stNVMReadWrite, + (IOCTL_BCM_NVM_READ == cmd) ? + IoBuffer.OutputBuffer : IoBuffer.InputBuffer, + sizeof(struct bcm_nvm_readwrite))) + return -EFAULT; + + /* + * Deny the access if the offset crosses the cal area limit. + */ + if (stNVMReadWrite.uiNumBytes > Adapter->uiNVMDSDSize) + return STATUS_FAILURE; + + if (stNVMReadWrite.uiOffset > + Adapter->uiNVMDSDSize - stNVMReadWrite.uiNumBytes) + return STATUS_FAILURE; + + pReadData = memdup_user(stNVMReadWrite.pBuffer, + stNVMReadWrite.uiNumBytes); + if (IS_ERR(pReadData)) + return PTR_ERR(pReadData); + + do_gettimeofday(&tv0); + if (IOCTL_BCM_NVM_READ == cmd) { + down(&Adapter->NVMRdmWrmLock); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Device is in Idle/Shutdown Mode\n"); + up(&Adapter->NVMRdmWrmLock); + kfree(pReadData); + return -EACCES; + } + + Status = BeceemNVMRead(Adapter, (PUINT)pReadData, + stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes); + up(&Adapter->NVMRdmWrmLock); + + if (Status != STATUS_SUCCESS) { + kfree(pReadData); + return Status; + } + + if (copy_to_user(stNVMReadWrite.pBuffer, pReadData, + stNVMReadWrite.uiNumBytes)) { + kfree(pReadData); + return -EFAULT; + } + } else { + down(&Adapter->NVMRdmWrmLock); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Device is in Idle/Shutdown Mode\n"); + up(&Adapter->NVMRdmWrmLock); + kfree(pReadData); + return -EACCES; + } + + Adapter->bHeaderChangeAllowed = TRUE; + if (IsFlash2x(Adapter)) { + /* + * New Requirement:- + * DSD section updation will be allowed in two case:- + * 1. if DSD sig is present in DSD header means dongle + * is ok and updation is fruitfull + * 2. if point 1 failes then user buff should have + * DSD sig. this point ensures that if dongle is + * corrupted then user space program first modify + * the DSD header with valid DSD sig so that this + * as well as further write may be worthwhile. + * + * This restriction has been put assuming that + * if DSD sig is corrupted, DSD data won't be + * considered valid. + */ + + Status = BcmFlash2xCorruptSig(Adapter, + Adapter->eActiveDSD); + if (Status != STATUS_SUCCESS) { + if (((stNVMReadWrite.uiOffset + stNVMReadWrite.uiNumBytes) != + Adapter->uiNVMDSDSize) || + (stNVMReadWrite.uiNumBytes < SIGNATURE_SIZE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + OSAL_DBG, DBG_LVL_ALL, + "DSD Sig is present neither in Flash nor User provided Input.."); + up(&Adapter->NVMRdmWrmLock); + kfree(pReadData); + return Status; + } + + ulDSDMagicNumInUsrBuff = ntohl(*(PUINT)(pReadData + stNVMReadWrite.uiNumBytes - SIGNATURE_SIZE)); + if (ulDSDMagicNumInUsrBuff != + DSD_IMAGE_MAGIC_NUMBER) { + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "DSD Sig is present neither in Flash nor User provided Input.."); + up(&Adapter->NVMRdmWrmLock); + kfree(pReadData); + return Status; + } + } + } + + Status = BeceemNVMWrite(Adapter, (PUINT)pReadData, + stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes, + stNVMReadWrite.bVerify); + if (IsFlash2x(Adapter)) + BcmFlash2xWriteSig(Adapter, Adapter->eActiveDSD); + + Adapter->bHeaderChangeAllowed = false; + + up(&Adapter->NVMRdmWrmLock); + + if (Status != STATUS_SUCCESS) { + kfree(pReadData); + return Status; + } + } + + do_gettimeofday(&tv1); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + " timetaken by Write/read :%ld msec\n", + (tv1.tv_sec - tv0.tv_sec)*1000 + (tv1.tv_usec - tv0.tv_usec)/1000); + + kfree(pReadData); + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_flash2x_section_read(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_flash2x_readwrite sFlash2xRead = {0}; + struct bcm_ioctl_buffer IoBuffer; + PUCHAR pReadBuff = NULL; + UINT NOB = 0; + UINT BuffSize = 0; + UINT ReadBytes = 0; + UINT ReadOffset = 0; + INT Status = STATUS_FAILURE; + void __user *OutPutBuff; + + if (IsFlash2x(Adapter) != TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Flash Does not have 2.x map"); + return -EINVAL; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, "IOCTL_BCM_FLASH2X_SECTION_READ Called"); + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + /* Reading FLASH 2.x READ structure */ + if (copy_from_user(&sFlash2xRead, IoBuffer.InputBuffer, + sizeof(struct bcm_flash2x_readwrite))) + return -EFAULT; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\nsFlash2xRead.Section :%x", sFlash2xRead.Section); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\nsFlash2xRead.offset :%x", sFlash2xRead.offset); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\nsFlash2xRead.numOfBytes :%x", sFlash2xRead.numOfBytes); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\nsFlash2xRead.bVerify :%x\n", sFlash2xRead.bVerify); + + /* This was internal to driver for raw read. + * now it has ben exposed to user space app. + */ + if (validateFlash2xReadWrite(Adapter, &sFlash2xRead) == false) + return STATUS_FAILURE; + + NOB = sFlash2xRead.numOfBytes; + if (NOB > Adapter->uiSectorSize) + BuffSize = Adapter->uiSectorSize; + else + BuffSize = NOB; + + ReadOffset = sFlash2xRead.offset; + OutPutBuff = IoBuffer.OutputBuffer; + pReadBuff = (PCHAR)kzalloc(BuffSize , GFP_KERNEL); + + if (pReadBuff == NULL) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Memory allocation failed for Flash 2.x Read Structure"); + return -ENOMEM; + } + down(&Adapter->NVMRdmWrmLock); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n"); + up(&Adapter->NVMRdmWrmLock); + kfree(pReadBuff); + return -EACCES; + } + + while (NOB) { + if (NOB > Adapter->uiSectorSize) + ReadBytes = Adapter->uiSectorSize; + else + ReadBytes = NOB; + + /* Reading the data from Flash 2.x */ + Status = BcmFlash2xBulkRead(Adapter, (PUINT)pReadBuff, + sFlash2xRead.Section, ReadOffset, ReadBytes); + if (Status) { + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Flash 2x read err with Status :%d", + Status); + break; + } + + BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, pReadBuff, ReadBytes); + + Status = copy_to_user(OutPutBuff, pReadBuff, ReadBytes); + if (Status) { + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Copy to use failed with status :%d", Status); + up(&Adapter->NVMRdmWrmLock); + kfree(pReadBuff); + return -EFAULT; + } + NOB = NOB - ReadBytes; + if (NOB) { + ReadOffset = ReadOffset + ReadBytes; + OutPutBuff = OutPutBuff + ReadBytes; + } + } + + up(&Adapter->NVMRdmWrmLock); + kfree(pReadBuff); + return Status; +} + +static int bcm_char_ioctl_flash2x_section_write(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_flash2x_readwrite sFlash2xWrite = {0}; + struct bcm_ioctl_buffer IoBuffer; + PUCHAR pWriteBuff; + void __user *InputAddr; + UINT NOB = 0; + UINT BuffSize = 0; + UINT WriteOffset = 0; + UINT WriteBytes = 0; + INT Status = STATUS_FAILURE; + + if (IsFlash2x(Adapter) != TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Flash Does not have 2.x map"); + return -EINVAL; + } + + /* First make this False so that we can enable the Sector + * Permission Check in BeceemFlashBulkWrite + */ + Adapter->bAllDSDWriteAllow = false; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_FLASH2X_SECTION_WRITE Called"); + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + /* Reading FLASH 2.x READ structure */ + if (copy_from_user(&sFlash2xWrite, IoBuffer.InputBuffer, + sizeof(struct bcm_flash2x_readwrite))) + return -EFAULT; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\nsFlash2xRead.Section :%x", sFlash2xWrite.Section); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\nsFlash2xRead.offset :%d", sFlash2xWrite.offset); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\nsFlash2xRead.numOfBytes :%x", sFlash2xWrite.numOfBytes); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\nsFlash2xRead.bVerify :%x\n", sFlash2xWrite.bVerify); + + if ((sFlash2xWrite.Section != VSA0) && (sFlash2xWrite.Section != VSA1) + && (sFlash2xWrite.Section != VSA2)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Only VSA write is allowed"); + return -EINVAL; + } + + if (validateFlash2xReadWrite(Adapter, &sFlash2xWrite) == false) + return STATUS_FAILURE; + + InputAddr = sFlash2xWrite.pDataBuff; + WriteOffset = sFlash2xWrite.offset; + NOB = sFlash2xWrite.numOfBytes; + + if (NOB > Adapter->uiSectorSize) + BuffSize = Adapter->uiSectorSize; + else + BuffSize = NOB; + + pWriteBuff = kmalloc(BuffSize, GFP_KERNEL); + + if (pWriteBuff == NULL) + return -ENOMEM; + + /* extracting the remainder of the given offset. */ + WriteBytes = Adapter->uiSectorSize; + if (WriteOffset % Adapter->uiSectorSize) + WriteBytes = Adapter->uiSectorSize - (WriteOffset % Adapter->uiSectorSize); + + if (NOB < WriteBytes) + WriteBytes = NOB; + + down(&Adapter->NVMRdmWrmLock); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Device is in Idle/Shutdown Mode\n"); + up(&Adapter->NVMRdmWrmLock); + kfree(pWriteBuff); + return -EACCES; + } + + BcmFlash2xCorruptSig(Adapter, sFlash2xWrite.Section); + do { + Status = copy_from_user(pWriteBuff, InputAddr, WriteBytes); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy to user failed with status :%d", Status); + up(&Adapter->NVMRdmWrmLock); + kfree(pWriteBuff); + return -EFAULT; + } + BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, + OSAL_DBG, DBG_LVL_ALL, pWriteBuff, WriteBytes); + + /* Writing the data from Flash 2.x */ + Status = BcmFlash2xBulkWrite(Adapter, (PUINT)pWriteBuff, + sFlash2xWrite.Section, WriteOffset, WriteBytes, + sFlash2xWrite.bVerify); + + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Flash 2x read err with Status :%d", Status); + break; + } + + NOB = NOB - WriteBytes; + if (NOB) { + WriteOffset = WriteOffset + WriteBytes; + InputAddr = InputAddr + WriteBytes; + if (NOB > Adapter->uiSectorSize) + WriteBytes = Adapter->uiSectorSize; + else + WriteBytes = NOB; + } + } while (NOB > 0); + + BcmFlash2xWriteSig(Adapter, sFlash2xWrite.Section); + up(&Adapter->NVMRdmWrmLock); + kfree(pWriteBuff); + return Status; +} + +static int bcm_char_ioctl_flash2x_section_bitmap(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_flash2x_bitmap *psFlash2xBitMap; + struct bcm_ioctl_buffer IoBuffer; + INT Status = STATUS_FAILURE; + +BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP Called"); + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.OutputLength != sizeof(struct bcm_flash2x_bitmap)) + return -EINVAL; + + psFlash2xBitMap = kzalloc(sizeof(struct bcm_flash2x_bitmap), GFP_KERNEL); + if (psFlash2xBitMap == NULL) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Memory is not available"); + return -ENOMEM; + } + + /* Reading the Flash Sectio Bit map */ + down(&Adapter->NVMRdmWrmLock); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Device is in Idle/Shutdown Mode\n"); + up(&Adapter->NVMRdmWrmLock); + kfree(psFlash2xBitMap); + return -EACCES; + } + + BcmGetFlash2xSectionalBitMap(Adapter, psFlash2xBitMap); + up(&Adapter->NVMRdmWrmLock); + if (copy_to_user(IoBuffer.OutputBuffer, psFlash2xBitMap, + sizeof(struct bcm_flash2x_bitmap))) { + kfree(psFlash2xBitMap); + return -EFAULT; + } + + kfree(psFlash2xBitMap); + return Status; +} + +static int bcm_char_ioctl_set_active_section(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + enum bcm_flash2x_section_val eFlash2xSectionVal = 0; + INT Status = STATUS_FAILURE; + struct bcm_ioctl_buffer IoBuffer; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_SET_ACTIVE_SECTION Called"); + + if (IsFlash2x(Adapter) != TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Flash Does not have 2.x map"); + return -EINVAL; + } + + Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy of IOCTL BUFFER failed"); + return -EFAULT; + } + + Status = copy_from_user(&eFlash2xSectionVal, + IoBuffer.InputBuffer, sizeof(INT)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy of flash section val failed"); + return -EFAULT; + } + + down(&Adapter->NVMRdmWrmLock); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Device is in Idle/Shutdown Mode\n"); + up(&Adapter->NVMRdmWrmLock); + return -EACCES; + } + + Status = BcmSetActiveSection(Adapter, eFlash2xSectionVal); + if (Status) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Failed to make it's priority Highest. Status %d", + Status); + + up(&Adapter->NVMRdmWrmLock); + + return Status; +} + +static int bcm_char_ioctl_copy_section(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_flash2x_copy_section sCopySectStrut = {0}; + struct bcm_ioctl_buffer IoBuffer; + INT Status = STATUS_SUCCESS; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_COPY_SECTION Called"); + + Adapter->bAllDSDWriteAllow = false; + if (IsFlash2x(Adapter) != TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Flash Does not have 2.x map"); + return -EINVAL; + } + + Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy of IOCTL BUFFER failed Status :%d", Status); + return -EFAULT; + } + + Status = copy_from_user(&sCopySectStrut, IoBuffer.InputBuffer, + sizeof(struct bcm_flash2x_copy_section)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy of Copy_Section_Struct failed with Status :%d", + Status); + return -EFAULT; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Source SEction :%x", sCopySectStrut.SrcSection); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Destination SEction :%x", sCopySectStrut.DstSection); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "offset :%x", sCopySectStrut.offset); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "NOB :%x", sCopySectStrut.numOfBytes); + + if (IsSectionExistInFlash(Adapter, sCopySectStrut.SrcSection) == false) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Source Section<%x> does not exist in Flash ", + sCopySectStrut.SrcSection); + return -EINVAL; + } + + if (IsSectionExistInFlash(Adapter, sCopySectStrut.DstSection) == false) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Destinatio Section<%x> does not exist in Flash ", + sCopySectStrut.DstSection); + return -EINVAL; + } + + if (sCopySectStrut.SrcSection == sCopySectStrut.DstSection) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Source and Destination section should be different"); + return -EINVAL; + } + + down(&Adapter->NVMRdmWrmLock); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Device is in Idle/Shutdown Mode\n"); + up(&Adapter->NVMRdmWrmLock); + return -EACCES; + } + + if (sCopySectStrut.SrcSection == ISO_IMAGE1 || + sCopySectStrut.SrcSection == ISO_IMAGE2) { + if (IsNonCDLessDevice(Adapter)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Device is Non-CDLess hence won't have ISO !!"); + Status = -EINVAL; + } else if (sCopySectStrut.numOfBytes == 0) { + Status = BcmCopyISO(Adapter, sCopySectStrut); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Partial Copy of ISO section is not Allowed.."); + Status = STATUS_FAILURE; + } + up(&Adapter->NVMRdmWrmLock); + return Status; + } + + Status = BcmCopySection(Adapter, sCopySectStrut.SrcSection, + sCopySectStrut.DstSection, + sCopySectStrut.offset, + sCopySectStrut.numOfBytes); + up(&Adapter->NVMRdmWrmLock); + return Status; +} + +static int bcm_char_ioctl_get_flash_cs_info(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_ioctl_buffer IoBuffer; + INT Status = STATUS_SUCCESS; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + " IOCTL_BCM_GET_FLASH_CS_INFO Called"); + + Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy of IOCTL BUFFER failed"); + return -EFAULT; + } + + if (Adapter->eNVMType != NVM_FLASH) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Connected device does not have flash"); + return -EINVAL; + } + + if (IsFlash2x(Adapter) == TRUE) { + if (IoBuffer.OutputLength < sizeof(struct bcm_flash2x_cs_info)) + return -EINVAL; + + if (copy_to_user(IoBuffer.OutputBuffer, + Adapter->psFlash2xCSInfo, + sizeof(struct bcm_flash2x_cs_info))) + return -EFAULT; + } else { + if (IoBuffer.OutputLength < sizeof(struct bcm_flash_cs_info)) + return -EINVAL; + + if (copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlashCSInfo, + sizeof(struct bcm_flash_cs_info))) + return -EFAULT; + } + return Status; +} + +static int bcm_char_ioctl_select_dsd(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_ioctl_buffer IoBuffer; + INT Status = STATUS_FAILURE; + UINT SectOfset = 0; + enum bcm_flash2x_section_val eFlash2xSectionVal; + + eFlash2xSectionVal = NO_SECTION_VAL; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_SELECT_DSD Called"); + + if (IsFlash2x(Adapter) != TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Flash Does not have 2.x map"); + return -EINVAL; + } + + Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy of IOCTL BUFFER failed"); + return -EFAULT; + } + Status = copy_from_user(&eFlash2xSectionVal, IoBuffer.InputBuffer, + sizeof(INT)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy of flash section val failed"); + return -EFAULT; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Read Section :%d", eFlash2xSectionVal); + if ((eFlash2xSectionVal != DSD0) && + (eFlash2xSectionVal != DSD1) && + (eFlash2xSectionVal != DSD2)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Passed section<%x> is not DSD section", + eFlash2xSectionVal); + return STATUS_FAILURE; + } + + SectOfset = BcmGetSectionValStartOffset(Adapter, eFlash2xSectionVal); + if (SectOfset == INVALID_OFFSET) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Provided Section val <%d> does not exist in Flash 2.x", + eFlash2xSectionVal); + return -EINVAL; + } + + Adapter->bAllDSDWriteAllow = TRUE; + Adapter->ulFlashCalStart = SectOfset; + Adapter->eActiveDSD = eFlash2xSectionVal; + + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_nvm_raw_read(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_nvm_readwrite stNVMRead; + struct bcm_ioctl_buffer IoBuffer; + unsigned int NOB; + INT BuffSize; + INT ReadOffset = 0; + UINT ReadBytes = 0; + PUCHAR pReadBuff; + void __user *OutPutBuff; + INT Status = STATUS_FAILURE; + + if (Adapter->eNVMType != NVM_FLASH) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "NVM TYPE is not Flash"); + return -EINVAL; + } + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "copy_from_user 1 failed\n"); + return -EFAULT; + } + + if (copy_from_user(&stNVMRead, IoBuffer.OutputBuffer, + sizeof(struct bcm_nvm_readwrite))) + return -EFAULT; + + NOB = stNVMRead.uiNumBytes; + /* In Raw-Read max Buff size : 64MB */ + + if (NOB > DEFAULT_BUFF_SIZE) + BuffSize = DEFAULT_BUFF_SIZE; + else + BuffSize = NOB; + + ReadOffset = stNVMRead.uiOffset; + OutPutBuff = stNVMRead.pBuffer; + + pReadBuff = kzalloc(BuffSize , GFP_KERNEL); + if (pReadBuff == NULL) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Memory allocation failed for Flash 2.x Read Structure"); + return -ENOMEM; + } + down(&Adapter->NVMRdmWrmLock); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n"); + kfree(pReadBuff); + up(&Adapter->NVMRdmWrmLock); + return -EACCES; + } + + Adapter->bFlashRawRead = TRUE; + + while (NOB) { + if (NOB > DEFAULT_BUFF_SIZE) + ReadBytes = DEFAULT_BUFF_SIZE; + else + ReadBytes = NOB; + + /* Reading the data from Flash 2.x */ + Status = BeceemNVMRead(Adapter, (PUINT)pReadBuff, + ReadOffset, ReadBytes); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Flash 2x read err with Status :%d", Status); + break; + } + + BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, pReadBuff, ReadBytes); + + Status = copy_to_user(OutPutBuff, pReadBuff, ReadBytes); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy to use failed with status :%d", Status); + up(&Adapter->NVMRdmWrmLock); + kfree(pReadBuff); + return -EFAULT; + } + NOB = NOB - ReadBytes; + if (NOB) { + ReadOffset = ReadOffset + ReadBytes; + OutPutBuff = OutPutBuff + ReadBytes; + } + } + Adapter->bFlashRawRead = false; + up(&Adapter->NVMRdmWrmLock); + kfree(pReadBuff); + return Status; +} + +static int bcm_char_ioctl_cntrlmsg_mask(void __user *argp, + struct bcm_mini_adapter *Adapter, struct bcm_tarang_data *pTarang) +{ + struct bcm_ioctl_buffer IoBuffer; + INT Status = STATUS_FAILURE; + ULONG RxCntrlMsgBitMask = 0; + + /* Copy Ioctl Buffer structure */ + Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "copy of Ioctl buffer is failed from user space"); + return -EFAULT; + } + + if (IoBuffer.InputLength != sizeof(unsigned long)) + return -EINVAL; + + Status = copy_from_user(&RxCntrlMsgBitMask, + IoBuffer.InputBuffer, IoBuffer.InputLength); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "copy of control bit mask failed from user space"); + return -EFAULT; + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\n Got user defined cntrl msg bit mask :%lx", + RxCntrlMsgBitMask); + pTarang->RxCntrlMsgBitMask = RxCntrlMsgBitMask; + + return Status; +} + +static int bcm_char_ioctl_get_device_driver_info(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_driver_info DevInfo; + struct bcm_ioctl_buffer IoBuffer; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, "Called IOCTL_BCM_GET_DEVICE_DRIVER_INFO\n"); + + memset(&DevInfo, 0, sizeof(DevInfo)); + DevInfo.MaxRDMBufferSize = BUFFER_4K; + DevInfo.u32DSDStartOffset = EEPROM_CALPARAM_START; + DevInfo.u32RxAlignmentCorrection = 0; + DevInfo.u32NVMType = Adapter->eNVMType; + DevInfo.u32InterfaceType = BCM_USB; + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.OutputLength < sizeof(DevInfo)) + return -EINVAL; + + if (copy_to_user(IoBuffer.OutputBuffer, &DevInfo, sizeof(DevInfo))) + return -EFAULT; + + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_time_since_net_entry(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_time_elapsed stTimeElapsedSinceNetEntry = {0}; + struct bcm_ioctl_buffer IoBuffer; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_TIME_SINCE_NET_ENTRY called"); + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.OutputLength < sizeof(struct bcm_time_elapsed)) + return -EINVAL; + + stTimeElapsedSinceNetEntry.ul64TimeElapsedSinceNetEntry = + get_seconds() - Adapter->liTimeSinceLastNetEntry; + + if (copy_to_user(IoBuffer.OutputBuffer, &stTimeElapsedSinceNetEntry, + sizeof(struct bcm_time_elapsed))) + return -EFAULT; + + return STATUS_SUCCESS; +} + + static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) { struct bcm_tarang_data *pTarang = filp->private_data; void __user *argp = (void __user *)arg; struct bcm_mini_adapter *Adapter = pTarang->Adapter; INT Status = STATUS_FAILURE; - int timeout = 0; - struct bcm_ioctl_buffer IoBuffer; - int bytes; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Parameters Passed to control IOCTL cmd=0x%X arg=0x%lX", @@ -201,778 +2332,65 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) switch (cmd) { /* Rdms for Swin Idle... */ - case IOCTL_BCM_REGISTER_READ_PRIVATE: { - struct bcm_rdm_buffer sRdmBuffer = {0}; - PCHAR temp_buff; - UINT Bufflen; - u16 temp_value; + case IOCTL_BCM_REGISTER_READ_PRIVATE: + Status = bcm_char_ioctl_reg_read_private(argp, Adapter); + return Status; - /* Copy Ioctl Buffer structure */ - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (IoBuffer.InputLength > sizeof(sRdmBuffer)) - return -EINVAL; - - if (copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) - return -EFAULT; - - if (IoBuffer.OutputLength > USHRT_MAX || - IoBuffer.OutputLength == 0) { - return -EINVAL; - } - - Bufflen = IoBuffer.OutputLength; - temp_value = 4 - (Bufflen % 4); - Bufflen += temp_value % 4; - - temp_buff = kmalloc(Bufflen, GFP_KERNEL); - if (!temp_buff) - return -ENOMEM; - - bytes = rdmalt(Adapter, (UINT)sRdmBuffer.Register, - (PUINT)temp_buff, Bufflen); - if (bytes > 0) { - Status = STATUS_SUCCESS; - if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, bytes)) { - kfree(temp_buff); - return -EFAULT; - } - } else { - Status = bytes; - } - - kfree(temp_buff); - break; - } - - case IOCTL_BCM_REGISTER_WRITE_PRIVATE: { - struct bcm_wrm_buffer sWrmBuffer = {0}; - UINT uiTempVar = 0; - /* Copy Ioctl Buffer structure */ - - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (IoBuffer.InputLength > sizeof(sWrmBuffer)) - return -EINVAL; - - /* Get WrmBuffer structure */ - if (copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) - return -EFAULT; - - uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK; - if (!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) && - ((uiTempVar == EEPROM_REJECT_REG_1) || - (uiTempVar == EEPROM_REJECT_REG_2) || - (uiTempVar == EEPROM_REJECT_REG_3) || - (uiTempVar == EEPROM_REJECT_REG_4))) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "EEPROM Access Denied, not in VSG Mode\n"); - return -EFAULT; - } - - Status = wrmalt(Adapter, (UINT)sWrmBuffer.Register, - (PUINT)sWrmBuffer.Data, sizeof(ULONG)); - - if (Status == STATUS_SUCCESS) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, - DBG_LVL_ALL, "WRM Done\n"); - } else { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, - DBG_LVL_ALL, "WRM Failed\n"); - Status = -EFAULT; - } - break; - } + case IOCTL_BCM_REGISTER_WRITE_PRIVATE: + Status = bcm_char_ioctl_reg_write_private(argp, Adapter); + return Status; case IOCTL_BCM_REGISTER_READ: - case IOCTL_BCM_EEPROM_REGISTER_READ: { - struct bcm_rdm_buffer sRdmBuffer = {0}; - PCHAR temp_buff = NULL; - UINT uiTempVar = 0; - if ((Adapter->IdleMode == TRUE) || - (Adapter->bShutStatus == TRUE) || - (Adapter->bPreparingForLowPowerMode == TRUE)) { + case IOCTL_BCM_EEPROM_REGISTER_READ: + Status = bcm_char_ioctl_eeprom_reg_read(argp, Adapter); + return Status; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "Device in Idle Mode, Blocking Rdms\n"); - return -EACCES; - } - - /* Copy Ioctl Buffer structure */ - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (IoBuffer.InputLength > sizeof(sRdmBuffer)) - return -EINVAL; - - if (copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) - return -EFAULT; - - if (IoBuffer.OutputLength > USHRT_MAX || - IoBuffer.OutputLength == 0) { - return -EINVAL; - } - - temp_buff = kmalloc(IoBuffer.OutputLength, GFP_KERNEL); - if (!temp_buff) - return STATUS_FAILURE; - - if ((((ULONG)sRdmBuffer.Register & 0x0F000000) != 0x0F000000) || - ((ULONG)sRdmBuffer.Register & 0x3)) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "RDM Done On invalid Address : %x Access Denied.\n", - (int)sRdmBuffer.Register); - - kfree(temp_buff); - return -EINVAL; - } - - uiTempVar = sRdmBuffer.Register & EEPROM_REJECT_MASK; - bytes = rdmaltWithLock(Adapter, (UINT)sRdmBuffer.Register, - (PUINT)temp_buff, IoBuffer.OutputLength); - - if (bytes > 0) { - Status = STATUS_SUCCESS; - if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, bytes)) { - kfree(temp_buff); - return -EFAULT; - } - } else { - Status = bytes; - } - - kfree(temp_buff); - break; - } case IOCTL_BCM_REGISTER_WRITE: - case IOCTL_BCM_EEPROM_REGISTER_WRITE: { - struct bcm_wrm_buffer sWrmBuffer = {0}; - UINT uiTempVar = 0; + case IOCTL_BCM_EEPROM_REGISTER_WRITE: + Status = bcm_char_ioctl_eeprom_reg_write(argp, Adapter, cmd); + return Status; - if ((Adapter->IdleMode == TRUE) || - (Adapter->bShutStatus == TRUE) || - (Adapter->bPreparingForLowPowerMode == TRUE)) { + case IOCTL_BCM_GPIO_SET_REQUEST: + Status = bcm_char_ioctl_gpio_set_request(argp, Adapter); + return Status; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "Device in Idle Mode, Blocking Wrms\n"); - return -EACCES; - } + case BCM_LED_THREAD_STATE_CHANGE_REQ: + Status = bcm_char_ioctl_led_thread_state_change_req(argp, Adapter); + return Status; - /* Copy Ioctl Buffer structure */ - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; + case IOCTL_BCM_GPIO_STATUS_REQUEST: + Status = bcm_char_ioctl_gpio_status_request(argp, Adapter); + return Status; - if (IoBuffer.InputLength > sizeof(sWrmBuffer)) - return -EINVAL; + case IOCTL_BCM_GPIO_MULTI_REQUEST: + Status = bcm_char_ioctl_gpio_multi_request(argp, Adapter); + return Status; - /* Get WrmBuffer structure */ - if (copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) - return -EFAULT; - - if ((((ULONG)sWrmBuffer.Register & 0x0F000000) != 0x0F000000) || - ((ULONG)sWrmBuffer.Register & 0x3)) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "WRM Done On invalid Address : %x Access Denied.\n", - (int)sWrmBuffer.Register); - return -EINVAL; - } - - uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK; - if (!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) && - ((uiTempVar == EEPROM_REJECT_REG_1) || - (uiTempVar == EEPROM_REJECT_REG_2) || - (uiTempVar == EEPROM_REJECT_REG_3) || - (uiTempVar == EEPROM_REJECT_REG_4)) && - (cmd == IOCTL_BCM_REGISTER_WRITE)) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "EEPROM Access Denied, not in VSG Mode\n"); - return -EFAULT; - } - - Status = wrmaltWithLock(Adapter, (UINT)sWrmBuffer.Register, - (PUINT)sWrmBuffer.Data, - sWrmBuffer.Length); - - if (Status == STATUS_SUCCESS) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, OSAL_DBG, - DBG_LVL_ALL, "WRM Done\n"); - } else { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, - DBG_LVL_ALL, "WRM Failed\n"); - Status = -EFAULT; - } - break; - } - case IOCTL_BCM_GPIO_SET_REQUEST: { - UCHAR ucResetValue[4]; - UINT value = 0; - UINT uiBit = 0; - UINT uiOperation = 0; - struct bcm_gpio_info gpio_info = {0}; - - if ((Adapter->IdleMode == TRUE) || - (Adapter->bShutStatus == TRUE) || - (Adapter->bPreparingForLowPowerMode == TRUE)) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, - DBG_LVL_ALL, - "GPIO Can't be set/clear in Low power Mode"); - return -EACCES; - } - - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (IoBuffer.InputLength > sizeof(gpio_info)) - return -EINVAL; - - if (copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength)) - return -EFAULT; - - uiBit = gpio_info.uiGpioNumber; - uiOperation = gpio_info.uiGpioValue; - value = (1< is not correspond to LED !!!", - value); - Status = -EINVAL; - break; - } - - /* Set - setting 1 */ - if (uiOperation) { - /* Set the gpio output register */ - Status = wrmaltWithLock(Adapter, - BCM_GPIO_OUTPUT_SET_REG, - (PUINT)(&value), sizeof(UINT)); - - if (Status == STATUS_SUCCESS) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, - OSAL_DBG, DBG_LVL_ALL, - "Set the GPIO bit\n"); - } else { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, - OSAL_DBG, DBG_LVL_ALL, - "Failed to set the %dth GPIO\n", - uiBit); - break; - } - } else { - /* Set the gpio output register */ - Status = wrmaltWithLock(Adapter, - BCM_GPIO_OUTPUT_CLR_REG, - (PUINT)(&value), sizeof(UINT)); - - if (Status == STATUS_SUCCESS) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, - OSAL_DBG, DBG_LVL_ALL, - "Set the GPIO bit\n"); - } else { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, - OSAL_DBG, DBG_LVL_ALL, - "Failed to clear the %dth GPIO\n", - uiBit); - break; - } - } - - bytes = rdmaltWithLock(Adapter, (UINT)GPIO_MODE_REGISTER, - (PUINT)ucResetValue, sizeof(UINT)); - if (bytes < 0) { - Status = bytes; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, - "GPIO_MODE_REGISTER read failed"); - break; - } else { - Status = STATUS_SUCCESS; - } - - /* Set the gpio mode register to output */ - *(UINT *)ucResetValue |= (1<IdleMode == TRUE) || - (Adapter->bShutStatus == TRUE) || - (Adapter->bPreparingForLowPowerMode == TRUE)) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, - DBG_LVL_ALL, - "GPIO Can't be set/clear in Low power Mode"); - Status = -EACCES; - break; - } - - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (IoBuffer.InputLength > sizeof(threadReq)) - return -EINVAL; - - if (copy_from_user(&threadReq, IoBuffer.InputBuffer, IoBuffer.InputLength)) - return -EFAULT; - - /* if LED thread is running(Actively or Inactively) set it state to make inactive */ - if (Adapter->LEDInfo.led_thread_running) { - if (threadReq.ThreadState == LED_THREAD_ACTIVATION_REQ) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, - OSAL_DBG, DBG_LVL_ALL, - "Activating thread req"); - Adapter->DriverState = LED_THREAD_ACTIVE; - } else { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, - OSAL_DBG, DBG_LVL_ALL, - "DeActivating Thread req....."); - Adapter->DriverState = LED_THREAD_INACTIVE; - } - - /* signal thread. */ - wake_up(&Adapter->LEDInfo.notify_led_event); - } - } - break; - - case IOCTL_BCM_GPIO_STATUS_REQUEST: { - ULONG uiBit = 0; - UCHAR ucRead[4]; - struct bcm_gpio_info gpio_info = {0}; - - if ((Adapter->IdleMode == TRUE) || - (Adapter->bShutStatus == TRUE) || - (Adapter->bPreparingForLowPowerMode == TRUE)) - return -EACCES; - - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (IoBuffer.InputLength > sizeof(gpio_info)) - return -EINVAL; - - if (copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength)) - return -EFAULT; - - uiBit = gpio_info.uiGpioNumber; - - /* Set the gpio output register */ - bytes = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER, - (PUINT)ucRead, sizeof(UINT)); - - if (bytes < 0) { - Status = bytes; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "RDM Failed\n"); - return Status; - } else { - Status = STATUS_SUCCESS; - } - } - break; - - case IOCTL_BCM_GPIO_MULTI_REQUEST: { - UCHAR ucResetValue[4]; - struct bcm_gpio_multi_info gpio_multi_info[MAX_IDX]; - struct bcm_gpio_multi_info *pgpio_multi_info = (struct bcm_gpio_multi_info *)gpio_multi_info; - - memset(pgpio_multi_info, 0, MAX_IDX * sizeof(struct bcm_gpio_multi_info)); - - if ((Adapter->IdleMode == TRUE) || - (Adapter->bShutStatus == TRUE) || - (Adapter->bPreparingForLowPowerMode == TRUE)) - return -EINVAL; - - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (IoBuffer.InputLength > sizeof(gpio_multi_info)) - return -EINVAL; - - if (copy_from_user(&gpio_multi_info, IoBuffer.InputBuffer, IoBuffer.InputLength)) - return -EFAULT; - - if (IsReqGpioIsLedInNVM(Adapter, pgpio_multi_info[WIMAX_IDX].uiGPIOMask) == false) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, - DBG_LVL_ALL, - "Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!", - pgpio_multi_info[WIMAX_IDX].uiGPIOMask, - Adapter->gpioBitMap); - Status = -EINVAL; - break; - } - - /* Set the gpio output register */ - if ((pgpio_multi_info[WIMAX_IDX].uiGPIOMask) & - (pgpio_multi_info[WIMAX_IDX].uiGPIOCommand)) { - /* Set 1's in GPIO OUTPUT REGISTER */ - *(UINT *)ucResetValue = pgpio_multi_info[WIMAX_IDX].uiGPIOMask & - pgpio_multi_info[WIMAX_IDX].uiGPIOCommand & - pgpio_multi_info[WIMAX_IDX].uiGPIOValue; - - if (*(UINT *) ucResetValue) - Status = wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_SET_REG, - (PUINT)ucResetValue, sizeof(ULONG)); - - if (Status != STATUS_SUCCESS) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "WRM to BCM_GPIO_OUTPUT_SET_REG Failed."); - return Status; - } - - /* Clear to 0's in GPIO OUTPUT REGISTER */ - *(UINT *)ucResetValue = (pgpio_multi_info[WIMAX_IDX].uiGPIOMask & - pgpio_multi_info[WIMAX_IDX].uiGPIOCommand & - (~(pgpio_multi_info[WIMAX_IDX].uiGPIOValue))); - - if (*(UINT *) ucResetValue) - Status = wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_CLR_REG, (PUINT)ucResetValue, sizeof(ULONG)); - - if (Status != STATUS_SUCCESS) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "WRM to BCM_GPIO_OUTPUT_CLR_REG Failed."); - return Status; - } - } - - if (pgpio_multi_info[WIMAX_IDX].uiGPIOMask) { - bytes = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER, (PUINT)ucResetValue, sizeof(UINT)); - - if (bytes < 0) { - Status = bytes; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "RDM to GPIO_PIN_STATE_REGISTER Failed."); - return Status; - } else { - Status = STATUS_SUCCESS; - } - - pgpio_multi_info[WIMAX_IDX].uiGPIOValue = (*(UINT *)ucResetValue & - pgpio_multi_info[WIMAX_IDX].uiGPIOMask); - } - - Status = copy_to_user(IoBuffer.OutputBuffer, &gpio_multi_info, IoBuffer.OutputLength); - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "Failed while copying Content to IOBufer for user space err:%d", Status); - return -EFAULT; - } - } - break; - - case IOCTL_BCM_GPIO_MODE_REQUEST: { - UCHAR ucResetValue[4]; - struct bcm_gpio_multi_mode gpio_multi_mode[MAX_IDX]; - struct bcm_gpio_multi_mode *pgpio_multi_mode = (struct bcm_gpio_multi_mode *)gpio_multi_mode; - - if ((Adapter->IdleMode == TRUE) || - (Adapter->bShutStatus == TRUE) || - (Adapter->bPreparingForLowPowerMode == TRUE)) - return -EINVAL; - - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (IoBuffer.InputLength > sizeof(gpio_multi_mode)) - return -EINVAL; - - if (copy_from_user(&gpio_multi_mode, IoBuffer.InputBuffer, IoBuffer.InputLength)) - return -EFAULT; - - bytes = rdmaltWithLock(Adapter, (UINT)GPIO_MODE_REGISTER, (PUINT)ucResetValue, sizeof(UINT)); - - if (bytes < 0) { - Status = bytes; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Read of GPIO_MODE_REGISTER failed"); - return Status; - } else { - Status = STATUS_SUCCESS; - } - - /* Validating the request */ - if (IsReqGpioIsLedInNVM(Adapter, pgpio_multi_mode[WIMAX_IDX].uiGPIOMask) == false) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, - "Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!", - pgpio_multi_mode[WIMAX_IDX].uiGPIOMask, Adapter->gpioBitMap); - Status = -EINVAL; - break; - } - - if (pgpio_multi_mode[WIMAX_IDX].uiGPIOMask) { - /* write all OUT's (1's) */ - *(UINT *) ucResetValue |= (pgpio_multi_mode[WIMAX_IDX].uiGPIOMode & - pgpio_multi_mode[WIMAX_IDX].uiGPIOMask); - - /* write all IN's (0's) */ - *(UINT *) ucResetValue &= ~((~pgpio_multi_mode[WIMAX_IDX].uiGPIOMode) & - pgpio_multi_mode[WIMAX_IDX].uiGPIOMask); - - /* Currently implemented return the modes of all GPIO's - * else needs to bit AND with mask - */ - pgpio_multi_mode[WIMAX_IDX].uiGPIOMode = *(UINT *)ucResetValue; - - Status = wrmaltWithLock(Adapter, GPIO_MODE_REGISTER, (PUINT)ucResetValue, sizeof(ULONG)); - if (Status == STATUS_SUCCESS) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, - "WRM to GPIO_MODE_REGISTER Done"); - } else { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "WRM to GPIO_MODE_REGISTER Failed"); - Status = -EFAULT; - break; - } - } else { -/* if uiGPIOMask is 0 then return mode register configuration */ - pgpio_multi_mode[WIMAX_IDX].uiGPIOMode = *(UINT *)ucResetValue; - } - - Status = copy_to_user(IoBuffer.OutputBuffer, &gpio_multi_mode, IoBuffer.OutputLength); - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "Failed while copying Content to IOBufer for user space err:%d", Status); - return -EFAULT; - } - } - break; + case IOCTL_BCM_GPIO_MODE_REQUEST: + Status = bcm_char_ioctl_gpio_mode_request(argp, Adapter); + return Status; case IOCTL_MAC_ADDR_REQ: case IOCTL_LINK_REQ: case IOCTL_CM_REQUEST: case IOCTL_SS_INFO_REQ: case IOCTL_SEND_CONTROL_MESSAGE: - case IOCTL_IDLE_REQ: { - PVOID pvBuffer = NULL; - - /* Copy Ioctl Buffer structure */ - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (IoBuffer.InputLength < sizeof(struct bcm_link_request)) - return -EINVAL; - - if (IoBuffer.InputLength > MAX_CNTL_PKT_SIZE) - return -EINVAL; - - pvBuffer = memdup_user(IoBuffer.InputBuffer, - IoBuffer.InputLength); - if (IS_ERR(pvBuffer)) - return PTR_ERR(pvBuffer); - - down(&Adapter->LowPowerModeSync); - Status = wait_event_interruptible_timeout(Adapter->lowpower_mode_wait_queue, - !Adapter->bPreparingForLowPowerMode, - (1 * HZ)); - if (Status == -ERESTARTSYS) - goto cntrlEnd; - - if (Adapter->bPreparingForLowPowerMode) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, - "Preparing Idle Mode is still True - Hence Rejecting control message\n"); - Status = STATUS_FAILURE; - goto cntrlEnd; - } - Status = CopyBufferToControlPacket(Adapter, (PVOID)pvBuffer); - -cntrlEnd: - up(&Adapter->LowPowerModeSync); - kfree(pvBuffer); - break; - } - - case IOCTL_BCM_BUFFER_DOWNLOAD_START: { - if (down_trylock(&Adapter->NVMRdmWrmLock)) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, - "IOCTL_BCM_CHIP_RESET not allowed as EEPROM Read/Write is in progress\n"); - return -EACCES; - } - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "Starting the firmware download PID =0x%x!!!!\n", current->pid); - - if (down_trylock(&Adapter->fw_download_sema)) - return -EBUSY; - - Adapter->bBinDownloaded = false; - Adapter->fw_download_process_pid = current->pid; - Adapter->bCfgDownloaded = false; - Adapter->fw_download_done = false; - netif_carrier_off(Adapter->dev); - netif_stop_queue(Adapter->dev); - Status = reset_card_proc(Adapter); - if (Status) { - pr_err(PFX "%s: reset_card_proc Failed!\n", Adapter->dev->name); - up(&Adapter->fw_download_sema); - up(&Adapter->NVMRdmWrmLock); - return Status; - } - mdelay(10); - - up(&Adapter->NVMRdmWrmLock); + case IOCTL_IDLE_REQ: + Status = bcm_char_ioctl_misc_request(argp, Adapter); return Status; - } - case IOCTL_BCM_BUFFER_DOWNLOAD: { - struct bcm_firmware_info *psFwInfo = NULL; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Starting the firmware download PID =0x%x!!!!\n", current->pid); - - if (!down_trylock(&Adapter->fw_download_sema)) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "Invalid way to download buffer. Use Start and then call this!!!\n"); - up(&Adapter->fw_download_sema); - Status = -EINVAL; - return Status; - } - - /* Copy Ioctl Buffer structure */ - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) { - up(&Adapter->fw_download_sema); - return -EFAULT; - } - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "Length for FW DLD is : %lx\n", IoBuffer.InputLength); - - if (IoBuffer.InputLength > sizeof(struct bcm_firmware_info)) { - up(&Adapter->fw_download_sema); - return -EINVAL; - } - - psFwInfo = kmalloc(sizeof(*psFwInfo), GFP_KERNEL); - if (!psFwInfo) { - up(&Adapter->fw_download_sema); - return -ENOMEM; - } - - if (copy_from_user(psFwInfo, IoBuffer.InputBuffer, IoBuffer.InputLength)) { - up(&Adapter->fw_download_sema); - kfree(psFwInfo); - return -EFAULT; - } - - if (!psFwInfo->pvMappedFirmwareAddress || - (psFwInfo->u32FirmwareLength == 0)) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Something else is wrong %lu\n", - psFwInfo->u32FirmwareLength); - up(&Adapter->fw_download_sema); - kfree(psFwInfo); - Status = -EINVAL; - return Status; - } - - Status = bcm_ioctl_fw_download(Adapter, psFwInfo); - - if (Status != STATUS_SUCCESS) { - if (psFwInfo->u32StartingAddress == CONFIG_BEGIN_ADDR) - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "IOCTL: Configuration File Upload Failed\n"); - else - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "IOCTL: Firmware File Upload Failed\n"); - - /* up(&Adapter->fw_download_sema); */ - - if (Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { - Adapter->DriverState = DRIVER_INIT; - Adapter->LEDInfo.bLedInitDone = false; - wake_up(&Adapter->LEDInfo.notify_led_event); - } - } - - if (Status != STATUS_SUCCESS) - up(&Adapter->fw_download_sema); - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, OSAL_DBG, DBG_LVL_ALL, "IOCTL: Firmware File Uploaded\n"); - kfree(psFwInfo); + case IOCTL_BCM_BUFFER_DOWNLOAD_START: + Status = bcm_char_ioctl_buffer_download_start(Adapter); return Status; - } - case IOCTL_BCM_BUFFER_DOWNLOAD_STOP: { - if (!down_trylock(&Adapter->fw_download_sema)) { - up(&Adapter->fw_download_sema); - return -EINVAL; - } - - if (down_trylock(&Adapter->NVMRdmWrmLock)) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "FW download blocked as EEPROM Read/Write is in progress\n"); - up(&Adapter->fw_download_sema); - return -EACCES; - } - - Adapter->bBinDownloaded = TRUE; - Adapter->bCfgDownloaded = TRUE; - atomic_set(&Adapter->CurrNumFreeTxDesc, 0); - Adapter->CurrNumRecvDescs = 0; - Adapter->downloadDDR = 0; - - /* setting the Mips to Run */ - Status = run_card_proc(Adapter); - - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Firm Download Failed\n"); - up(&Adapter->fw_download_sema); - up(&Adapter->NVMRdmWrmLock); - return Status; - } else { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, - DBG_LVL_ALL, "Firm Download Over...\n"); - } - - mdelay(10); - - /* Wait for MailBox Interrupt */ - if (StartInterruptUrb((struct bcm_interface_adapter *)Adapter->pvInterfaceAdapter)) - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Unable to send interrupt...\n"); - - timeout = 5*HZ; - Adapter->waiting_to_fw_download_done = false; - wait_event_timeout(Adapter->ioctl_fw_dnld_wait_queue, - Adapter->waiting_to_fw_download_done, timeout); - Adapter->fw_download_process_pid = INVALID_PID; - Adapter->fw_download_done = TRUE; - atomic_set(&Adapter->CurrNumFreeTxDesc, 0); - Adapter->CurrNumRecvDescs = 0; - Adapter->PrevNumRecvDescs = 0; - atomic_set(&Adapter->cntrlpktCnt, 0); - Adapter->LinkUpStatus = 0; - Adapter->LinkStatus = 0; - - if (Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { - Adapter->DriverState = FW_DOWNLOAD_DONE; - wake_up(&Adapter->LEDInfo.notify_led_event); - } - - if (!timeout) - Status = -ENODEV; - - up(&Adapter->fw_download_sema); - up(&Adapter->NVMRdmWrmLock); + case IOCTL_BCM_BUFFER_DOWNLOAD: + Status = bcm_char_ioctl_buffer_download(argp, Adapter); return Status; - } + + case IOCTL_BCM_BUFFER_DOWNLOAD_STOP: + Status = bcm_char_ioctl_buffer_download_stop(argp, Adapter); + return Status; + case IOCTL_BE_BUCKET_SIZE: Status = 0; @@ -986,35 +2404,13 @@ cntrlEnd: Status = -EFAULT; break; - case IOCTL_CHIP_RESET: { - INT NVMAccess = down_trylock(&Adapter->NVMRdmWrmLock); - if (NVMAccess) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, " IOCTL_BCM_CHIP_RESET not allowed as EEPROM Read/Write is in progress\n"); - return -EACCES; - } + case IOCTL_CHIP_RESET: + Status = bcm_char_ioctl_chip_reset(Adapter); + return Status; - down(&Adapter->RxAppControlQueuelock); - Status = reset_card_proc(Adapter); - flushAllAppQ(); - up(&Adapter->RxAppControlQueuelock); - up(&Adapter->NVMRdmWrmLock); - ResetCounters(Adapter); - break; - } - - case IOCTL_QOS_THRESHOLD: { - USHORT uiLoopIndex; - - Status = 0; - for (uiLoopIndex = 0; uiLoopIndex < NO_OF_QUEUES; uiLoopIndex++) { - if (get_user(Adapter->PackInfo[uiLoopIndex].uiThreshold, - (unsigned long __user *)arg)) { - Status = -EFAULT; - break; - } - } - break; - } + case IOCTL_QOS_THRESHOLD: + Status = bcm_char_ioctl_qos_threshold(arg, Adapter); + return Status; case IOCTL_DUMP_PACKET_INFO: DumpPackInfo(Adapter); @@ -1023,142 +2419,39 @@ cntrlEnd: break; case IOCTL_GET_PACK_INFO: - if (copy_to_user(argp, &Adapter->PackInfo, sizeof(struct bcm_packet_info)*NO_OF_QUEUES)) + if (copy_to_user(argp, &Adapter->PackInfo, + sizeof(struct bcm_packet_info)*NO_OF_QUEUES)) return -EFAULT; Status = STATUS_SUCCESS; break; - case IOCTL_BCM_SWITCH_TRANSFER_MODE: { - UINT uiData = 0; - if (copy_from_user(&uiData, argp, sizeof(UINT))) - return -EFAULT; + case IOCTL_BCM_SWITCH_TRANSFER_MODE: + Status = bcm_char_ioctl_switch_transfer_mode(argp, Adapter); + return Status; - if (uiData) { - /* Allow All Packets */ - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_SWITCH_TRANSFER_MODE: ETH_PACKET_TUNNELING_MODE\n"); - Adapter->TransferMode = ETH_PACKET_TUNNELING_MODE; - } else { - /* Allow IP only Packets */ - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_SWITCH_TRANSFER_MODE: IP_PACKET_ONLY_MODE\n"); - Adapter->TransferMode = IP_PACKET_ONLY_MODE; - } - Status = STATUS_SUCCESS; - break; - } + case IOCTL_BCM_GET_DRIVER_VERSION: + Status = bcm_char_ioctl_get_driver_version(argp); + return Status; - case IOCTL_BCM_GET_DRIVER_VERSION: { - ulong len; + case IOCTL_BCM_GET_CURRENT_STATUS: + Status = bcm_char_ioctl_get_current_status(argp, Adapter); + return Status; - /* Copy Ioctl Buffer structure */ - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; + case IOCTL_BCM_SET_MAC_TRACING: + Status = bcm_char_ioctl_set_mac_tracing(argp, Adapter); + return Status; - len = min_t(ulong, IoBuffer.OutputLength, strlen(DRV_VERSION) + 1); + case IOCTL_BCM_GET_DSX_INDICATION: + Status = bcm_char_ioctl_get_dsx_indication(argp, Adapter); + return Status; - if (copy_to_user(IoBuffer.OutputBuffer, DRV_VERSION, len)) - return -EFAULT; - Status = STATUS_SUCCESS; - break; - } - - case IOCTL_BCM_GET_CURRENT_STATUS: { - struct bcm_link_state link_state; - - /* Copy Ioctl Buffer structure */ - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "copy_from_user failed..\n"); - return -EFAULT; - } - - if (IoBuffer.OutputLength != sizeof(link_state)) { - Status = -EINVAL; - break; - } - - memset(&link_state, 0, sizeof(link_state)); - link_state.bIdleMode = Adapter->IdleMode; - link_state.bShutdownMode = Adapter->bShutStatus; - link_state.ucLinkStatus = Adapter->LinkStatus; - - if (copy_to_user(IoBuffer.OutputBuffer, &link_state, min_t(size_t, sizeof(link_state), IoBuffer.OutputLength))) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy_to_user Failed..\n"); - return -EFAULT; - } - Status = STATUS_SUCCESS; - break; - } - - case IOCTL_BCM_SET_MAC_TRACING: { - UINT tracing_flag; - - /* copy ioctl Buffer structure */ - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (copy_from_user(&tracing_flag, IoBuffer.InputBuffer, sizeof(UINT))) - return -EFAULT; - - if (tracing_flag) - Adapter->pTarangs->MacTracingEnabled = TRUE; - else - Adapter->pTarangs->MacTracingEnabled = false; - break; - } - - case IOCTL_BCM_GET_DSX_INDICATION: { - ULONG ulSFId = 0; - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (IoBuffer.OutputLength < sizeof(struct bcm_add_indication_alt)) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "Mismatch req: %lx needed is =0x%zx!!!", - IoBuffer.OutputLength, sizeof(struct bcm_add_indication_alt)); - return -EINVAL; - } - - if (copy_from_user(&ulSFId, IoBuffer.InputBuffer, sizeof(ulSFId))) - return -EFAULT; - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Get DSX Data SF ID is =%lx\n", ulSFId); - get_dsx_sf_data_to_application(Adapter, ulSFId, IoBuffer.OutputBuffer); - Status = STATUS_SUCCESS; - } - break; - - case IOCTL_BCM_GET_HOST_MIBS: { - PVOID temp_buff; - - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (IoBuffer.OutputLength != sizeof(struct bcm_host_stats_mibs)) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, - "Length Check failed %lu %zd\n", - IoBuffer.OutputLength, sizeof(struct bcm_host_stats_mibs)); - return -EINVAL; - } - - /* FIXME: HOST_STATS are too big for kmalloc (122048)! */ - temp_buff = kzalloc(sizeof(struct bcm_host_stats_mibs), GFP_KERNEL); - if (!temp_buff) - return STATUS_FAILURE; - - Status = ProcessGetHostMibs(Adapter, temp_buff); - GetDroppedAppCntrlPktMibs(temp_buff, pTarang); - - if (Status != STATUS_FAILURE) - if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, sizeof(struct bcm_host_stats_mibs))) { - kfree(temp_buff); - return -EFAULT; - } - - kfree(temp_buff); - break; - } + case IOCTL_BCM_GET_HOST_MIBS: + Status = bcm_char_ioctl_get_host_mibs(argp, Adapter, pTarang); + return Status; case IOCTL_BCM_WAKE_UP_DEVICE_FROM_IDLE: - if ((false == Adapter->bTriedToWakeUpFromlowPowerMode) && (TRUE == Adapter->IdleMode)) { + if ((false == Adapter->bTriedToWakeUpFromlowPowerMode) && + (TRUE == Adapter->IdleMode)) { Adapter->usIdleModePattern = ABORT_IDLE_MODE; Adapter->bWakeUpDevice = TRUE; wake_up(&Adapter->process_rx_cntrlpkt); @@ -1167,886 +2460,82 @@ cntrlEnd: Status = STATUS_SUCCESS; break; - case IOCTL_BCM_BULK_WRM: { - struct bcm_bulk_wrm_buffer *pBulkBuffer; - UINT uiTempVar = 0; - PCHAR pvBuffer = NULL; - - if ((Adapter->IdleMode == TRUE) || - (Adapter->bShutStatus == TRUE) || - (Adapter->bPreparingForLowPowerMode == TRUE)) { - - BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "Device in Idle/Shutdown Mode, Blocking Wrms\n"); - Status = -EACCES; - break; - } - - /* Copy Ioctl Buffer structure */ - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (IoBuffer.InputLength < sizeof(ULONG) * 2) - return -EINVAL; - - pvBuffer = memdup_user(IoBuffer.InputBuffer, - IoBuffer.InputLength); - if (IS_ERR(pvBuffer)) - return PTR_ERR(pvBuffer); - - pBulkBuffer = (struct bcm_bulk_wrm_buffer *)pvBuffer; - - if (((ULONG)pBulkBuffer->Register & 0x0F000000) != 0x0F000000 || - ((ULONG)pBulkBuffer->Register & 0x3)) { - BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM Done On invalid Address : %x Access Denied.\n", (int)pBulkBuffer->Register); - kfree(pvBuffer); - Status = -EINVAL; - break; - } - - uiTempVar = pBulkBuffer->Register & EEPROM_REJECT_MASK; - if (!((Adapter->pstargetparams->m_u32Customize)&VSG_MODE) && - ((uiTempVar == EEPROM_REJECT_REG_1) || - (uiTempVar == EEPROM_REJECT_REG_2) || - (uiTempVar == EEPROM_REJECT_REG_3) || - (uiTempVar == EEPROM_REJECT_REG_4)) && - (cmd == IOCTL_BCM_REGISTER_WRITE)) { - - kfree(pvBuffer); - BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "EEPROM Access Denied, not in VSG Mode\n"); - Status = -EFAULT; - break; - } - - if (pBulkBuffer->SwapEndian == false) - Status = wrmWithLock(Adapter, (UINT)pBulkBuffer->Register, (PCHAR)pBulkBuffer->Values, IoBuffer.InputLength - 2*sizeof(ULONG)); - else - Status = wrmaltWithLock(Adapter, (UINT)pBulkBuffer->Register, (PUINT)pBulkBuffer->Values, IoBuffer.InputLength - 2*sizeof(ULONG)); - - if (Status != STATUS_SUCCESS) - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM Failed\n"); - - kfree(pvBuffer); - break; - } + case IOCTL_BCM_BULK_WRM: + Status = bcm_char_ioctl_bulk_wrm(argp, Adapter, cmd); + return Status; case IOCTL_BCM_GET_NVM_SIZE: - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; + Status = bcm_char_ioctl_get_nvm_size(argp, Adapter); + return Status; - if (Adapter->eNVMType == NVM_EEPROM || Adapter->eNVMType == NVM_FLASH) { - if (copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiNVMDSDSize, sizeof(UINT))) - return -EFAULT; - } - - Status = STATUS_SUCCESS; - break; - - case IOCTL_BCM_CAL_INIT: { - UINT uiSectorSize = 0; - if (Adapter->eNVMType == NVM_FLASH) { - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (copy_from_user(&uiSectorSize, IoBuffer.InputBuffer, sizeof(UINT))) - return -EFAULT; - - if ((uiSectorSize < MIN_SECTOR_SIZE) || (uiSectorSize > MAX_SECTOR_SIZE)) { - if (copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiSectorSize, - sizeof(UINT))) - return -EFAULT; - } else { - if (IsFlash2x(Adapter)) { - if (copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiSectorSize, sizeof(UINT))) - return -EFAULT; - } else { - if ((TRUE == Adapter->bShutStatus) || (TRUE == Adapter->IdleMode)) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Device is in Idle/Shutdown Mode\n"); - return -EACCES; - } - - Adapter->uiSectorSize = uiSectorSize; - BcmUpdateSectorSize(Adapter, Adapter->uiSectorSize); - } - } - Status = STATUS_SUCCESS; - } else { - Status = STATUS_FAILURE; - } - } - break; + case IOCTL_BCM_CAL_INIT: + Status = bcm_char_ioctl_cal_init(argp, Adapter); + return Status; case IOCTL_BCM_SET_DEBUG: -#ifdef DEBUG - { - struct bcm_user_debug_state sUserDebugState; - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "In SET_DEBUG ioctl\n"); - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (copy_from_user(&sUserDebugState, IoBuffer.InputBuffer, sizeof(struct bcm_user_debug_state))) - return -EFAULT; - - BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "IOCTL_BCM_SET_DEBUG: OnOff=%d Type = 0x%x ", - sUserDebugState.OnOff, sUserDebugState.Type); - /* sUserDebugState.Subtype <<= 1; */ - sUserDebugState.Subtype = 1 << sUserDebugState.Subtype; - BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "actual Subtype=0x%x\n", sUserDebugState.Subtype); - - /* Update new 'DebugState' in the Adapter */ - Adapter->stDebugState.type |= sUserDebugState.Type; - /* Subtype: A bitmap of 32 bits for Subtype per Type. - * Valid indexes in 'subtype' array: 1,2,4,8 - * corresponding to valid Type values. Hence we can use the 'Type' field - * as the index value, ignoring the array entries 0,3,5,6,7 ! - */ - if (sUserDebugState.OnOff) - Adapter->stDebugState.subtype[sUserDebugState.Type] |= sUserDebugState.Subtype; - else - Adapter->stDebugState.subtype[sUserDebugState.Type] &= ~sUserDebugState.Subtype; - - BCM_SHOW_DEBUG_BITMAP(Adapter); - } -#endif - break; + Status = bcm_char_ioctl_set_debug(argp, Adapter); + return Status; case IOCTL_BCM_NVM_READ: - case IOCTL_BCM_NVM_WRITE: { - struct bcm_nvm_readwrite stNVMReadWrite; - PUCHAR pReadData = NULL; - ULONG ulDSDMagicNumInUsrBuff = 0; - struct timeval tv0, tv1; - memset(&tv0, 0, sizeof(struct timeval)); - memset(&tv1, 0, sizeof(struct timeval)); - if ((Adapter->eNVMType == NVM_FLASH) && (Adapter->uiFlashLayoutMajorVersion == 0)) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "The Flash Control Section is Corrupted. Hence Rejection on NVM Read/Write\n"); - return -EFAULT; - } + case IOCTL_BCM_NVM_WRITE: + Status = bcm_char_ioctl_nvm_rw(argp, Adapter, cmd); + return Status; - if (IsFlash2x(Adapter)) { - if ((Adapter->eActiveDSD != DSD0) && - (Adapter->eActiveDSD != DSD1) && - (Adapter->eActiveDSD != DSD2)) { + case IOCTL_BCM_FLASH2X_SECTION_READ: + Status = bcm_char_ioctl_flash2x_section_read(argp, Adapter); + return Status; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "No DSD is active..hence NVM Command is blocked"); - return STATUS_FAILURE; - } - } + case IOCTL_BCM_FLASH2X_SECTION_WRITE: + Status = bcm_char_ioctl_flash2x_section_write(argp, Adapter); + return Status; - /* Copy Ioctl Buffer structure */ - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; + case IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP: + Status = bcm_char_ioctl_flash2x_section_bitmap(argp, Adapter); + return Status; - if (copy_from_user(&stNVMReadWrite, - (IOCTL_BCM_NVM_READ == cmd) ? IoBuffer.OutputBuffer : IoBuffer.InputBuffer, - sizeof(struct bcm_nvm_readwrite))) - return -EFAULT; + case IOCTL_BCM_SET_ACTIVE_SECTION: + Status = bcm_char_ioctl_set_active_section(argp, Adapter); + return Status; - /* - * Deny the access if the offset crosses the cal area limit. - */ - if (stNVMReadWrite.uiNumBytes > Adapter->uiNVMDSDSize) - return STATUS_FAILURE; - - if (stNVMReadWrite.uiOffset > Adapter->uiNVMDSDSize - stNVMReadWrite.uiNumBytes) { - /* BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Can't allow access beyond NVM Size: 0x%x 0x%x\n", stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes); */ - return STATUS_FAILURE; - } - - pReadData = memdup_user(stNVMReadWrite.pBuffer, - stNVMReadWrite.uiNumBytes); - if (IS_ERR(pReadData)) - return PTR_ERR(pReadData); - - do_gettimeofday(&tv0); - if (IOCTL_BCM_NVM_READ == cmd) { - down(&Adapter->NVMRdmWrmLock); - - if ((Adapter->IdleMode == TRUE) || - (Adapter->bShutStatus == TRUE) || - (Adapter->bPreparingForLowPowerMode == TRUE)) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n"); - up(&Adapter->NVMRdmWrmLock); - kfree(pReadData); - return -EACCES; - } - - Status = BeceemNVMRead(Adapter, (PUINT)pReadData, stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes); - up(&Adapter->NVMRdmWrmLock); - - if (Status != STATUS_SUCCESS) { - kfree(pReadData); - return Status; - } - - if (copy_to_user(stNVMReadWrite.pBuffer, pReadData, stNVMReadWrite.uiNumBytes)) { - kfree(pReadData); - return -EFAULT; - } - } else { - down(&Adapter->NVMRdmWrmLock); - - if ((Adapter->IdleMode == TRUE) || - (Adapter->bShutStatus == TRUE) || - (Adapter->bPreparingForLowPowerMode == TRUE)) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n"); - up(&Adapter->NVMRdmWrmLock); - kfree(pReadData); - return -EACCES; - } - - Adapter->bHeaderChangeAllowed = TRUE; - if (IsFlash2x(Adapter)) { - /* - * New Requirement:- - * DSD section updation will be allowed in two case:- - * 1. if DSD sig is present in DSD header means dongle is ok and updation is fruitfull - * 2. if point 1 failes then user buff should have DSD sig. this point ensures that if dongle is - * corrupted then user space program first modify the DSD header with valid DSD sig so - * that this as well as further write may be worthwhile. - * - * This restriction has been put assuming that if DSD sig is corrupted, DSD - * data won't be considered valid. - */ - - Status = BcmFlash2xCorruptSig(Adapter, Adapter->eActiveDSD); - if (Status != STATUS_SUCCESS) { - if (((stNVMReadWrite.uiOffset + stNVMReadWrite.uiNumBytes) != Adapter->uiNVMDSDSize) || - (stNVMReadWrite.uiNumBytes < SIGNATURE_SIZE)) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "DSD Sig is present neither in Flash nor User provided Input.."); - up(&Adapter->NVMRdmWrmLock); - kfree(pReadData); - return Status; - } - - ulDSDMagicNumInUsrBuff = ntohl(*(PUINT)(pReadData + stNVMReadWrite.uiNumBytes - SIGNATURE_SIZE)); - if (ulDSDMagicNumInUsrBuff != DSD_IMAGE_MAGIC_NUMBER) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "DSD Sig is present neither in Flash nor User provided Input.."); - up(&Adapter->NVMRdmWrmLock); - kfree(pReadData); - return Status; - } - } - } - - Status = BeceemNVMWrite(Adapter, (PUINT)pReadData, stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes, stNVMReadWrite.bVerify); - if (IsFlash2x(Adapter)) - BcmFlash2xWriteSig(Adapter, Adapter->eActiveDSD); - - Adapter->bHeaderChangeAllowed = false; - - up(&Adapter->NVMRdmWrmLock); - - if (Status != STATUS_SUCCESS) { - kfree(pReadData); - return Status; - } - } - - do_gettimeofday(&tv1); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, " timetaken by Write/read :%ld msec\n", (tv1.tv_sec - tv0.tv_sec)*1000 + (tv1.tv_usec - tv0.tv_usec)/1000); - - kfree(pReadData); - return STATUS_SUCCESS; - } - - case IOCTL_BCM_FLASH2X_SECTION_READ: { - struct bcm_flash2x_readwrite sFlash2xRead = {0}; - PUCHAR pReadBuff = NULL; - UINT NOB = 0; - UINT BuffSize = 0; - UINT ReadBytes = 0; - UINT ReadOffset = 0; - void __user *OutPutBuff; - - if (IsFlash2x(Adapter) != TRUE) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Does not have 2.x map"); - return -EINVAL; - } - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_FLASH2X_SECTION_READ Called"); - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - /* Reading FLASH 2.x READ structure */ - if (copy_from_user(&sFlash2xRead, IoBuffer.InputBuffer, sizeof(struct bcm_flash2x_readwrite))) - return -EFAULT; - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.Section :%x", sFlash2xRead.Section); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.offset :%x", sFlash2xRead.offset); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.numOfBytes :%x", sFlash2xRead.numOfBytes); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.bVerify :%x\n", sFlash2xRead.bVerify); - - /* This was internal to driver for raw read. now it has ben exposed to user space app. */ - if (validateFlash2xReadWrite(Adapter, &sFlash2xRead) == false) - return STATUS_FAILURE; - - NOB = sFlash2xRead.numOfBytes; - if (NOB > Adapter->uiSectorSize) - BuffSize = Adapter->uiSectorSize; - else - BuffSize = NOB; - - ReadOffset = sFlash2xRead.offset; - OutPutBuff = IoBuffer.OutputBuffer; - pReadBuff = (PCHAR)kzalloc(BuffSize , GFP_KERNEL); - - if (pReadBuff == NULL) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed for Flash 2.x Read Structure"); - return -ENOMEM; - } - down(&Adapter->NVMRdmWrmLock); - - if ((Adapter->IdleMode == TRUE) || - (Adapter->bShutStatus == TRUE) || - (Adapter->bPreparingForLowPowerMode == TRUE)) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n"); - up(&Adapter->NVMRdmWrmLock); - kfree(pReadBuff); - return -EACCES; - } - - while (NOB) { - if (NOB > Adapter->uiSectorSize) - ReadBytes = Adapter->uiSectorSize; - else - ReadBytes = NOB; - - /* Reading the data from Flash 2.x */ - Status = BcmFlash2xBulkRead(Adapter, (PUINT)pReadBuff, sFlash2xRead.Section, ReadOffset, ReadBytes); - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Flash 2x read err with Status :%d", Status); - break; - } - - BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, pReadBuff, ReadBytes); - - Status = copy_to_user(OutPutBuff, pReadBuff, ReadBytes); - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Copy to use failed with status :%d", Status); - up(&Adapter->NVMRdmWrmLock); - kfree(pReadBuff); - return -EFAULT; - } - NOB = NOB - ReadBytes; - if (NOB) { - ReadOffset = ReadOffset + ReadBytes; - OutPutBuff = OutPutBuff + ReadBytes; - } - } - - up(&Adapter->NVMRdmWrmLock); - kfree(pReadBuff); - } - break; - - case IOCTL_BCM_FLASH2X_SECTION_WRITE: { - struct bcm_flash2x_readwrite sFlash2xWrite = {0}; - PUCHAR pWriteBuff; - void __user *InputAddr; - UINT NOB = 0; - UINT BuffSize = 0; - UINT WriteOffset = 0; - UINT WriteBytes = 0; - - if (IsFlash2x(Adapter) != TRUE) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Does not have 2.x map"); - return -EINVAL; - } - - /* First make this False so that we can enable the Sector Permission Check in BeceemFlashBulkWrite */ - Adapter->bAllDSDWriteAllow = false; - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_FLASH2X_SECTION_WRITE Called"); - - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - /* Reading FLASH 2.x READ structure */ - if (copy_from_user(&sFlash2xWrite, IoBuffer.InputBuffer, sizeof(struct bcm_flash2x_readwrite))) - return -EFAULT; - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.Section :%x", sFlash2xWrite.Section); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.offset :%d", sFlash2xWrite.offset); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.numOfBytes :%x", sFlash2xWrite.numOfBytes); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\nsFlash2xRead.bVerify :%x\n", sFlash2xWrite.bVerify); - - if ((sFlash2xWrite.Section != VSA0) && (sFlash2xWrite.Section != VSA1) && (sFlash2xWrite.Section != VSA2)) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Only VSA write is allowed"); - return -EINVAL; - } - - if (validateFlash2xReadWrite(Adapter, &sFlash2xWrite) == false) - return STATUS_FAILURE; - - InputAddr = sFlash2xWrite.pDataBuff; - WriteOffset = sFlash2xWrite.offset; - NOB = sFlash2xWrite.numOfBytes; - - if (NOB > Adapter->uiSectorSize) - BuffSize = Adapter->uiSectorSize; - else - BuffSize = NOB; - - pWriteBuff = kmalloc(BuffSize, GFP_KERNEL); - - if (pWriteBuff == NULL) - return -ENOMEM; - - /* extracting the remainder of the given offset. */ - WriteBytes = Adapter->uiSectorSize; - if (WriteOffset % Adapter->uiSectorSize) - WriteBytes = Adapter->uiSectorSize - (WriteOffset % Adapter->uiSectorSize); - - if (NOB < WriteBytes) - WriteBytes = NOB; - - down(&Adapter->NVMRdmWrmLock); - - if ((Adapter->IdleMode == TRUE) || - (Adapter->bShutStatus == TRUE) || - (Adapter->bPreparingForLowPowerMode == TRUE)) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n"); - up(&Adapter->NVMRdmWrmLock); - kfree(pWriteBuff); - return -EACCES; - } - - BcmFlash2xCorruptSig(Adapter, sFlash2xWrite.Section); - do { - Status = copy_from_user(pWriteBuff, InputAddr, WriteBytes); - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy to user failed with status :%d", Status); - up(&Adapter->NVMRdmWrmLock); - kfree(pWriteBuff); - return -EFAULT; - } - BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, pWriteBuff, WriteBytes); - - /* Writing the data from Flash 2.x */ - Status = BcmFlash2xBulkWrite(Adapter, (PUINT)pWriteBuff, sFlash2xWrite.Section, WriteOffset, WriteBytes, sFlash2xWrite.bVerify); - - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash 2x read err with Status :%d", Status); - break; - } - - NOB = NOB - WriteBytes; - if (NOB) { - WriteOffset = WriteOffset + WriteBytes; - InputAddr = InputAddr + WriteBytes; - if (NOB > Adapter->uiSectorSize) - WriteBytes = Adapter->uiSectorSize; - else - WriteBytes = NOB; - } - } while (NOB > 0); - - BcmFlash2xWriteSig(Adapter, sFlash2xWrite.Section); - up(&Adapter->NVMRdmWrmLock); - kfree(pWriteBuff); - } - break; - - case IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP: { - struct bcm_flash2x_bitmap *psFlash2xBitMap; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP Called"); - - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (IoBuffer.OutputLength != sizeof(struct bcm_flash2x_bitmap)) - return -EINVAL; - - psFlash2xBitMap = kzalloc(sizeof(struct bcm_flash2x_bitmap), GFP_KERNEL); - if (psFlash2xBitMap == NULL) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory is not available"); - return -ENOMEM; - } - - /* Reading the Flash Sectio Bit map */ - down(&Adapter->NVMRdmWrmLock); - - if ((Adapter->IdleMode == TRUE) || - (Adapter->bShutStatus == TRUE) || - (Adapter->bPreparingForLowPowerMode == TRUE)) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n"); - up(&Adapter->NVMRdmWrmLock); - kfree(psFlash2xBitMap); - return -EACCES; - } - - BcmGetFlash2xSectionalBitMap(Adapter, psFlash2xBitMap); - up(&Adapter->NVMRdmWrmLock); - if (copy_to_user(IoBuffer.OutputBuffer, psFlash2xBitMap, sizeof(struct bcm_flash2x_bitmap))) { - kfree(psFlash2xBitMap); - return -EFAULT; - } - - kfree(psFlash2xBitMap); - } - break; - - case IOCTL_BCM_SET_ACTIVE_SECTION: { - enum bcm_flash2x_section_val eFlash2xSectionVal = 0; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_SET_ACTIVE_SECTION Called"); - - if (IsFlash2x(Adapter) != TRUE) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Does not have 2.x map"); - return -EINVAL; - } - - Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)); - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed"); - return -EFAULT; - } - - Status = copy_from_user(&eFlash2xSectionVal, IoBuffer.InputBuffer, sizeof(INT)); - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of flash section val failed"); - return -EFAULT; - } - - down(&Adapter->NVMRdmWrmLock); - - if ((Adapter->IdleMode == TRUE) || - (Adapter->bShutStatus == TRUE) || - (Adapter->bPreparingForLowPowerMode == TRUE)) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n"); - up(&Adapter->NVMRdmWrmLock); - return -EACCES; - } - - Status = BcmSetActiveSection(Adapter, eFlash2xSectionVal); - if (Status) - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Failed to make it's priority Highest. Status %d", Status); - - up(&Adapter->NVMRdmWrmLock); - } - break; - - case IOCTL_BCM_IDENTIFY_ACTIVE_SECTION: { + case IOCTL_BCM_IDENTIFY_ACTIVE_SECTION: /* Right Now we are taking care of only DSD */ Adapter->bAllDSDWriteAllow = false; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_IDENTIFY_ACTIVE_SECTION called"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_IDENTIFY_ACTIVE_SECTION called"); Status = STATUS_SUCCESS; - } - break; - - case IOCTL_BCM_COPY_SECTION: { - struct bcm_flash2x_copy_section sCopySectStrut = {0}; - Status = STATUS_SUCCESS; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_COPY_SECTION Called"); - - Adapter->bAllDSDWriteAllow = false; - if (IsFlash2x(Adapter) != TRUE) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Does not have 2.x map"); - return -EINVAL; - } - - Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)); - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed Status :%d", Status); - return -EFAULT; - } - - Status = copy_from_user(&sCopySectStrut, IoBuffer.InputBuffer, sizeof(struct bcm_flash2x_copy_section)); - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of Copy_Section_Struct failed with Status :%d", Status); - return -EFAULT; - } - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Source SEction :%x", sCopySectStrut.SrcSection); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Destination SEction :%x", sCopySectStrut.DstSection); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "offset :%x", sCopySectStrut.offset); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "NOB :%x", sCopySectStrut.numOfBytes); - - if (IsSectionExistInFlash(Adapter, sCopySectStrut.SrcSection) == false) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Source Section<%x> does not exist in Flash ", sCopySectStrut.SrcSection); - return -EINVAL; - } - - if (IsSectionExistInFlash(Adapter, sCopySectStrut.DstSection) == false) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Destinatio Section<%x> does not exist in Flash ", sCopySectStrut.DstSection); - return -EINVAL; - } - - if (sCopySectStrut.SrcSection == sCopySectStrut.DstSection) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Source and Destination section should be different"); - return -EINVAL; - } - - down(&Adapter->NVMRdmWrmLock); - - if ((Adapter->IdleMode == TRUE) || - (Adapter->bShutStatus == TRUE) || - (Adapter->bPreparingForLowPowerMode == TRUE)) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n"); - up(&Adapter->NVMRdmWrmLock); - return -EACCES; - } - - if (sCopySectStrut.SrcSection == ISO_IMAGE1 || sCopySectStrut.SrcSection == ISO_IMAGE2) { - if (IsNonCDLessDevice(Adapter)) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Device is Non-CDLess hence won't have ISO !!"); - Status = -EINVAL; - } else if (sCopySectStrut.numOfBytes == 0) { - Status = BcmCopyISO(Adapter, sCopySectStrut); - } else { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Partial Copy of ISO section is not Allowed.."); - Status = STATUS_FAILURE; - } - up(&Adapter->NVMRdmWrmLock); - return Status; - } - - Status = BcmCopySection(Adapter, sCopySectStrut.SrcSection, - sCopySectStrut.DstSection, sCopySectStrut.offset, sCopySectStrut.numOfBytes); - up(&Adapter->NVMRdmWrmLock); - } - break; - - case IOCTL_BCM_GET_FLASH_CS_INFO: { - Status = STATUS_SUCCESS; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, " IOCTL_BCM_GET_FLASH_CS_INFO Called"); - - Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)); - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed"); - return -EFAULT; - } - - if (Adapter->eNVMType != NVM_FLASH) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Connected device does not have flash"); - Status = -EINVAL; - break; - } - - if (IsFlash2x(Adapter) == TRUE) { - if (IoBuffer.OutputLength < sizeof(struct bcm_flash2x_cs_info)) - return -EINVAL; - - if (copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlash2xCSInfo, sizeof(struct bcm_flash2x_cs_info))) - return -EFAULT; - } else { - if (IoBuffer.OutputLength < sizeof(struct bcm_flash_cs_info)) - return -EINVAL; - - if (copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlashCSInfo, sizeof(struct bcm_flash_cs_info))) - return -EFAULT; - } - } - break; - - case IOCTL_BCM_SELECT_DSD: { - UINT SectOfset = 0; - enum bcm_flash2x_section_val eFlash2xSectionVal; - eFlash2xSectionVal = NO_SECTION_VAL; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_SELECT_DSD Called"); - - if (IsFlash2x(Adapter) != TRUE) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Does not have 2.x map"); - return -EINVAL; - } - - Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)); - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed"); - return -EFAULT; - } - Status = copy_from_user(&eFlash2xSectionVal, IoBuffer.InputBuffer, sizeof(INT)); - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy of flash section val failed"); - return -EFAULT; - } - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Read Section :%d", eFlash2xSectionVal); - if ((eFlash2xSectionVal != DSD0) && - (eFlash2xSectionVal != DSD1) && - (eFlash2xSectionVal != DSD2)) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Passed section<%x> is not DSD section", eFlash2xSectionVal); - return STATUS_FAILURE; - } - - SectOfset = BcmGetSectionValStartOffset(Adapter, eFlash2xSectionVal); - if (SectOfset == INVALID_OFFSET) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Provided Section val <%d> does not exist in Flash 2.x", eFlash2xSectionVal); - return -EINVAL; - } - - Adapter->bAllDSDWriteAllow = TRUE; - Adapter->ulFlashCalStart = SectOfset; - Adapter->eActiveDSD = eFlash2xSectionVal; - } - Status = STATUS_SUCCESS; - break; - - case IOCTL_BCM_NVM_RAW_READ: { - struct bcm_nvm_readwrite stNVMRead; - INT NOB; - INT BuffSize; - INT ReadOffset = 0; - UINT ReadBytes = 0; - PUCHAR pReadBuff; - void __user *OutPutBuff; - - if (Adapter->eNVMType != NVM_FLASH) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "NVM TYPE is not Flash"); - return -EINVAL; - } - - /* Copy Ioctl Buffer structure */ - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "copy_from_user 1 failed\n"); - return -EFAULT; - } - - if (copy_from_user(&stNVMRead, IoBuffer.OutputBuffer, sizeof(struct bcm_nvm_readwrite))) - return -EFAULT; - - NOB = stNVMRead.uiNumBytes; - /* In Raw-Read max Buff size : 64MB */ - - if (NOB > DEFAULT_BUFF_SIZE) - BuffSize = DEFAULT_BUFF_SIZE; - else - BuffSize = NOB; - - ReadOffset = stNVMRead.uiOffset; - OutPutBuff = stNVMRead.pBuffer; - - pReadBuff = kzalloc(BuffSize , GFP_KERNEL); - if (pReadBuff == NULL) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed for Flash 2.x Read Structure"); - Status = -ENOMEM; - break; - } - down(&Adapter->NVMRdmWrmLock); - - if ((Adapter->IdleMode == TRUE) || - (Adapter->bShutStatus == TRUE) || - (Adapter->bPreparingForLowPowerMode == TRUE)) { - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Device is in Idle/Shutdown Mode\n"); - kfree(pReadBuff); - up(&Adapter->NVMRdmWrmLock); - return -EACCES; - } - - Adapter->bFlashRawRead = TRUE; - - while (NOB) { - if (NOB > DEFAULT_BUFF_SIZE) - ReadBytes = DEFAULT_BUFF_SIZE; - else - ReadBytes = NOB; - - /* Reading the data from Flash 2.x */ - Status = BeceemNVMRead(Adapter, (PUINT)pReadBuff, ReadOffset, ReadBytes); - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash 2x read err with Status :%d", Status); - break; - } - - BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, pReadBuff, ReadBytes); - - Status = copy_to_user(OutPutBuff, pReadBuff, ReadBytes); - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy to use failed with status :%d", Status); - up(&Adapter->NVMRdmWrmLock); - kfree(pReadBuff); - return -EFAULT; - } - NOB = NOB - ReadBytes; - if (NOB) { - ReadOffset = ReadOffset + ReadBytes; - OutPutBuff = OutPutBuff + ReadBytes; - } - } - Adapter->bFlashRawRead = false; - up(&Adapter->NVMRdmWrmLock); - kfree(pReadBuff); break; - } - case IOCTL_BCM_CNTRLMSG_MASK: { - ULONG RxCntrlMsgBitMask = 0; + case IOCTL_BCM_COPY_SECTION: + Status = bcm_char_ioctl_copy_section(argp, Adapter); + return Status; - /* Copy Ioctl Buffer structure */ - Status = copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)); - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "copy of Ioctl buffer is failed from user space"); - return -EFAULT; - } + case IOCTL_BCM_GET_FLASH_CS_INFO: + Status = bcm_char_ioctl_get_flash_cs_info(argp, Adapter); + return Status; - if (IoBuffer.InputLength != sizeof(unsigned long)) { - Status = -EINVAL; - break; - } + case IOCTL_BCM_SELECT_DSD: + Status = bcm_char_ioctl_select_dsd(argp, Adapter); + return Status; - Status = copy_from_user(&RxCntrlMsgBitMask, IoBuffer.InputBuffer, IoBuffer.InputLength); - if (Status) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "copy of control bit mask failed from user space"); - return -EFAULT; - } - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "\n Got user defined cntrl msg bit mask :%lx", RxCntrlMsgBitMask); - pTarang->RxCntrlMsgBitMask = RxCntrlMsgBitMask; - } - break; + case IOCTL_BCM_NVM_RAW_READ: + Status = bcm_char_ioctl_nvm_raw_read(argp, Adapter); + return Status; - case IOCTL_BCM_GET_DEVICE_DRIVER_INFO: { - struct bcm_driver_info DevInfo; + case IOCTL_BCM_CNTRLMSG_MASK: + Status = bcm_char_ioctl_cntrlmsg_mask(argp, Adapter, pTarang); + return Status; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Called IOCTL_BCM_GET_DEVICE_DRIVER_INFO\n"); + case IOCTL_BCM_GET_DEVICE_DRIVER_INFO: + Status = bcm_char_ioctl_get_device_driver_info(argp, Adapter); + return Status; - memset(&DevInfo, 0, sizeof(DevInfo)); - DevInfo.MaxRDMBufferSize = BUFFER_4K; - DevInfo.u32DSDStartOffset = EEPROM_CALPARAM_START; - DevInfo.u32RxAlignmentCorrection = 0; - DevInfo.u32NVMType = Adapter->eNVMType; - DevInfo.u32InterfaceType = BCM_USB; - - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (IoBuffer.OutputLength < sizeof(DevInfo)) - return -EINVAL; - - if (copy_to_user(IoBuffer.OutputBuffer, &DevInfo, sizeof(DevInfo))) - return -EFAULT; - } - break; - - case IOCTL_BCM_TIME_SINCE_NET_ENTRY: { - struct bcm_time_elapsed stTimeElapsedSinceNetEntry = {0}; - - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_TIME_SINCE_NET_ENTRY called"); - - if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) - return -EFAULT; - - if (IoBuffer.OutputLength < sizeof(struct bcm_time_elapsed)) - return -EINVAL; - - stTimeElapsedSinceNetEntry.ul64TimeElapsedSinceNetEntry = get_seconds() - Adapter->liTimeSinceLastNetEntry; - - if (copy_to_user(IoBuffer.OutputBuffer, &stTimeElapsedSinceNetEntry, sizeof(struct bcm_time_elapsed))) - return -EFAULT; - } - break; + case IOCTL_BCM_TIME_SINCE_NET_ENTRY: + Status = bcm_char_ioctl_time_since_net_entry(argp, Adapter); + return Status; case IOCTL_CLOSE_NOTIFICATION: - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_CLOSE_NOTIFICATION"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, "IOCTL_CLOSE_NOTIFICATION"); break; default: diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c index cc91b5e934aa..632f81a7c63f 100644 --- a/drivers/staging/bcm/CmHost.c +++ b/drivers/staging/bcm/CmHost.c @@ -975,8 +975,8 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, - DBG_LVL_ALL, "u8EthernetSourceMACAddress[6]: " - "%pM", psfCSType->cCPacketClassificationRule. + DBG_LVL_ALL, "u8EthernetSourceMACAddress[6]: %pM", + psfCSType->cCPacketClassificationRule. u8EthernetSourceMACAddress); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthertypeLength: 0x%02X ", @@ -1092,18 +1092,16 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, - DBG_LVL_ALL, "u8ProtocolSourcePortRange[4]: " - "0x%*ph ", 4, psfCSType-> - cCPacketClassificationRule. + DBG_LVL_ALL, "u8ProtocolSourcePortRange[4]: 0x%*ph ", + 4, psfCSType->cCPacketClassificationRule. u8ProtocolSourcePortRange); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolDestPortRangeLength: 0x%02X ", psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, - DBG_LVL_ALL, "u8ProtocolDestPortRange[4]: " - "0x%*ph ", 4, psfCSType-> - cCPacketClassificationRule. + DBG_LVL_ALL, "u8ProtocolDestPortRange[4]: 0x%*ph ", + 4, psfCSType->cCPacketClassificationRule. u8ProtocolDestPortRange); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetDestMacAddressLength: 0x%02X ", @@ -1118,8 +1116,8 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, - DBG_LVL_ALL, "u8EthernetSourceMACAddress[6]: " - "%pM", psfCSType->cCPacketClassificationRule. + DBG_LVL_ALL, "u8EthernetSourceMACAddress[6]: %pM", + psfCSType->cCPacketClassificationRule. u8EthernetSourceMACAddress); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthertypeLength: 0x%02X ", psfCSType->cCPacketClassificationRule.u8EthertypeLength); @@ -1637,6 +1635,8 @@ bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* u16TID); switch (pstAddIndication->u8Type) { case DSA_REQ: - { pLeader->PLength = sizeof(struct bcm_add_indication_alt); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Sending DSA Response....\n"); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSA RESPONSE TO MAC %d", pLeader->PLength); @@ -1671,22 +1670,16 @@ bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* u16VCID)); CopyBufferToControlPacket(Adapter, (PVOID)Adapter->caDsxReqResp); kfree(pstAddIndication); - } - break; + break; case DSA_RSP: - { pLeader->PLength = sizeof(struct bcm_add_indication_alt); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSA ACK TO MAC %d", pLeader->PLength); *((struct bcm_add_indication_alt *)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *pstAddIndication; ((struct bcm_add_indication_alt *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSA_ACK; - - } /* no break here..we should go down. */ + /* FALLTHROUGH */ case DSA_ACK: - { - UINT uiSearchRuleIndex = 0; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "VCID:0x%X", ntohs(pstAddIndication->u16VCID)); uiSearchRuleIndex = SearchFreeSfid(Adapter); @@ -1694,7 +1687,7 @@ bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* u8Direction); - if ((uiSearchRuleIndex < NO_OF_QUEUES)) { + if (uiSearchRuleIndex < NO_OF_QUEUES) { Adapter->PackInfo[uiSearchRuleIndex].ucDirection = pstAddIndication->u8Direction; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "bValid:0x%X ", @@ -1769,10 +1762,8 @@ bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* PLength = sizeof(struct bcm_change_indication); pstChangeIndication = (struct bcm_change_indication *)pstAddIndication; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSC RESPONSE TO MAC %d", pLeader->PLength); @@ -1782,26 +1773,21 @@ bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* caDsxReqResp); kfree(pstAddIndication); - } - break; + break; case DSC_RSP: - { pLeader->PLength = sizeof(struct bcm_change_indication); pstChangeIndication = (struct bcm_change_indication *)pstAddIndication; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSC ACK TO MAC %d", pLeader->PLength); *((struct bcm_change_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *pstChangeIndication; ((struct bcm_change_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSC_ACK; - } + /* FALLTHROUGH */ case DSC_ACK: - { - UINT uiSearchRuleIndex = 0; - pstChangeIndication = (struct bcm_change_indication *)pstAddIndication; uiSearchRuleIndex = SearchSfid(Adapter, ntohl(pstChangeIndication->sfActiveSet.u32SFID)); if (uiSearchRuleIndex > NO_OF_QUEUES-1) BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "SF doesn't exist for which DSC_ACK is received"); - if ((uiSearchRuleIndex < NO_OF_QUEUES)) { + if (uiSearchRuleIndex < NO_OF_QUEUES) { Adapter->PackInfo[uiSearchRuleIndex].ucDirection = pstChangeIndication->u8Direction; if (pstChangeIndication->sfActiveSet.bValid == TRUE) Adapter->PackInfo[uiSearchRuleIndex].bActiveSet = TRUE; @@ -1849,13 +1835,8 @@ bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* PLength = sizeof(struct bcm_del_indication); *((struct bcm_del_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *((struct bcm_del_indication *)pstAddIndication); @@ -1872,12 +1853,10 @@ bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* caDsxReqResp[LEADER_SIZE]))->u8Type = DSD_RSP; CopyBufferToControlPacket(Adapter, (PVOID)Adapter->caDsxReqResp); - } + /* FALLTHROUGH */ case DSD_RSP: - { /* Do nothing as SF has already got Deleted */ - } - break; + break; case DSD_ACK: BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "DSD ACK Rcd, let App handle it\n"); break; diff --git a/drivers/staging/bcm/DDRInit.c b/drivers/staging/bcm/DDRInit.c index ed285b2d892d..f1d7cb82fd7e 100644 --- a/drivers/staging/bcm/DDRInit.c +++ b/drivers/staging/bcm/DDRInit.c @@ -3,7 +3,7 @@ #define DDR_DUMP_INTERNAL_DEVICE_MEMORY 0xBFC02B00 -#define MIPS_CLOCK_REG 0x0f000820 +#define MIPS_CLOCK_REG 0x0f000820 /* DDR INIT-133Mhz */ #define T3_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 12 /* index for 0x0F007000 */ @@ -818,13 +818,13 @@ int ddr_init(struct bcm_mini_adapter *Adapter) if ((Adapter->chip_id != BCS220_2) && (Adapter->chip_id != BCS220_2BC) && (Adapter->chip_id != BCS220_3)) { - retval = rdmalt(Adapter,(UINT)0x0f000830, &uiResetValue, sizeof(uiResetValue)); + retval = rdmalt(Adapter, (UINT)0x0f000830, &uiResetValue, sizeof(uiResetValue)); if (retval < 0) { BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); return retval; } uiResetValue |= 0x44; - retval = wrmalt(Adapter,(UINT)0x0f000830, &uiResetValue, sizeof(uiResetValue)); + retval = wrmalt(Adapter, (UINT)0x0f000830, &uiResetValue, sizeof(uiResetValue)); if (retval < 0) { BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); return retval; @@ -871,7 +871,7 @@ int ddr_init(struct bcm_mini_adapter *Adapter) case 0xbece0121: case 0xbece0130: case 0xbece0300: - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "DDR Setting: %x\n", Adapter->DDRSetting); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "DDR Setting: %x\n", Adapter->DDRSetting); switch (Adapter->DDRSetting) { case DDR_80_MHZ: psDDRSetting = asT3_DDRSetting80MHz; @@ -933,7 +933,7 @@ int ddr_init(struct bcm_mini_adapter *Adapter) } value = 0; - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Register Count is =%lu\n", RegCount); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Register Count is =%lu\n", RegCount); while (RegCount && !retval) { if (uiClockSetting && psDDRSetting->ulRegAddress == MIPS_CLOCK_REG) value = uiClockSetting; @@ -990,12 +990,12 @@ int ddr_init(struct bcm_mini_adapter *Adapter) * we will change this when we will have internal PMU. */ if (Adapter->PmuMode == HYBRID_MODE_7C) { - retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); + retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); if (retval < 0) { BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); return retval; } - retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); + retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); if (retval < 0) { BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); return retval; @@ -1006,12 +1006,12 @@ int ddr_init(struct bcm_mini_adapter *Adapter) BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); return retval; } - retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); + retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); if (retval < 0) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); return retval; } - retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); + retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); if (retval < 0) { BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); return retval; @@ -1024,12 +1024,12 @@ int ddr_init(struct bcm_mini_adapter *Adapter) } } else if (Adapter->PmuMode == HYBRID_MODE_6) { - retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); + retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); if (retval < 0) { BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); return retval; } - retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); + retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); if (retval < 0) { BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); return retval; @@ -1040,12 +1040,12 @@ int ddr_init(struct bcm_mini_adapter *Adapter) BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); return retval; } - retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); + retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); if (retval < 0) { BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); return retval; } - retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); + retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); if (retval < 0) { BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); return retval; @@ -1094,8 +1094,8 @@ int download_ddr_settings(struct bcm_mini_adapter *Adapter) RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ; psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ; break; - default: - return -EINVAL; + default: + return -EINVAL; } break; @@ -1215,7 +1215,7 @@ int download_ddr_settings(struct bcm_mini_adapter *Adapter) ul_ddr_setting_load_addr += sizeof(ULONG); if (!retval) { if (bOverrideSelfRefresh && (psDDRSetting->ulRegAddress == 0x0F007018)) { - value = (psDDRSetting->ulRegValue |(1<<8)); + value = (psDDRSetting->ulRegValue | (1<<8)); if (STATUS_SUCCESS != wrmalt(Adapter, ul_ddr_setting_load_addr, &value, sizeof(value))) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__); diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 94f32728f7c8..7c04c73e3bc8 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -1,5 +1,5 @@ #include "headers.h" - +#include static struct usb_device_id InterfaceUsbtable[] = { { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) }, { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) }, @@ -30,19 +30,22 @@ static void InterfaceAdapterFree(struct bcm_interface_adapter *psIntfAdapter) int i = 0; /* Wake up the wait_queue... */ - if (psIntfAdapter->psAdapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { + if (psIntfAdapter->psAdapter->LEDInfo.led_thread_running & + BCM_LED_THREAD_RUNNING_ACTIVELY) { psIntfAdapter->psAdapter->DriverState = DRIVER_HALT; wake_up(&psIntfAdapter->psAdapter->LEDInfo.notify_led_event); } reset_card_proc(psIntfAdapter->psAdapter); /* - * worst case time taken by the RDM/WRM will be 5 sec. will check after every 100 ms - * to accertain the device is not being accessed. After this No RDM/WRM should be made. + * worst case time taken by the RDM/WRM will be 5 sec. will check after + * every 100 ms to accertain the device is not being accessed. After + * this No RDM/WRM should be made. */ while (psIntfAdapter->psAdapter->DeviceAccess) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "Device is being accessed.\n"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, + DRV_ENTRY, DBG_LVL_ALL, + "Device is being accessed.\n"); msleep(100); } /* Free interrupt URB */ @@ -71,6 +74,7 @@ static void ConfigureEndPointTypesThroughEEPROM(struct bcm_mini_adapter *Adapter { u32 ulReg; int bytes; + struct bcm_interface_adapter *interfaceAdapter; /* Program EP2 MAX_PKT_SIZE */ ulReg = ntohl(EP2_MPS_REG); @@ -80,7 +84,9 @@ static void ConfigureEndPointTypesThroughEEPROM(struct bcm_mini_adapter *Adapter ulReg = ntohl(EP2_CFG_REG); BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x132, 4, TRUE); - if (((struct bcm_interface_adapter *)(Adapter->pvInterfaceAdapter))->bHighSpeedDevice == TRUE) { + interfaceAdapter = + (struct bcm_interface_adapter *)(Adapter->pvInterfaceAdapter); + if (interfaceAdapter->bHighSpeedDevice) { ulReg = ntohl(EP2_CFG_INT); BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE); } else { @@ -98,8 +104,8 @@ static void ConfigureEndPointTypesThroughEEPROM(struct bcm_mini_adapter *Adapter /* Program TX EP as interrupt(Alternate Setting) */ bytes = rdmalt(Adapter, 0x0F0110F8, &ulReg, sizeof(u32)); if (bytes < 0) { - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "reading of Tx EP failed\n"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, "reading of Tx EP failed\n"); return; } ulReg |= 0x6; @@ -150,7 +156,8 @@ static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_devi struct net_device *ndev; /* Reserve one extra queue for the bit-bucket */ - ndev = alloc_etherdev_mq(sizeof(struct bcm_mini_adapter), NO_OF_QUEUES+1); + ndev = alloc_etherdev_mq(sizeof(struct bcm_mini_adapter), + NO_OF_QUEUES + 1); if (ndev == NULL) { dev_err(&udev->dev, DRV_NAME ": no memory for device\n"); return -ENOMEM; @@ -169,13 +176,14 @@ static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_devi /* * Technically, one can start using BCM_DEBUG_PRINT after this point. - * However, realize that by default the Type/Subtype bitmaps are all zero now; - * so no prints will actually appear until the TestApp turns on debug paths via - * the ioctl(); so practically speaking, in early init, no logging happens. + * However, realize that by default the Type/Subtype bitmaps are all + * zero now; so no prints will actually appear until the TestApp turns + * on debug paths via the ioctl(); so practically speaking, in early + * init, no logging happens. * - * A solution (used below): we explicitly set the bitmaps to 1 for Type=DBG_TYPE_INITEXIT - * and ALL subtype's of the same. Now all bcm debug statements get logged, enabling debug - * during early init. + * A solution (used below): we explicitly set the bitmaps to 1 for + * Type=DBG_TYPE_INITEXIT and ALL subtype's of the same. Now all bcm + * debug statements get logged, enabling debug during early init. * Further, we turn this OFF once init_module() completes. */ @@ -191,7 +199,7 @@ static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_devi /* Allocate interface adapter structure */ psIntfAdapter = kzalloc(sizeof(struct bcm_interface_adapter), - GFP_KERNEL); + GFP_KERNEL); if (psIntfAdapter == NULL) { AdapterFree(psAdapter); return -ENOMEM; @@ -205,7 +213,7 @@ static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_devi usb_set_intfdata(intf, psIntfAdapter); BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "psIntfAdapter 0x%p\n", psIntfAdapter); + "psIntfAdapter 0x%p\n", psIntfAdapter); retval = InterfaceAdapterInit(psIntfAdapter); if (retval) { /* If the Firmware/Cfg File is not present @@ -213,12 +221,13 @@ static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_devi * download the files. */ if (-ENOENT == retval) { - BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "File Not Found. Use app to download.\n"); + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, + "File Not Found. Use app to download.\n"); return STATUS_SUCCESS; } - BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "InterfaceAdapterInit failed.\n"); + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, "InterfaceAdapterInit failed.\n"); usb_set_intfdata(intf, NULL); udev = interface_to_usbdev(intf); usb_put_dev(udev); @@ -228,7 +237,10 @@ static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_devi if (psAdapter->chip_id > T3) { uint32_t uiNackZeroLengthInt = 4; - retval = wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT, &uiNackZeroLengthInt, sizeof(uiNackZeroLengthInt)); + retval = + wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT, + &uiNackZeroLengthInt, + sizeof(uiNackZeroLengthInt)); if (retval) return retval; } @@ -242,9 +254,11 @@ static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_devi intf->needs_remote_wakeup = 1; usb_enable_autosuspend(udev); device_init_wakeup(&intf->dev, 1); - INIT_WORK(&psIntfAdapter->usbSuspendWork, putUsbSuspend); - BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "Enabling USB Auto-Suspend\n"); + INIT_WORK(&psIntfAdapter->usbSuspendWork, + putUsbSuspend); + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, + "Enabling USB Auto-Suspend\n"); #endif } else { intf->needs_remote_wakeup = 0; @@ -271,7 +285,7 @@ static void usbbcm_disconnect(struct usb_interface *intf) if (psAdapter->bDoSuspend) intf->needs_remote_wakeup = 0; - psAdapter->device_removed = TRUE ; + psAdapter->device_removed = TRUE; usb_set_intfdata(intf, NULL); InterfaceAdapterFree(psIntfAdapter); usb_put_dev(udev); @@ -285,8 +299,10 @@ static int AllocUsbCb(struct bcm_interface_adapter *psIntfAdapter) psIntfAdapter->asUsbTcb[i].urb = usb_alloc_urb(0, GFP_KERNEL); if (psIntfAdapter->asUsbTcb[i].urb == NULL) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, - "Can't allocate Tx urb for index %d\n", i); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_PRINTK, 0, 0, + "Can't allocate Tx urb for index %d\n", + i); return -ENOMEM; } } @@ -295,19 +311,25 @@ static int AllocUsbCb(struct bcm_interface_adapter *psIntfAdapter) psIntfAdapter->asUsbRcb[i].urb = usb_alloc_urb(0, GFP_KERNEL); if (psIntfAdapter->asUsbRcb[i].urb == NULL) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, - "Can't allocate Rx urb for index %d\n", i); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_PRINTK, 0, 0, + "Can't allocate Rx urb for index %d\n", + i); return -ENOMEM; } - psIntfAdapter->asUsbRcb[i].urb->transfer_buffer = kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL); + psIntfAdapter->asUsbRcb[i].urb->transfer_buffer = + kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL); if (psIntfAdapter->asUsbRcb[i].urb->transfer_buffer == NULL) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, - "Can't allocate Rx buffer for index %d\n", i); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_PRINTK, 0, 0, + "Can't allocate Rx buffer for index %d\n", + i); return -ENOMEM; } - psIntfAdapter->asUsbRcb[i].urb->transfer_buffer_length = MAX_DATA_BUFFER_SIZE; + psIntfAdapter->asUsbRcb[i].urb->transfer_buffer_length = + MAX_DATA_BUFFER_SIZE; } return 0; } @@ -322,24 +344,29 @@ static int device_run(struct bcm_interface_adapter *psIntfAdapter) pr_err(DRV_NAME "InitCardAndDownloadFirmware failed.\n"); return status; } - if (TRUE == psIntfAdapter->psAdapter->fw_download_done) { + if (psIntfAdapter->psAdapter->fw_download_done) { if (StartInterruptUrb(psIntfAdapter)) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "Cannot send interrupt in URB\n"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, + "Cannot send interrupt in URB\n"); } /* - * now register the cntrl interface. - * after downloading the f/w waiting for 5 sec to get the mailbox interrupt. + * now register the cntrl interface. after downloading the f/w + * waiting for 5 sec to get the mailbox interrupt. */ psIntfAdapter->psAdapter->waiting_to_fw_download_done = false; - value = wait_event_timeout(psIntfAdapter->psAdapter->ioctl_fw_dnld_wait_queue, - psIntfAdapter->psAdapter->waiting_to_fw_download_done, 5*HZ); + value = wait_event_timeout( + psIntfAdapter->psAdapter->ioctl_fw_dnld_wait_queue, + psIntfAdapter->psAdapter->waiting_to_fw_download_done, + 5 * HZ); if (value == 0) pr_err(DRV_NAME ": Timeout waiting for mailbox interrupt.\n"); - if (register_control_device_interface(psIntfAdapter->psAdapter) < 0) { + if (register_control_device_interface( + psIntfAdapter->psAdapter) < 0) { pr_err(DRV_NAME ": Register Control Device failed.\n"); return -EIO; } @@ -347,81 +374,6 @@ static int device_run(struct bcm_interface_adapter *psIntfAdapter) return 0; } - -static inline int bcm_usb_endpoint_num(const struct usb_endpoint_descriptor *epd) -{ - return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; -} - -static inline int bcm_usb_endpoint_type(const struct usb_endpoint_descriptor *epd) -{ - return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; -} - -static inline int bcm_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN); -} - -static inline int bcm_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); -} - -static inline int bcm_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_BULK); -} - -static inline int bcm_usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_CONTROL); -} - -static inline int bcm_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_INT); -} - -static inline int bcm_usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_ISOC); -} - -static inline int bcm_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd) -{ - return bcm_usb_endpoint_xfer_bulk(epd) && bcm_usb_endpoint_dir_in(epd); -} - -static inline int bcm_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) -{ - return bcm_usb_endpoint_xfer_bulk(epd) && bcm_usb_endpoint_dir_out(epd); -} - -static inline int bcm_usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd) -{ - return bcm_usb_endpoint_xfer_int(epd) && bcm_usb_endpoint_dir_in(epd); -} - -static inline int bcm_usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd) -{ - return bcm_usb_endpoint_xfer_int(epd) && bcm_usb_endpoint_dir_out(epd); -} - -static inline int bcm_usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd) -{ - return bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_in(epd); -} - -static inline int bcm_usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd) -{ - return bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_out(epd); -} - static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter) { struct usb_host_interface *iface_desc; @@ -429,23 +381,27 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter) size_t buffer_size; unsigned long value; int retval = 0; - int usedIntOutForBulkTransfer = 0 ; + int usedIntOutForBulkTransfer = 0; bool bBcm16 = false; UINT uiData = 0; int bytes; /* Store the usb dev into interface adapter */ - psIntfAdapter->udev = usb_get_dev(interface_to_usbdev(psIntfAdapter->interface)); + psIntfAdapter->udev = + usb_get_dev(interface_to_usbdev(psIntfAdapter->interface)); - psIntfAdapter->bHighSpeedDevice = (psIntfAdapter->udev->speed == USB_SPEED_HIGH); + psIntfAdapter->bHighSpeedDevice = + (psIntfAdapter->udev->speed == USB_SPEED_HIGH); psIntfAdapter->psAdapter->interface_rdm = BcmRDM; psIntfAdapter->psAdapter->interface_wrm = BcmWRM; bytes = rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG, - (u32 *)&(psIntfAdapter->psAdapter->chip_id), sizeof(u32)); + (u32 *) &(psIntfAdapter->psAdapter->chip_id), + sizeof(u32)); if (bytes < 0) { retval = bytes; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "CHIP ID Read Failed\n"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, + "CHIP ID Read Failed\n"); return retval; } @@ -453,81 +409,119 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter) psIntfAdapter->psAdapter->chip_id &= ~0xF0; dev_info(&psIntfAdapter->udev->dev, "RDM Chip ID 0x%lx\n", - psIntfAdapter->psAdapter->chip_id); + psIntfAdapter->psAdapter->chip_id); iface_desc = psIntfAdapter->interface->cur_altsetting; if (psIntfAdapter->psAdapter->chip_id == T3B) { - /* T3B device will have EEPROM, check if EEPROM is proper and BCM16 can be done or not. */ + /* T3B device will have EEPROM, check if EEPROM is proper and + * BCM16 can be done or not. */ BeceemEEPROMBulkRead(psIntfAdapter->psAdapter, &uiData, 0x0, 4); if (uiData == BECM) bBcm16 = TRUE; - dev_info(&psIntfAdapter->udev->dev, "number of alternate setting %d\n", - psIntfAdapter->interface->num_altsetting); + dev_info(&psIntfAdapter->udev->dev, + "number of alternate setting %d\n", + psIntfAdapter->interface->num_altsetting); if (bBcm16 == TRUE) { - /* selecting alternate setting one as a default setting for High Speed modem. */ + /* selecting alternate setting one as a default setting + * for High Speed modem. */ if (psIntfAdapter->bHighSpeedDevice) - retval = usb_set_interface(psIntfAdapter->udev, DEFAULT_SETTING_0, ALTERNATE_SETTING_1); - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "BCM16 is applicable on this dongle\n"); - if (retval || (psIntfAdapter->bHighSpeedDevice == false)) { - usedIntOutForBulkTransfer = EP2 ; + retval = usb_set_interface(psIntfAdapter->udev, + DEFAULT_SETTING_0, + ALTERNATE_SETTING_1); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, + "BCM16 is applicable on this dongle\n"); + if (retval || !psIntfAdapter->bHighSpeedDevice) { + usedIntOutForBulkTransfer = EP2; endpoint = &iface_desc->endpoint[EP2].desc; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "Interface altsetting failed or modem is configured to Full Speed, hence will work on default setting 0\n"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, + "Interface altsetting failed or modem is configured to Full Speed, hence will work on default setting 0\n"); /* - * If Modem is high speed device EP2 should be INT OUT End point - * If Mode is FS then EP2 should be bulk end point + * If Modem is high speed device EP2 should be + * INT OUT End point + * + * If Mode is FS then EP2 should be bulk end + * point */ - if (((psIntfAdapter->bHighSpeedDevice == TRUE) && (bcm_usb_endpoint_is_int_out(endpoint) == false)) - || ((psIntfAdapter->bHighSpeedDevice == false) && (bcm_usb_endpoint_is_bulk_out(endpoint) == false))) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "Configuring the EEPROM\n"); + if ((psIntfAdapter->bHighSpeedDevice && + !usb_endpoint_is_int_out(endpoint)) || + (!psIntfAdapter->bHighSpeedDevice && + !usb_endpoint_is_bulk_out(endpoint))) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, + DRV_ENTRY, DBG_LVL_ALL, + "Configuring the EEPROM\n"); /* change the EP2, EP4 to INT OUT end point */ - ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter); + ConfigureEndPointTypesThroughEEPROM( + psIntfAdapter->psAdapter); /* - * It resets the device and if any thing gets changed - * in USB descriptor it will show fail and re-enumerate - * the device + * It resets the device and if any thing + * gets changed in USB descriptor it + * will show fail and re-enumerate the + * device */ - retval = usb_reset_device(psIntfAdapter->udev); + retval = usb_reset_device( + psIntfAdapter->udev); if (retval) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "reset failed. Re-enumerating the device.\n"); - return retval ; + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, + DRV_ENTRY, + DBG_LVL_ALL, + "reset failed. Re-enumerating the device.\n"); + return retval; } } - if ((psIntfAdapter->bHighSpeedDevice == false) && bcm_usb_endpoint_is_bulk_out(endpoint)) { + if (!psIntfAdapter->bHighSpeedDevice && + usb_endpoint_is_bulk_out(endpoint)) { /* Once BULK is selected in FS mode. Revert it back to INT. Else USB_IF will fail. */ UINT _uiData = ntohl(EP2_CFG_INT); - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "Reverting Bulk to INT as it is in Full Speed mode.\n"); - BeceemEEPROMBulkWrite(psIntfAdapter->psAdapter, (PUCHAR)&_uiData, 0x136, 4, TRUE); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, + DRV_ENTRY, DBG_LVL_ALL, + "Reverting Bulk to INT as it is in Full Speed mode.\n"); + BeceemEEPROMBulkWrite( + psIntfAdapter->psAdapter, + (PUCHAR) & _uiData, + 0x136, 4, TRUE); } } else { - usedIntOutForBulkTransfer = EP4 ; + usedIntOutForBulkTransfer = EP4; endpoint = &iface_desc->endpoint[EP4].desc; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "Choosing AltSetting as a default setting.\n"); - if (bcm_usb_endpoint_is_int_out(endpoint) == false) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "Dongle does not have BCM16 Fix.\n"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, + "Choosing AltSetting as a default setting.\n"); + if (!usb_endpoint_is_int_out(endpoint)) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, + DRV_ENTRY, DBG_LVL_ALL, + "Dongle does not have BCM16 Fix.\n"); /* change the EP2, EP4 to INT OUT end point and use EP4 in altsetting */ - ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter); + ConfigureEndPointTypesThroughEEPROM( + psIntfAdapter->psAdapter); /* - * It resets the device and if any thing gets changed in - * USB descriptor it will show fail and re-enumerate the + * It resets the device and if any thing + * gets changed in USB descriptor it + * will show fail and re-enumerate the * device */ - retval = usb_reset_device(psIntfAdapter->udev); + retval = usb_reset_device( + psIntfAdapter->udev); if (retval) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "reset failed. Re-enumerating the device.\n"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, + DRV_ENTRY, + DBG_LVL_ALL, + "reset failed. Re-enumerating the device.\n"); return retval; } @@ -541,49 +535,69 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter) for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value) { endpoint = &iface_desc->endpoint[value].desc; - if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr && bcm_usb_endpoint_is_bulk_in(endpoint)) { + if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr && + usb_endpoint_is_bulk_in(endpoint)) { buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); psIntfAdapter->sBulkIn.bulk_in_size = buffer_size; - psIntfAdapter->sBulkIn.bulk_in_endpointAddr = endpoint->bEndpointAddress; - psIntfAdapter->sBulkIn.bulk_in_pipe = - usb_rcvbulkpipe(psIntfAdapter->udev, - psIntfAdapter->sBulkIn.bulk_in_endpointAddr); + psIntfAdapter->sBulkIn.bulk_in_endpointAddr = + endpoint->bEndpointAddress; + psIntfAdapter->sBulkIn.bulk_in_pipe = usb_rcvbulkpipe( + psIntfAdapter->udev, + psIntfAdapter->sBulkIn.bulk_in_endpointAddr); } - if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && bcm_usb_endpoint_is_bulk_out(endpoint)) { - psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress; - psIntfAdapter->sBulkOut.bulk_out_pipe = - usb_sndbulkpipe(psIntfAdapter->udev, + if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && + usb_endpoint_is_bulk_out(endpoint)) { + psIntfAdapter->sBulkOut.bulk_out_endpointAddr = + endpoint->bEndpointAddress; + psIntfAdapter->sBulkOut.bulk_out_pipe = usb_sndbulkpipe( + psIntfAdapter->udev, psIntfAdapter->sBulkOut.bulk_out_endpointAddr); } - if (!psIntfAdapter->sIntrIn.int_in_endpointAddr && bcm_usb_endpoint_is_int_in(endpoint)) { + if (!psIntfAdapter->sIntrIn.int_in_endpointAddr && + usb_endpoint_is_int_in(endpoint)) { buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); psIntfAdapter->sIntrIn.int_in_size = buffer_size; - psIntfAdapter->sIntrIn.int_in_endpointAddr = endpoint->bEndpointAddress; - psIntfAdapter->sIntrIn.int_in_interval = endpoint->bInterval; + psIntfAdapter->sIntrIn.int_in_endpointAddr = + endpoint->bEndpointAddress; + psIntfAdapter->sIntrIn.int_in_interval = + endpoint->bInterval; psIntfAdapter->sIntrIn.int_in_buffer = - kmalloc(buffer_size, GFP_KERNEL); + kmalloc(buffer_size, GFP_KERNEL); if (!psIntfAdapter->sIntrIn.int_in_buffer) return -EINVAL; } - if (!psIntfAdapter->sIntrOut.int_out_endpointAddr && bcm_usb_endpoint_is_int_out(endpoint)) { + if (!psIntfAdapter->sIntrOut.int_out_endpointAddr && + usb_endpoint_is_int_out(endpoint)) { if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && - (psIntfAdapter->psAdapter->chip_id == T3B) && (value == usedIntOutForBulkTransfer)) { + (psIntfAdapter->psAdapter->chip_id == T3B) && + (value == usedIntOutForBulkTransfer)) { /* use first intout end point as a bulk out end point */ - buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); - psIntfAdapter->sBulkOut.bulk_out_size = buffer_size; - psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress; - psIntfAdapter->sBulkOut.bulk_out_pipe = usb_sndintpipe(psIntfAdapter->udev, - psIntfAdapter->sBulkOut.bulk_out_endpointAddr); - psIntfAdapter->sBulkOut.int_out_interval = endpoint->bInterval; + buffer_size = + le16_to_cpu(endpoint->wMaxPacketSize); + psIntfAdapter->sBulkOut.bulk_out_size = + buffer_size; + psIntfAdapter->sBulkOut.bulk_out_endpointAddr = + endpoint->bEndpointAddress; + psIntfAdapter->sBulkOut.bulk_out_pipe = + usb_sndintpipe(psIntfAdapter->udev, + psIntfAdapter->sBulkOut + .bulk_out_endpointAddr); + psIntfAdapter->sBulkOut.int_out_interval = + endpoint->bInterval; } else if (value == EP6) { - buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); - psIntfAdapter->sIntrOut.int_out_size = buffer_size; - psIntfAdapter->sIntrOut.int_out_endpointAddr = endpoint->bEndpointAddress; - psIntfAdapter->sIntrOut.int_out_interval = endpoint->bInterval; - psIntfAdapter->sIntrOut.int_out_buffer = kmalloc(buffer_size, GFP_KERNEL); + buffer_size = + le16_to_cpu(endpoint->wMaxPacketSize); + psIntfAdapter->sIntrOut.int_out_size = + buffer_size; + psIntfAdapter->sIntrOut.int_out_endpointAddr = + endpoint->bEndpointAddress; + psIntfAdapter->sIntrOut.int_out_interval = + endpoint->bInterval; + psIntfAdapter->sIntrOut.int_out_buffer = + kmalloc(buffer_size, GFP_KERNEL); if (!psIntfAdapter->sIntrOut.int_out_buffer) return -EINVAL; } @@ -594,14 +608,14 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter) psIntfAdapter->psAdapter->bcm_file_download = InterfaceFileDownload; psIntfAdapter->psAdapter->bcm_file_readback_from_chip = - InterfaceFileReadbackFromChip; + InterfaceFileReadbackFromChip; psIntfAdapter->psAdapter->interface_transmit = InterfaceTransmitPacket; retval = CreateInterruptUrb(psIntfAdapter); if (retval) { BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, - "Cannot create interrupt urb\n"); + "Cannot create interrupt urb\n"); return retval; } @@ -618,17 +632,21 @@ static int InterfaceSuspend(struct usb_interface *intf, pm_message_t message) psIntfAdapter->bSuspended = TRUE; - if (TRUE == psIntfAdapter->bPreparingForBusSuspend) { + if (psIntfAdapter->bPreparingForBusSuspend) { psIntfAdapter->bPreparingForBusSuspend = false; if (psIntfAdapter->psAdapter->LinkStatus == LINKUP_DONE) { - psIntfAdapter->psAdapter->IdleMode = TRUE ; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "Host Entered in PMU Idle Mode.\n"); + psIntfAdapter->psAdapter->IdleMode = TRUE; + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, + "Host Entered in PMU Idle Mode.\n"); } else { psIntfAdapter->psAdapter->bShutStatus = TRUE; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, - "Host Entered in PMU Shutdown Mode.\n"); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, + "Host Entered in PMU Shutdown Mode.\n"); } } psIntfAdapter->psAdapter->bPreparingForLowPowerMode = false; diff --git a/drivers/staging/bcm/InterfaceIsr.c b/drivers/staging/bcm/InterfaceIsr.c index 7b39f4f5f1ab..b9f8a7aa24fe 100644 --- a/drivers/staging/bcm/InterfaceIsr.c +++ b/drivers/staging/bcm/InterfaceIsr.c @@ -4,108 +4,126 @@ static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/) { int status = urb->status; - struct bcm_interface_adapter *psIntfAdapter = (struct bcm_interface_adapter *)urb->context; - struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter ; + struct bcm_interface_adapter *psIntfAdapter = + (struct bcm_interface_adapter *)urb->context; + struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter; if (netif_msg_intr(Adapter)) pr_info(PFX "%s: interrupt status %d\n", - Adapter->dev->name, status); + Adapter->dev->name, status); - if(Adapter->device_removed == TRUE) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Device has Got Removed."); - return ; + if (Adapter->device_removed) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, + DBG_LVL_ALL, "Device has Got Removed."); + return; } - if(((Adapter->bPreparingForLowPowerMode == TRUE) && (Adapter->bDoSuspend == TRUE)) || - psIntfAdapter->bSuspended || - psIntfAdapter->bPreparingForBusSuspend) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Interrupt call back is called while suspending the device"); - return ; + if ((Adapter->bPreparingForLowPowerMode && Adapter->bDoSuspend) || + psIntfAdapter->bSuspended || + psIntfAdapter->bPreparingForBusSuspend) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, + DBG_LVL_ALL, + "Interrupt call back is called while suspending the device"); + return; } - //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "interrupt urb status %d", status); switch (status) { - /* success */ - case STATUS_SUCCESS: - if ( urb->actual_length ) - { + /* success */ + case STATUS_SUCCESS: + if (urb->actual_length) { - if(psIntfAdapter->ulInterruptData[1] & 0xFF) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL, "Got USIM interrupt"); + if (psIntfAdapter->ulInterruptData[1] & 0xFF) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + INTF_INIT, DBG_LVL_ALL, + "Got USIM interrupt"); } - if(psIntfAdapter->ulInterruptData[1] & 0xFF00) - { + if (psIntfAdapter->ulInterruptData[1] & 0xFF00) { atomic_set(&Adapter->CurrNumFreeTxDesc, - (psIntfAdapter->ulInterruptData[1] & 0xFF00) >> 8); - atomic_set (&Adapter->uiMBupdate, TRUE); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL, "TX mailbox contains %d", + (psIntfAdapter->ulInterruptData[1] & + 0xFF00) >> 8); + atomic_set(&Adapter->uiMBupdate, TRUE); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + INTF_INIT, DBG_LVL_ALL, + "TX mailbox contains %d", atomic_read(&Adapter->CurrNumFreeTxDesc)); } - if(psIntfAdapter->ulInterruptData[1] >> 16) - { - Adapter->CurrNumRecvDescs= + if (psIntfAdapter->ulInterruptData[1] >> 16) { + Adapter->CurrNumRecvDescs = (psIntfAdapter->ulInterruptData[1] >> 16); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"RX mailbox contains %d", - Adapter->CurrNumRecvDescs); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + INTF_INIT, DBG_LVL_ALL, + "RX mailbox contains %d", + Adapter->CurrNumRecvDescs); InterfaceRx(psIntfAdapter); } - if(Adapter->fw_download_done && + if (Adapter->fw_download_done && !Adapter->downloadDDR && - atomic_read(&Adapter->CurrNumFreeTxDesc)) - { - psIntfAdapter->psAdapter->downloadDDR +=1; + atomic_read(&Adapter->CurrNumFreeTxDesc)) { + + psIntfAdapter->psAdapter->downloadDDR += 1; wake_up(&Adapter->tx_packet_wait_queue); } - if(false == Adapter->waiting_to_fw_download_done) - { + if (!Adapter->waiting_to_fw_download_done) { Adapter->waiting_to_fw_download_done = TRUE; wake_up(&Adapter->ioctl_fw_dnld_wait_queue); } - if(!atomic_read(&Adapter->TxPktAvail)) - { + if (!atomic_read(&Adapter->TxPktAvail)) { atomic_set(&Adapter->TxPktAvail, 1); wake_up(&Adapter->tx_packet_wait_queue); } - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Firing interrupt in URB"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, + DBG_LVL_ALL, "Firing interrupt in URB"); } break; - case -ENOENT : - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"URB has got disconnected ...."); - return ; - } - case -EINPROGRESS: - { - //This situation may happened when URBunlink is used. for detail check usb_unlink_urb documentation. - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Impossibe condition has occurred... something very bad is going on"); - break ; - //return; - } - case -EPIPE: - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Interrupt IN endPoint has got halted/stalled...need to clear this"); - Adapter->bEndPointHalted = TRUE ; - wake_up(&Adapter->tx_packet_wait_queue); - urb->status = STATUS_SUCCESS ; - return; - } - /* software-driven interface shutdown */ - case -ECONNRESET: //URB got unlinked. - case -ESHUTDOWN: // hardware gone. this is the serious problem. - //Occurs only when something happens with the host controller device - case -ENODEV : //Device got removed - case -EINVAL : //Some thing very bad happened with the URB. No description is available. - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"interrupt urb error %d", status); - urb->status = STATUS_SUCCESS ; - break ; - //return; - default: - //This is required to check what is the defaults conditions when it occurs.. - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,"GOT DEFAULT INTERRUPT URB STATUS :%d..Please Analyze it...", status); + case -ENOENT: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, + DBG_LVL_ALL, "URB has got disconnected...."); + return; + case -EINPROGRESS: + /* + * This situation may happened when URBunlink is used. for + * detail check usb_unlink_urb documentation. + */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, + DBG_LVL_ALL, + "Impossibe condition has occurred... something very bad is going on"); + break; + /* return; */ + case -EPIPE: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, + DBG_LVL_ALL, + "Interrupt IN endPoint has got halted/stalled...need to clear this"); + Adapter->bEndPointHalted = TRUE; + wake_up(&Adapter->tx_packet_wait_queue); + urb->status = STATUS_SUCCESS; + return; + /* software-driven interface shutdown */ + case -ECONNRESET: /* URB got unlinked */ + case -ESHUTDOWN: /* hardware gone. this is the serious problem */ + /* + * Occurs only when something happens with the + * host controller device + */ + case -ENODEV: /* Device got removed */ + case -EINVAL: + /* + * Some thing very bad happened with the URB. No + * description is available. + */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, + DBG_LVL_ALL, "interrupt urb error %d", status); + urb->status = STATUS_SUCCESS; + break; + /* return; */ + default: + /* + * This is required to check what is the defaults conditions + * when it occurs.. + */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, + "GOT DEFAULT INTERRUPT URB STATUS :%d..Please Analyze it...", + status); break; } @@ -117,28 +135,30 @@ static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/) int CreateInterruptUrb(struct bcm_interface_adapter *psIntfAdapter) { psIntfAdapter->psInterruptUrb = usb_alloc_urb(0, GFP_KERNEL); - if (!psIntfAdapter->psInterruptUrb) - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Cannot allocate interrupt urb"); + if (!psIntfAdapter->psInterruptUrb) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, + INTF_INIT, DBG_LVL_ALL, + "Cannot allocate interrupt urb"); return -ENOMEM; } psIntfAdapter->psInterruptUrb->transfer_buffer = - psIntfAdapter->ulInterruptData; + psIntfAdapter->ulInterruptData; psIntfAdapter->psInterruptUrb->transfer_buffer_length = - sizeof(psIntfAdapter->ulInterruptData); + sizeof(psIntfAdapter->ulInterruptData); psIntfAdapter->sIntrIn.int_in_pipe = usb_rcvintpipe(psIntfAdapter->udev, - psIntfAdapter->sIntrIn.int_in_endpointAddr); + psIntfAdapter->sIntrIn.int_in_endpointAddr); usb_fill_int_urb(psIntfAdapter->psInterruptUrb, psIntfAdapter->udev, - psIntfAdapter->sIntrIn.int_in_pipe, - psIntfAdapter->psInterruptUrb->transfer_buffer, - psIntfAdapter->psInterruptUrb->transfer_buffer_length, - read_int_callback, psIntfAdapter, - psIntfAdapter->sIntrIn.int_in_interval); + psIntfAdapter->sIntrIn.int_in_pipe, + psIntfAdapter->psInterruptUrb->transfer_buffer, + psIntfAdapter->psInterruptUrb->transfer_buffer_length, + read_int_callback, psIntfAdapter, + psIntfAdapter->sIntrIn.int_in_interval); - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Interrupt Interval: %d\n", - psIntfAdapter->sIntrIn.int_in_interval); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, INTF_INIT, + DBG_LVL_ALL, "Interrupt Interval: %d\n", + psIntfAdapter->sIntrIn.int_in_interval); return 0; } @@ -147,19 +167,20 @@ INT StartInterruptUrb(struct bcm_interface_adapter *psIntfAdapter) { INT status = 0; - if( false == psIntfAdapter->psAdapter->device_removed && - false == psIntfAdapter->psAdapter->bEndPointHalted && - false == psIntfAdapter->bSuspended && - false == psIntfAdapter->bPreparingForBusSuspend && - false == psIntfAdapter->psAdapter->StopAllXaction) - { - status = usb_submit_urb(psIntfAdapter->psInterruptUrb, GFP_ATOMIC); - if (status) - { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Cannot send int urb %d\n", status); - if(status == -EPIPE) - { - psIntfAdapter->psAdapter->bEndPointHalted = TRUE ; + if (!(psIntfAdapter->psAdapter->device_removed || + psIntfAdapter->psAdapter->bEndPointHalted || + psIntfAdapter->bSuspended || + psIntfAdapter->bPreparingForBusSuspend || + psIntfAdapter->psAdapter->StopAllXaction)) { + status = + usb_submit_urb(psIntfAdapter->psInterruptUrb, GFP_ATOMIC); + if (status) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL, + "Cannot send inturb %d\n", status); + if (status == -EPIPE) { + psIntfAdapter->psAdapter->bEndPointHalted = + TRUE; wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue); } } diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c index 0727599bf5fa..4f315835ddfc 100644 --- a/drivers/staging/bcm/Qos.c +++ b/drivers/staging/bcm/Qos.c @@ -222,10 +222,7 @@ static USHORT IpVersion4(struct bcm_mini_adapter *Adapter, //Checking classifier validity if (!pstClassifierRule->bUsed || pstClassifierRule->ucDirection == DOWNLINK_DIR) - { - bClassificationSucceed = false; break; - } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "is IPv6 check!"); if (pstClassifierRule->bIpv6Protocol) @@ -233,51 +230,47 @@ static USHORT IpVersion4(struct bcm_mini_adapter *Adapter, //**************Checking IP header parameter**************************// BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Trying to match Source IP Address"); - if (false == (bClassificationSucceed = - MatchSrcIpAddress(pstClassifierRule, iphd->saddr))) + if (!MatchSrcIpAddress(pstClassifierRule, iphd->saddr)) break; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source IP Address Matched"); - if (false == (bClassificationSucceed = - MatchDestIpAddress(pstClassifierRule, iphd->daddr))) + if (!MatchDestIpAddress(pstClassifierRule, iphd->daddr)) break; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination IP Address Matched"); - if (false == (bClassificationSucceed = - MatchTos(pstClassifierRule, iphd->tos))) - { + if (!MatchTos(pstClassifierRule, iphd->tos)) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "TOS Match failed\n"); break; } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "TOS Matched"); - if (false == (bClassificationSucceed = - MatchProtocol(pstClassifierRule, iphd->protocol))) + if (!MatchProtocol(pstClassifierRule, iphd->protocol)) break; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol Matched"); //if protocol is not TCP or UDP then no need of comparing source port and destination port - if (iphd->protocol != TCP && iphd->protocol != UDP) + if (iphd->protocol != TCP && iphd->protocol != UDP) { + bClassificationSucceed = TRUE; break; + } //******************Checking Transport Layer Header field if present *****************// BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source Port %04x", (iphd->protocol == UDP) ? xprt_hdr->uhdr.source : xprt_hdr->thdr.source); - if (false == (bClassificationSucceed = - MatchSrcPort(pstClassifierRule, - ntohs((iphd->protocol == UDP) ? - xprt_hdr->uhdr.source : xprt_hdr->thdr.source)))) + if (!MatchSrcPort(pstClassifierRule, + ntohs((iphd->protocol == UDP) ? + xprt_hdr->uhdr.source : xprt_hdr->thdr.source))) break; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Port Matched"); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Port %04x", (iphd->protocol == UDP) ? xprt_hdr->uhdr.dest : xprt_hdr->thdr.dest); - if (false == (bClassificationSucceed = - MatchDestPort(pstClassifierRule, - ntohs((iphd->protocol == UDP) ? - xprt_hdr->uhdr.dest : xprt_hdr->thdr.dest)))) + if (!MatchDestPort(pstClassifierRule, + ntohs((iphd->protocol == UDP) ? + xprt_hdr->uhdr.dest : xprt_hdr->thdr.dest))) break; + bClassificationSucceed = TRUE; } while (0); if (TRUE == bClassificationSucceed) diff --git a/drivers/staging/bcm/Typedefs.h b/drivers/staging/bcm/Typedefs.h index 832adcfd1e3a..90b3b25dd606 100644 --- a/drivers/staging/bcm/Typedefs.h +++ b/drivers/staging/bcm/Typedefs.h @@ -25,16 +25,16 @@ typedef unsigned int B_UINT32; typedef unsigned long ULONG; typedef unsigned long DWORD; -typedef char* PCHAR; -typedef short* PSHORT; -typedef int* PINT; -typedef long* PLONG; -typedef void* PVOID; +typedef char *PCHAR; +typedef short *PSHORT; +typedef int *PINT; +typedef long *PLONG; +typedef void *PVOID; -typedef unsigned char* PUCHAR; -typedef unsigned short* PUSHORT; -typedef unsigned int* PUINT; -typedef unsigned long* PULONG; +typedef unsigned char *PUCHAR; +typedef unsigned short *PUSHORT; +typedef unsigned int *PUINT; +typedef unsigned long *PULONG; typedef unsigned long long ULONG64; typedef unsigned long long LARGE_INTEGER; typedef unsigned int UINT32; @@ -43,5 +43,5 @@ typedef unsigned int UINT32; #endif -#endif //__TYPEDEFS_H__ +#endif /* __TYPEDEFS_H__ */ diff --git a/drivers/staging/bcm/headers.h b/drivers/staging/bcm/headers.h index 7fd21c6923cb..6f3270cc4176 100644 --- a/drivers/staging/bcm/headers.h +++ b/drivers/staging/bcm/headers.h @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include "Typedefs.h" diff --git a/drivers/staging/bcm/hostmibs.c b/drivers/staging/bcm/hostmibs.c index f55300db1d48..39ace5510c43 100644 --- a/drivers/staging/bcm/hostmibs.c +++ b/drivers/staging/bcm/hostmibs.c @@ -27,9 +27,9 @@ INT ProcessGetHostMibs(struct bcm_mini_adapter *Adapter, struct bcm_host_stats_m /* Copy the classifier Table */ for (nClassifierIndex = 0; nClassifierIndex < MAX_CLASSIFIERS; nClassifierIndex++) { if (Adapter->astClassifierTable[nClassifierIndex].bUsed == TRUE) - memcpy((PVOID) & pstHostMibs-> + memcpy((PVOID) &pstHostMibs-> astClassifierTable[nClassifierIndex], - (PVOID) & Adapter-> + (PVOID) &Adapter-> astClassifierTable[nClassifierIndex], sizeof(struct bcm_mibs_classifier_rule)); } @@ -37,8 +37,8 @@ INT ProcessGetHostMibs(struct bcm_mini_adapter *Adapter, struct bcm_host_stats_m /* Copy the SF Table */ for (nSfIndex = 0; nSfIndex < NO_OF_QUEUES; nSfIndex++) { if (Adapter->PackInfo[nSfIndex].bValid) { - memcpy((PVOID) & pstHostMibs->astSFtable[nSfIndex], - (PVOID) & Adapter->PackInfo[nSfIndex], + memcpy((PVOID) &pstHostMibs->astSFtable[nSfIndex], + (PVOID) &Adapter->PackInfo[nSfIndex], sizeof(struct bcm_mibs_table)); } else { /* If index in not valid, diff --git a/drivers/staging/bcm/nvm.c b/drivers/staging/bcm/nvm.c index fca164f51f4b..63be3be62ebd 100644 --- a/drivers/staging/bcm/nvm.c +++ b/drivers/staging/bcm/nvm.c @@ -122,7 +122,7 @@ static UCHAR ReadEEPROMStatusRegister(struct bcm_mini_adapter *Adapter) * OSAL_STATUS_CODE: */ -int ReadBeceemEEPROMBulk(struct bcm_mini_adapter *Adapter, +static int ReadBeceemEEPROMBulk(struct bcm_mini_adapter *Adapter, DWORD dwAddress, DWORD *pdwData, DWORD dwNumWords) @@ -2698,7 +2698,7 @@ int BcmGetSectionValStartOffset(struct bcm_mini_adapter *Adapter, enum bcm_flash * On Failure -returns STATUS_FAILURE */ -int BcmGetSectionValEndOffset(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlash2xSectionVal) +static int BcmGetSectionValEndOffset(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlash2xSectionVal) { int SectEndOffset = 0; @@ -2980,7 +2980,7 @@ static int BcmGetActiveISO(struct bcm_mini_adapter *Adapter) * */ -B_UINT8 IsOffsetWritable(struct bcm_mini_adapter *Adapter, unsigned int uiOffset) +static B_UINT8 IsOffsetWritable(struct bcm_mini_adapter *Adapter, unsigned int uiOffset) { unsigned int uiSectorNum = 0; unsigned int uiWordOfSectorPermission = 0; @@ -3374,7 +3374,7 @@ int BcmSetActiveSection(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_secti case DSD2: if (ReadDSDSignature(Adapter, eFlash2xSectVal) == DSD_IMAGE_MAGIC_NUMBER) { HighestPriDSD = getHighestPriDSD(Adapter); - if ((HighestPriDSD == eFlash2xSectVal)) { + if (HighestPriDSD == eFlash2xSectVal) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Given DSD<%x> already has highest priority", eFlash2xSectVal); Status = STATUS_SUCCESS; break; @@ -3402,7 +3402,7 @@ int BcmSetActiveSection(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_secti HighestPriDSD = getHighestPriDSD(Adapter); - if ((HighestPriDSD == eFlash2xSectVal)) { + if (HighestPriDSD == eFlash2xSectVal) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Made the DSD: %x highest by reducing priority of other\n", eFlash2xSectVal); Status = STATUS_SUCCESS; break; @@ -3421,7 +3421,7 @@ int BcmSetActiveSection(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_secti } HighestPriDSD = getHighestPriDSD(Adapter); - if ((HighestPriDSD == eFlash2xSectVal)) { + if (HighestPriDSD == eFlash2xSectVal) { Status = STATUS_SUCCESS; break; } @@ -4074,7 +4074,7 @@ int BcmCopySection(struct bcm_mini_adapter *Adapter, * Faillure :- Return negative error code */ -int SaveHeaderIfPresent(struct bcm_mini_adapter *Adapter, PUCHAR pBuff, unsigned int uiOffset) +static int SaveHeaderIfPresent(struct bcm_mini_adapter *Adapter, PUCHAR pBuff, unsigned int uiOffset) { unsigned int offsetToProtect = 0, HeaderSizeToProtect = 0; bool bHasHeader = false; @@ -4213,7 +4213,7 @@ static int BcmDoChipSelect(struct bcm_mini_adapter *Adapter, unsigned int offset return STATUS_SUCCESS; } -int ReadDSDSignature(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val dsd) +static int ReadDSDSignature(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val dsd) { unsigned int uiDSDsig = 0; /* unsigned int sigoffsetInMap = 0; @@ -4238,7 +4238,7 @@ int ReadDSDSignature(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_ return uiDSDsig; } -int ReadDSDPriority(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val dsd) +static int ReadDSDPriority(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val dsd) { /* unsigned int priOffsetInMap = 0 ; */ unsigned int uiDSDPri = STATUS_FAILURE; @@ -4261,7 +4261,7 @@ int ReadDSDPriority(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_v return uiDSDPri; } -enum bcm_flash2x_section_val getHighestPriDSD(struct bcm_mini_adapter *Adapter) +static enum bcm_flash2x_section_val getHighestPriDSD(struct bcm_mini_adapter *Adapter) { int DSDHighestPri = STATUS_FAILURE; int DsdPri = 0; @@ -4293,7 +4293,7 @@ enum bcm_flash2x_section_val getHighestPriDSD(struct bcm_mini_adapter *Adapter) return HighestPriDSD; } -int ReadISOSignature(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val iso) +static int ReadISOSignature(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val iso) { unsigned int uiISOsig = 0; /* unsigned int sigoffsetInMap = 0; @@ -4316,7 +4316,7 @@ int ReadISOSignature(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_ return uiISOsig; } -int ReadISOPriority(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val iso) +static int ReadISOPriority(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val iso) { unsigned int ISOPri = STATUS_FAILURE; if (IsSectionWritable(Adapter, iso)) { @@ -4335,7 +4335,7 @@ int ReadISOPriority(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_v return ISOPri; } -enum bcm_flash2x_section_val getHighestPriISO(struct bcm_mini_adapter *Adapter) +static enum bcm_flash2x_section_val getHighestPriISO(struct bcm_mini_adapter *Adapter) { int ISOHighestPri = STATUS_FAILURE; int ISOPri = 0; @@ -4359,7 +4359,7 @@ enum bcm_flash2x_section_val getHighestPriISO(struct bcm_mini_adapter *Adapter) return HighestPriISO; } -int WriteToFlashWithoutSectorErase(struct bcm_mini_adapter *Adapter, +static int WriteToFlashWithoutSectorErase(struct bcm_mini_adapter *Adapter, PUINT pBuff, enum bcm_flash2x_section_val eFlash2xSectionVal, unsigned int uiOffset, @@ -4472,7 +4472,7 @@ bool IsSectionExistInFlash(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_se return SectionPresent; } -int IsSectionWritable(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val Section) +static int IsSectionWritable(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val Section) { int offset = STATUS_FAILURE; int Status = false; diff --git a/drivers/staging/ced1401/ced_ioc.c b/drivers/staging/ced1401/ced_ioc.c index bf532b1bd345..ebbc5090f219 100644 --- a/drivers/staging/ced1401/ced_ioc.c +++ b/drivers/staging/ced1401/ced_ioc.c @@ -38,8 +38,8 @@ ****************************************************************************/ static void FlushOutBuff(DEVICE_EXTENSION *pdx) { - dev_dbg(&pdx->interface->dev, "%s currentState=%d", __func__, - pdx->sCurrentState); + dev_dbg(&pdx->interface->dev, "%s: currentState=%d\n", + __func__, pdx->sCurrentState); if (pdx->sCurrentState == U14ERR_TIME) /* Do nothing if hardware in trouble */ return; /* Kill off any pending I/O */ @@ -59,8 +59,8 @@ static void FlushOutBuff(DEVICE_EXTENSION *pdx) ****************************************************************************/ static void FlushInBuff(DEVICE_EXTENSION *pdx) { - dev_dbg(&pdx->interface->dev, "%s currentState=%d", __func__, - pdx->sCurrentState); + dev_dbg(&pdx->interface->dev, "%s: currentState=%d\n", + __func__, pdx->sCurrentState); if (pdx->sCurrentState == U14ERR_TIME) /* Do nothing if hardware in trouble */ return; /* Kill off any pending I/O */ @@ -118,8 +118,8 @@ int SendString(DEVICE_EXTENSION *pdx, const char __user *pData, mutex_lock(&pdx->io_mutex); /* Protect disconnect from new i/o */ if (n > 0) { /* do nothing if nowt to do! */ - dev_dbg(&pdx->interface->dev, "%s n=%d>%s<", __func__, n, - buffer); + dev_dbg(&pdx->interface->dev, "%s: n=%d>%s<\n", + __func__, n, buffer); iReturn = PutChars(pdx, buffer, n); } @@ -139,7 +139,7 @@ int SendChar(DEVICE_EXTENSION *pdx, char c) int iReturn; mutex_lock(&pdx->io_mutex); /* Protect disconnect from new i/o */ iReturn = PutChars(pdx, &c, 1); - dev_dbg(&pdx->interface->dev, "SendChar >%c< (0x%02x)", c, c); + dev_dbg(&pdx->interface->dev, "SendChar >%c< (0x%02x)\n", c, c); Allowi(pdx); /* Make sure char reads are running */ mutex_unlock(&pdx->io_mutex); return iReturn; @@ -174,7 +174,7 @@ int SendChar(DEVICE_EXTENSION *pdx, char c) int Get1401State(DEVICE_EXTENSION *pdx, __u32 *state, __u32 *error) { int nGot; - dev_dbg(&pdx->interface->dev, "Get1401State() entry"); + dev_dbg(&pdx->interface->dev, "%s: entry\n", __func__); *state = 0xFFFFFFFF; /* Start off with invalid state */ nGot = usb_control_msg(pdx->udev, usb_rcvctrlpipe(pdx->udev, 0), @@ -182,15 +182,15 @@ int Get1401State(DEVICE_EXTENSION *pdx, __u32 *state, __u32 *error) pdx->statBuf, sizeof(pdx->statBuf), HZ); if (nGot != sizeof(pdx->statBuf)) { dev_err(&pdx->interface->dev, - "Get1401State() FAILED, return code %d", nGot); + "%s: FAILED, return code %d\n", __func__, nGot); pdx->sCurrentState = U14ERR_TIME; /* Indicate that things are very wrong indeed */ *state = 0; /* Force status values to a known state */ *error = 0; } else { int nDevice; dev_dbg(&pdx->interface->dev, - "Get1401State() Success, state: 0x%x, 0x%x", - pdx->statBuf[0], pdx->statBuf[1]); + "%s: Success, state: 0x%x, 0x%x\n", + __func__, pdx->statBuf[0], pdx->statBuf[1]); *state = pdx->statBuf[0]; /* Return the state values to the calling code */ *error = pdx->statBuf[1]; @@ -220,8 +220,8 @@ int Get1401State(DEVICE_EXTENSION *pdx, __u32 *state, __u32 *error) ****************************************************************************/ int ReadWrite_Cancel(DEVICE_EXTENSION *pdx) { - dev_dbg(&pdx->interface->dev, "ReadWrite_Cancel entry %d", - pdx->bStagedUrbPending); + dev_dbg(&pdx->interface->dev, "%s: entry %d\n", + __func__, pdx->bStagedUrbPending); #ifdef NOT_WRITTEN_YET int ntStatus = STATUS_SUCCESS; bool bResult = false; @@ -231,7 +231,7 @@ int ReadWrite_Cancel(DEVICE_EXTENSION *pdx) if (pdx->bStagedUrbPending) { /* anything to be cancelled? May need more... */ dev_info(&pdx->interface - dev, - "ReadWrite_Cancel about to cancel Urb"); + "ReadWrite_Cancel about to cancel Urb\n"); /* Clear the staging done flag */ /* KeClearEvent(&pdx->StagingDoneEvent); */ USB_ASSERT(pdx->pStagedIrp != NULL); @@ -244,14 +244,14 @@ int ReadWrite_Cancel(DEVICE_EXTENSION *pdx) LARGE_INTEGER timeout; timeout.QuadPart = -10000000; /* Use a timeout of 1 second */ dev_info(&pdx->interface - dev, - "ReadWrite_Cancel about to wait till done"); + "%s: about to wait till done\n", __func__); ntStatus = KeWaitForSingleObject(&pdx->StagingDoneEvent, Executive, KernelMode, FALSE, &timeout); } else { dev_info(&pdx->interface - dev, - "ReadWrite_Cancel, cancellation failed"); + "%s: cancellation failed\n", __func__); ntStatus = U14ERR_FAIL; } USB_KdPrint(DBGLVL_DEFAULT, @@ -260,7 +260,7 @@ int ReadWrite_Cancel(DEVICE_EXTENSION *pdx) } else spin_unlock_irq(&pdx->stagedLock); - dev_info(&pdx->interface - dev, "ReadWrite_Cancel done"); + dev_info(&pdx->interface - dev, "%s: done\n", __func__); return ntStatus; #else return U14ERR_NOERROR; @@ -304,7 +304,7 @@ static int InSelfTest(DEVICE_EXTENSION *pdx, unsigned int *pState) bool Is1401(DEVICE_EXTENSION *pdx) { int iReturn; - dev_dbg(&pdx->interface->dev, "%s", __func__); + dev_dbg(&pdx->interface->dev, "%s\n", __func__); ced_draw_down(pdx); /* wait for, then kill outstanding Urbs */ FlushInBuff(pdx); /* Clear out input buffer & pipe */ @@ -368,7 +368,7 @@ bool QuickCheck(DEVICE_EXTENSION *pdx, bool bTestBuff, bool bCanReset) (pdx->sCurrentState >= U14ERR_STD)); /* No 1401 errors stored */ dev_dbg(&pdx->interface->dev, - "%s DMAFlag:%d, state:%d, force:%d, testBuff:%d, short:%d", + "%s: DMAFlag:%d, state:%d, force:%d, testBuff:%d, short:%d\n", __func__, pdx->dwDMAFlag, pdx->sCurrentState, pdx->bForceReset, bTestBuff, bShortTest); @@ -376,13 +376,13 @@ bool QuickCheck(DEVICE_EXTENSION *pdx, bool bTestBuff, bool bCanReset) (pdx->dwNumInput || pdx->dwNumOutput)) { /* ...characters were in the buffer? */ bShortTest = false; /* Then do the full test */ dev_dbg(&pdx->interface->dev, - "%s will reset as buffers not empty", __func__); + "%s: will reset as buffers not empty\n", __func__); } if (bShortTest || !bCanReset) { /* Still OK to try the short test? */ /* Always test if no reset - we want state update */ unsigned int state, error; - dev_dbg(&pdx->interface->dev, "%s->Get1401State", __func__); + dev_dbg(&pdx->interface->dev, "%s: Get1401State\n", __func__); if (Get1401State(pdx, &state, &error) == U14ERR_NOERROR) { /* Check on the 1401 state */ if ((state & 0xFF) == 0) /* If call worked, check the status value */ bRet = true; /* If that was zero, all is OK, no reset needed */ @@ -390,7 +390,7 @@ bool QuickCheck(DEVICE_EXTENSION *pdx, bool bTestBuff, bool bCanReset) } if (!bRet && bCanReset) { /* If all not OK, then */ - dev_info(&pdx->interface->dev, "%s->Is1401 %d %d %d %d", + dev_info(&pdx->interface->dev, "%s: Is1401 %d %d %d %d\n", __func__, bShortTest, pdx->sCurrentState, bTestBuff, pdx->bForceReset); bRet = Is1401(pdx); /* do full test */ @@ -407,7 +407,8 @@ bool QuickCheck(DEVICE_EXTENSION *pdx, bool bTestBuff, bool bCanReset) int Reset1401(DEVICE_EXTENSION *pdx) { mutex_lock(&pdx->io_mutex); /* Protect disconnect from new i/o */ - dev_dbg(&pdx->interface->dev, "ABout to call QuickCheck"); + dev_dbg(&pdx->interface->dev, "%s: About to call QuickCheck\n", + __func__); QuickCheck(pdx, true, true); /* Check 1401, reset if not OK */ mutex_unlock(&pdx->io_mutex); return U14ERR_NOERROR; @@ -423,7 +424,7 @@ int GetChar(DEVICE_EXTENSION *pdx) int iReturn = U14ERR_NOIN; /* assume we will get nothing */ mutex_lock(&pdx->io_mutex); /* Protect disconnect from new i/o */ - dev_dbg(&pdx->interface->dev, "GetChar"); + dev_dbg(&pdx->interface->dev, "%s\n", __func__); Allowi(pdx); /* Make sure char reads are running */ SendChars(pdx); /* and send any buffered chars */ @@ -497,8 +498,8 @@ int GetString(DEVICE_EXTENSION *pdx, char __user *pUser, int n) pdx->dwNumInput -= nGot; spin_unlock_irq(&pdx->charInLock); - dev_dbg(&pdx->interface->dev, - "GetString read %d characters >%s<", nGot, buffer); + dev_dbg(&pdx->interface->dev, "%s: read %d characters >%s<\n", + __func__, nGot, buffer); if (copy_to_user(pUser, buffer, nCopyToUser)) iReturn = -EFAULT; else @@ -555,7 +556,7 @@ int LineCount(DEVICE_EXTENSION *pdx) } spin_unlock_irq(&pdx->charInLock); - dev_dbg(&pdx->interface->dev, "LineCount returned %d", iReturn); + dev_dbg(&pdx->interface->dev, "%s: returned %d\n", __func__, iReturn); mutex_unlock(&pdx->io_mutex); /* Protect disconnect from new i/o */ return iReturn; } @@ -571,7 +572,7 @@ int GetOutBufSpace(DEVICE_EXTENSION *pdx) mutex_lock(&pdx->io_mutex); /* Protect disconnect from new i/o */ SendChars(pdx); /* send any buffered chars */ iReturn = (int)(OUTBUF_SZ - pdx->dwNumOutput); /* no lock needed for single read */ - dev_dbg(&pdx->interface->dev, "OutBufSpace %d", iReturn); + dev_dbg(&pdx->interface->dev, "%s: %d\n", __func__, iReturn); mutex_unlock(&pdx->io_mutex); /* Protect disconnect from new i/o */ return iReturn; } @@ -589,7 +590,7 @@ int ClearArea(DEVICE_EXTENSION *pdx, int nArea) if ((nArea < 0) || (nArea >= MAX_TRANSAREAS)) { iReturn = U14ERR_BADAREA; - dev_err(&pdx->interface->dev, "%s Attempt to clear area %d", + dev_err(&pdx->interface->dev, "%s: Attempt to clear area %d\n", __func__, nArea); } else { TRANSAREA *pTA = &pdx->rTransDef[nArea]; /* to save typing */ @@ -602,14 +603,14 @@ int ClearArea(DEVICE_EXTENSION *pdx, int nArea) int nPages = 0; /* and number of pages */ int np; - dev_dbg(&pdx->interface->dev, "%s area %d", __func__, - nArea); + dev_dbg(&pdx->interface->dev, "%s: area %d\n", + __func__, nArea); spin_lock_irq(&pdx->stagedLock); if ((pdx->StagedId == nArea) && (pdx->dwDMAFlag > MODE_CHAR)) { iReturn = U14ERR_UNLOCKFAIL; /* cannot delete as in use */ dev_err(&pdx->interface->dev, - "%s call on area %d while active", + "%s: call on area %d while active\n", __func__, nArea); } else { pPages = pTA->pPages; /* save page address list */ @@ -633,7 +634,7 @@ int ClearArea(DEVICE_EXTENSION *pdx, int nArea) /* Now we must undo the pinning down of the pages. We will assume the worst and mark */ /* all the pages as dirty. Don't be tempted to move this up above as you must not be */ /* holding a spin lock to do this stuff as it is not atomic. */ - dev_dbg(&pdx->interface->dev, "%s nPages=%d", + dev_dbg(&pdx->interface->dev, "%s: nPages=%d\n", __func__, nPages); for (np = 0; np < nPages; ++np) { @@ -645,7 +646,7 @@ int ClearArea(DEVICE_EXTENSION *pdx, int nArea) kfree(pPages); dev_dbg(&pdx->interface->dev, - "%s kfree(pPages) done", __func__); + "%s: kfree(pPages) done\n", __func__); } } } @@ -687,12 +688,12 @@ static int SetArea(DEVICE_EXTENSION *pdx, int nArea, char __user *puBuf, iReturn = U14ERR_NOMEMORY; goto error; } - dev_dbg(&pdx->interface->dev, "%s %p, length=%06x, circular %d", + dev_dbg(&pdx->interface->dev, "%s: %p, length=%06x, circular %d\n", __func__, puBuf, dwLength, bCircular); /* To pin down user pages we must first acquire the mapping semaphore. */ nPages = get_user_pages_fast(ulStart, len, 1, pPages); - dev_dbg(&pdx->interface->dev, "%s nPages = %d", __func__, nPages); + dev_dbg(&pdx->interface->dev, "%s: nPages = %d\n", __func__, nPages); if (nPages > 0) { /* if we succeeded */ /* If you are tempted to use page_address (form LDD3), forget it. You MUST use */ @@ -735,17 +736,17 @@ error: ** unset it. Unsetting will fail if the area is booked, and a transfer to that ** area is in progress. Otherwise, we will release the area and re-assign it. ****************************************************************************/ -int SetTransfer(DEVICE_EXTENSION *pdx, TRANSFERDESC __user *pTD) +int SetTransfer(DEVICE_EXTENSION *pdx, struct transfer_area_desc __user *pTD) { int iReturn; - TRANSFERDESC td; + struct transfer_area_desc td; if (copy_from_user(&td, pTD, sizeof(td))) return -EFAULT; mutex_lock(&pdx->io_mutex); - dev_dbg(&pdx->interface->dev, "%s area:%d, size:%08x", __func__, - td.wAreaNum, td.dwLength); + dev_dbg(&pdx->interface->dev, "%s: area:%d, size:%08x\n", + __func__, td.wAreaNum, td.dwLength); /* The strange cast is done so that we don't get warnings in 32-bit linux about the size of the */ /* pointer. The pointer is always passed as a 64-bit object so that we don't have problems using */ /* a 32-bit program on a 64-bit system. unsigned long is 64-bits on a 64-bit system. */ @@ -778,10 +779,10 @@ int UnsetTransfer(DEVICE_EXTENSION *pdx, int nArea) ** pretend that whatever the user asked for was achieved, so we return 1 if ** try to create one, and 0 if they ask to remove (assuming all else was OK). ****************************************************************************/ -int SetEvent(DEVICE_EXTENSION *pdx, TRANSFEREVENT __user *pTE) +int SetEvent(DEVICE_EXTENSION *pdx, struct transfer_event __user *pTE) { int iReturn = U14ERR_NOERROR; - TRANSFEREVENT te; + struct transfer_event te; /* get a local copy of the data */ if (copy_from_user(&te, pTE, sizeof(te))) @@ -922,7 +923,7 @@ int GetTransfer(DEVICE_EXTENSION *pdx, TGET_TX_BLOCK __user *pTX) ****************************************************************************/ int KillIO1401(DEVICE_EXTENSION *pdx) { - dev_dbg(&pdx->interface->dev, "%s", __func__); + dev_dbg(&pdx->interface->dev, "%s\n", __func__); mutex_lock(&pdx->io_mutex); FlushOutBuff(pdx); FlushInBuff(pdx); @@ -938,7 +939,7 @@ int KillIO1401(DEVICE_EXTENSION *pdx) int BlkTransState(DEVICE_EXTENSION *pdx) { int iReturn = pdx->dwDMAFlag != MODE_CHAR; - dev_dbg(&pdx->interface->dev, "%s = %d", __func__, iReturn); + dev_dbg(&pdx->interface->dev, "%s: %d\n", __func__, iReturn); return iReturn; } @@ -956,7 +957,7 @@ int StateOf1401(DEVICE_EXTENSION *pdx) iReturn = pdx->sCurrentState; mutex_unlock(&pdx->io_mutex); - dev_dbg(&pdx->interface->dev, "%s = %d", __func__, iReturn); + dev_dbg(&pdx->interface->dev, "%s: %d\n", __func__, iReturn); return iReturn; } @@ -971,7 +972,7 @@ int StartSelfTest(DEVICE_EXTENSION *pdx) { int nGot; mutex_lock(&pdx->io_mutex); - dev_dbg(&pdx->interface->dev, "%s", __func__); + dev_dbg(&pdx->interface->dev, "%s\n", __func__); ced_draw_down(pdx); /* wait for, then kill outstanding Urbs */ FlushInBuff(pdx); /* Clear out input buffer & pipe */ @@ -987,7 +988,7 @@ int StartSelfTest(DEVICE_EXTENSION *pdx) mutex_unlock(&pdx->io_mutex); if (nGot < 0) - dev_err(&pdx->interface->dev, "%s err=%d", __func__, nGot); + dev_err(&pdx->interface->dev, "%s: err=%d\n", __func__, nGot); return nGot < 0 ? U14ERR_FAIL : U14ERR_NOERROR; } @@ -1005,7 +1006,7 @@ int CheckSelfTest(DEVICE_EXTENSION *pdx, TGET_SELFTEST __user *pGST) mutex_lock(&pdx->io_mutex); - dev_dbg(&pdx->interface->dev, "%s", __func__); + dev_dbg(&pdx->interface->dev, "%s\n", __func__); iReturn = Get1401State(pdx, &state, &error); if (iReturn == U14ERR_NOERROR) /* Only accept zero if it happens twice */ iReturn = Get1401State(pdx, &state, &error); @@ -1013,8 +1014,8 @@ int CheckSelfTest(DEVICE_EXTENSION *pdx, TGET_SELFTEST __user *pGST) if (iReturn != U14ERR_NOERROR) { /* Self-test can cause comms errors */ /* so we assume still testing */ dev_err(&pdx->interface->dev, - "%s Get1401State=%d, assuming still testing", __func__, - iReturn); + "%s: Get1401State=%d, assuming still testing\n", + __func__, iReturn); state = 0x80; /* Force still-testing, no error */ error = 0; iReturn = U14ERR_NOERROR; @@ -1022,7 +1023,7 @@ int CheckSelfTest(DEVICE_EXTENSION *pdx, TGET_SELFTEST __user *pGST) if ((state == -1) && (error == -1)) { /* If Get1401State had problems */ dev_err(&pdx->interface->dev, - "%s Get1401State failed, assuming still testing", + "%s: Get1401State failed, assuming still testing\n", __func__); state = 0x80; /* Force still-testing, no error */ error = 0; @@ -1033,21 +1034,21 @@ int CheckSelfTest(DEVICE_EXTENSION *pdx, TGET_SELFTEST __user *pGST) gst.code = (state & 0x00FF0000) >> 16; /* read the error code */ gst.x = error & 0x0000FFFF; /* Error data X */ gst.y = (error & 0xFFFF0000) >> 16; /* and data Y */ - dev_dbg(&pdx->interface->dev, "Self-test error code %d", - gst.code); + dev_dbg(&pdx->interface->dev, + "Self-test error code %d\n", gst.code); } else { /* No error, check for timeout */ unsigned long ulNow = jiffies; /* get current time */ if (time_after(ulNow, pdx->ulSelfTestTime)) { gst.code = -2; /* Flag the timeout */ dev_dbg(&pdx->interface->dev, - "Self-test timed-out"); + "Self-test timed-out\n"); } else dev_dbg(&pdx->interface->dev, - "Self-test on-going"); + "Self-test on-going\n"); } } else { gst.code = -1; /* Flag the test is done */ - dev_dbg(&pdx->interface->dev, "Self-test done"); + dev_dbg(&pdx->interface->dev, "Self-test done\n"); } if (gst.code < 0) { /* If we have a problem or finished */ @@ -1074,7 +1075,7 @@ int TypeOf1401(DEVICE_EXTENSION *pdx) { int iReturn = TYPEUNKNOWN; mutex_lock(&pdx->io_mutex); - dev_dbg(&pdx->interface->dev, "%s", __func__); + dev_dbg(&pdx->interface->dev, "%s\n", __func__); switch (pdx->s1401Type) { case TYPE1401: @@ -1092,7 +1093,7 @@ int TypeOf1401(DEVICE_EXTENSION *pdx) else /* for up-coming 1401 designs */ iReturn = TYPEUNKNOWN; /* Don't know or not there */ } - dev_dbg(&pdx->interface->dev, "%s %d", __func__, iReturn); + dev_dbg(&pdx->interface->dev, "%s %d\n", __func__, iReturn); mutex_unlock(&pdx->io_mutex); return iReturn; @@ -1107,7 +1108,7 @@ int TransferFlags(DEVICE_EXTENSION *pdx) { int iReturn = U14TF_MULTIA | U14TF_DIAG | /* we always have multiple DMA area */ U14TF_NOTIFY | U14TF_CIRCTH; /* diagnostics, notify and circular */ - dev_dbg(&pdx->interface->dev, "%s", __func__); + dev_dbg(&pdx->interface->dev, "%s\n", __func__); mutex_lock(&pdx->io_mutex); if (pdx->bIsUSB2) /* Set flag for USB2 if appropriate */ iReturn |= U14TF_USB2; @@ -1125,15 +1126,15 @@ static int DbgCmd1401(DEVICE_EXTENSION *pdx, unsigned char cmd, unsigned int data) { int iReturn; - dev_dbg(&pdx->interface->dev, "%s entry", __func__); + dev_dbg(&pdx->interface->dev, "%s: entry\n", __func__); iReturn = usb_control_msg(pdx->udev, usb_sndctrlpipe(pdx->udev, 0), cmd, (H_TO_D | VENDOR | DEVREQ), (unsigned short)data, (unsigned short)(data >> 16), NULL, 0, HZ); /* allow 1 second timeout */ if (iReturn < 0) - dev_err(&pdx->interface->dev, "%s fail code=%d", __func__, - iReturn); + dev_err(&pdx->interface->dev, "%s: fail code=%d\n", + __func__, iReturn); return iReturn; } @@ -1152,7 +1153,7 @@ int DbgPeek(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB) return -EFAULT; mutex_lock(&pdx->io_mutex); - dev_dbg(&pdx->interface->dev, "%s @ %08x", __func__, db.iAddr); + dev_dbg(&pdx->interface->dev, "%s: @ %08x\n", __func__, db.iAddr); iReturn = DbgCmd1401(pdx, DB_SETADD, db.iAddr); if (iReturn == U14ERR_NOERROR) @@ -1181,7 +1182,7 @@ int DbgPoke(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB) return -EFAULT; mutex_lock(&pdx->io_mutex); - dev_dbg(&pdx->interface->dev, "%s @ %08x", __func__, db.iAddr); + dev_dbg(&pdx->interface->dev, "%s: @ %08x\n", __func__, db.iAddr); iReturn = DbgCmd1401(pdx, DB_SETADD, db.iAddr); if (iReturn == U14ERR_NOERROR) @@ -1210,7 +1211,7 @@ int DbgRampData(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB) return -EFAULT; mutex_lock(&pdx->io_mutex); - dev_dbg(&pdx->interface->dev, "%s @ %08x", __func__, db.iAddr); + dev_dbg(&pdx->interface->dev, "%s: @ %08x\n", __func__, db.iAddr); iReturn = DbgCmd1401(pdx, DB_SETADD, db.iAddr); if (iReturn == U14ERR_NOERROR) @@ -1242,7 +1243,7 @@ int DbgRampAddr(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB) return -EFAULT; mutex_lock(&pdx->io_mutex); - dev_dbg(&pdx->interface->dev, "%s", __func__); + dev_dbg(&pdx->interface->dev, "%s\n", __func__); iReturn = DbgCmd1401(pdx, DB_SETDEF, db.iDefault); if (iReturn == U14ERR_NOERROR) @@ -1270,7 +1271,7 @@ int DbgGetData(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB) memset(&db, 0, sizeof(db)); /* fill returned block with 0s */ mutex_lock(&pdx->io_mutex); - dev_dbg(&pdx->interface->dev, "%s", __func__); + dev_dbg(&pdx->interface->dev, "%s\n", __func__); /* Read back the last peeked value from the 1401. */ iReturn = usb_control_msg(pdx->udev, usb_rcvctrlpipe(pdx->udev, 0), @@ -1282,8 +1283,8 @@ int DbgGetData(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB) else iReturn = U14ERR_NOERROR; } else - dev_err(&pdx->interface->dev, "%s failed, code %d", __func__, - iReturn); + dev_err(&pdx->interface->dev, "%s: failed, code %d\n", + __func__, iReturn); mutex_unlock(&pdx->io_mutex); @@ -1302,7 +1303,7 @@ int DbgStopLoop(DEVICE_EXTENSION *pdx) unsigned int uState, uErr; mutex_lock(&pdx->io_mutex); - dev_dbg(&pdx->interface->dev, "%s", __func__); + dev_dbg(&pdx->interface->dev, "%s\n", __func__); iReturn = Get1401State(pdx, &uState, &uErr); mutex_unlock(&pdx->io_mutex); @@ -1317,18 +1318,18 @@ int DbgStopLoop(DEVICE_EXTENSION *pdx) ** booked and a transfer to that area is in progress. Otherwise, we will ** release the area and re-assign it. ****************************************************************************/ -int SetCircular(DEVICE_EXTENSION *pdx, TRANSFERDESC __user *pTD) +int SetCircular(DEVICE_EXTENSION *pdx, struct transfer_area_desc __user *pTD) { int iReturn; bool bToHost; - TRANSFERDESC td; + struct transfer_area_desc td; if (copy_from_user(&td, pTD, sizeof(td))) return -EFAULT; mutex_lock(&pdx->io_mutex); - dev_dbg(&pdx->interface->dev, "%s area:%d, size:%08x", __func__, - td.wAreaNum, td.dwLength); + dev_dbg(&pdx->interface->dev, "%s: area:%d, size:%08x\n", + __func__, td.wAreaNum, td.dwLength); bToHost = td.eSize != 0; /* this is used as the tohost flag */ /* The strange cast is done so that we don't get warnings in 32-bit linux about the size of the */ @@ -1353,7 +1354,7 @@ int GetCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user *pCB) unsigned int nArea; TCIRCBLOCK cb; - dev_dbg(&pdx->interface->dev, "%s", __func__); + dev_dbg(&pdx->interface->dev, "%s\n", __func__); if (copy_from_user(&cb, pCB, sizeof(cb))) return -EFAULT; @@ -1374,7 +1375,7 @@ int GetCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user *pCB) cb.dwOffset = pArea->aBlocks[0].dwOffset; cb.dwSize = pArea->aBlocks[0].dwSize; dev_dbg(&pdx->interface->dev, - "%s return block 0: %d bytes at %d", + "%s: return block 0: %d bytes at %d\n", __func__, cb.dwSize, cb.dwOffset); } } else @@ -1402,7 +1403,7 @@ int FreeCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user *pCB) unsigned int nArea, uStart, uSize; TCIRCBLOCK cb; - dev_dbg(&pdx->interface->dev, "%s", __func__); + dev_dbg(&pdx->interface->dev, "%s\n", __func__); if (copy_from_user(&cb, pCB, sizeof(cb))) return -EFAULT; @@ -1437,7 +1438,7 @@ int FreeCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user *pCB) } dev_dbg(&pdx->interface->dev, - "%s free %d bytes at %d, return %d bytes at %d, wait=%d", + "%s: free %d bytes at %d, return %d bytes at %d, wait=%d\n", __func__, uSize, uStart, pArea->aBlocks[0].dwSize, pArea->aBlocks[0].dwOffset, @@ -1453,13 +1454,13 @@ int FreeCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user *pCB) bWaiting = pdx->bXFerWaiting; if (bWaiting && pdx->bStagedUrbPending) { dev_err(&pdx->interface->dev, - "%s ERROR: waiting xfer and staged Urb pending!", + "%s: ERROR: waiting xfer and staged Urb pending!\n", __func__); bWaiting = false; } } else { dev_err(&pdx->interface->dev, - "%s ERROR: freeing %d bytes at %d, block 0 is %d bytes at %d", + "%s: ERROR: freeing %d bytes at %d, block 0 is %d bytes at %d\n", __func__, uSize, uStart, pArea->aBlocks[0].dwSize, pArea->aBlocks[0].dwOffset); @@ -1475,7 +1476,7 @@ int FreeCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user *pCB) pdx->rDMAInfo.dwSize); if (RWMStat != U14ERR_NOERROR) dev_err(&pdx->interface->dev, - "%s rw setup failed %d", + "%s: rw setup failed %d\n", __func__, RWMStat); } } else diff --git a/drivers/staging/ced1401/ced_ioctl.h b/drivers/staging/ced1401/ced_ioctl.h index aa68878bd251..4b6c9dedb21e 100644 --- a/drivers/staging/ced1401/ced_ioctl.h +++ b/drivers/staging/ced1401/ced_ioctl.h @@ -26,24 +26,21 @@ ** TypeDefs *****************************************************************************/ -typedef unsigned short TBLOCKENTRY; /* index the blk transfer table 0-7 */ - -typedef struct TransferDesc { +struct transfer_area_desc { long long lpvBuff; /* address of transfer area (for 64 or 32 bit) */ unsigned int dwLength; /* length of the area */ - TBLOCKENTRY wAreaNum; /* number of transfer area to set up */ + unsigned short wAreaNum; /* number of transfer area to set up */ short eSize; /* element size - is tohost flag for circular */ -} TRANSFERDESC; +}; -typedef TRANSFERDESC *LPTRANSFERDESC; -typedef struct TransferEvent { +struct transfer_event { unsigned int dwStart; /* offset into the area */ unsigned int dwLength; /* length of the region */ unsigned short wAreaNum; /* the area number */ unsigned short wFlags; /* bit 0 set for toHost */ int iSetEvent; /* could be dummy in LINUX */ -} TRANSFEREVENT; +}; #define MAX_TRANSFER_SIZE 0x4000 /* Maximum data bytes per IRP */ #define MAX_AREA_LENGTH 0x100000 /* Maximum size of transfer area */ @@ -85,12 +82,6 @@ typedef struct TCSBlock { */ #define CED_MAGIC_IOC 0xce -/* NBNB: READ and WRITE are from the point of view of the device, not user. */ -typedef struct ced_ioc_string { - int nChars; - char buffer[256]; -} CED_IOC_STRING; - #define IOCTL_CED_SENDSTRING(n) _IOC(_IOC_WRITE, CED_MAGIC_IOC, 2, n) #define IOCTL_CED_RESET1401 _IO(CED_MAGIC_IOC, 3) @@ -100,9 +91,9 @@ typedef struct ced_ioc_string { #define IOCTL_CED_LINECOUNT _IO(CED_MAGIC_IOC, 7) #define IOCTL_CED_GETSTRING(nMax) _IOC(_IOC_READ, CED_MAGIC_IOC, 8, nMax) -#define IOCTL_CED_SETTRANSFER _IOW(CED_MAGIC_IOC, 11, TRANSFERDESC) +#define IOCTL_CED_SETTRANSFER _IOW(CED_MAGIC_IOC, 11, struct transfer_area_desc) #define IOCTL_CED_UNSETTRANSFER _IO(CED_MAGIC_IOC, 12) -#define IOCTL_CED_SETEVENT _IOW(CED_MAGIC_IOC, 13, TRANSFEREVENT) +#define IOCTL_CED_SETEVENT _IOW(CED_MAGIC_IOC, 13, struct transfer_event) #define IOCTL_CED_GETOUTBUFSPACE _IO(CED_MAGIC_IOC, 14) #define IOCTL_CED_GETBASEADDRESS _IO(CED_MAGIC_IOC, 15) #define IOCTL_CED_GETDRIVERREVISION _IO(CED_MAGIC_IOC, 16) @@ -126,7 +117,7 @@ typedef struct ced_ioc_string { #define IOCTL_CED_DBGGETDATA _IOR(CED_MAGIC_IOC, 39, TDBGBLOCK) #define IOCTL_CED_DBGSTOPLOOP _IO(CED_MAGIC_IOC, 40) #define IOCTL_CED_FULLRESET _IO(CED_MAGIC_IOC, 41) -#define IOCTL_CED_SETCIRCULAR _IOW(CED_MAGIC_IOC, 42, TRANSFERDESC) +#define IOCTL_CED_SETCIRCULAR _IOW(CED_MAGIC_IOC, 42, struct transfer_area_desc) #define IOCTL_CED_GETCIRCBLOCK _IOWR(CED_MAGIC_IOC, 43, TCIRCBLOCK) #define IOCTL_CED_FREECIRCBLOCK _IOWR(CED_MAGIC_IOC, 44, TCIRCBLOCK) #define IOCTL_CED_WAITEVENT _IO(CED_MAGIC_IOC, 45) @@ -198,7 +189,7 @@ inline int CED_GetDriverRevision(int fh) return ioctl(fh, IOCTL_CED_GETDRIVERREVISION); } -inline int CED_SetTransfer(int fh, TRANSFERDESC *pTD) +inline int CED_SetTransfer(int fh, struct transfer_area_desc *pTD) { return ioctl(fh, IOCTL_CED_SETTRANSFER, pTD); } @@ -208,7 +199,7 @@ inline int CED_UnsetTransfer(int fh, int nArea) return ioctl(fh, IOCTL_CED_UNSETTRANSFER, nArea); } -inline int CED_SetEvent(int fh, TRANSFEREVENT *pTE) +inline int CED_SetEvent(int fh, struct transfer_event *pTE) { return ioctl(fh, IOCTL_CED_SETEVENT, pTE); } @@ -299,7 +290,7 @@ inline int CED_FullReset(int fh) return ioctl(fh, IOCTL_CED_FULLRESET); } -inline int CED_SetCircular(int fh, TRANSFERDESC *pTD) +inline int CED_SetCircular(int fh, struct transfer_area_desc *pTD) { return ioctl(fh, IOCTL_CED_SETCIRCULAR, pTD); } diff --git a/drivers/staging/ced1401/usb1401.c b/drivers/staging/ced1401/usb1401.c index efc310ca789e..284abc08922c 100644 --- a/drivers/staging/ced1401/usb1401.c +++ b/drivers/staging/ced1401/usb1401.c @@ -166,7 +166,7 @@ static int ced_open(struct inode *inode, struct file *file) goto exit; } - dev_dbg(&interface->dev, "%s got pdx", __func__); + dev_dbg(&interface->dev, "%s: got pdx\n", __func__); /* increment our usage count for the device */ kref_get(&pdx->kref); @@ -184,7 +184,7 @@ static int ced_open(struct inode *inode, struct file *file) goto exit; } } else { /* uncomment this block if you want exclusive open */ - dev_err(&interface->dev, "%s fail: already open", __func__); + dev_err(&interface->dev, "%s: fail: already open\n", __func__); retval = -EBUSY; pdx->open_count--; mutex_unlock(&pdx->io_mutex); @@ -207,7 +207,7 @@ static int ced_release(struct inode *inode, struct file *file) if (pdx == NULL) return -ENODEV; - dev_dbg(&pdx->interface->dev, "%s called", __func__); + dev_dbg(&pdx->interface->dev, "%s: called\n", __func__); mutex_lock(&pdx->io_mutex); if (!--pdx->open_count && pdx->interface) /* Allow autosuspend */ usb_autopm_put_interface(pdx->interface); @@ -224,12 +224,12 @@ static int ced_flush(struct file *file, fl_owner_t id) if (pdx == NULL) return -ENODEV; - dev_dbg(&pdx->interface->dev, "%s char in pend=%d", __func__, - pdx->bReadCharsPending); + dev_dbg(&pdx->interface->dev, "%s: char in pend=%d\n", + __func__, pdx->bReadCharsPending); /* wait for io to stop */ mutex_lock(&pdx->io_mutex); - dev_dbg(&pdx->interface->dev, "%s got io_mutex", __func__); + dev_dbg(&pdx->interface->dev, "%s: got io_mutex\n", __func__); ced_draw_down(pdx); /* read out errors, leave subsequent opens a clean slate */ @@ -239,7 +239,7 @@ static int ced_flush(struct file *file, fl_owner_t id) spin_unlock_irq(&pdx->err_lock); mutex_unlock(&pdx->io_mutex); - dev_dbg(&pdx->interface->dev, "%s exit reached", __func__); + dev_dbg(&pdx->interface->dev, "%s: exit reached\n", __func__); return res; } @@ -270,7 +270,7 @@ static void ced_writechar_callback(struct urb *pUrb) (pUrb->status == -ENOENT || pUrb->status == -ECONNRESET || pUrb->status == -ESHUTDOWN)) { dev_err(&pdx->interface->dev, - "%s - nonzero write bulk status received: %d", + "%s: nonzero write bulk status received: %d\n", __func__, pUrb->status); } @@ -287,10 +287,10 @@ static void ced_writechar_callback(struct urb *pUrb) pdx->bSendCharsPending = false; /* Allow other threads again */ spin_unlock(&pdx->charOutLock); /* already at irq level */ dev_dbg(&pdx->interface->dev, - "%s - char out done, 0 chars sent", __func__); + "%s: char out done, 0 chars sent\n", __func__); } else { dev_dbg(&pdx->interface->dev, - "%s - char out done, %d chars sent", __func__, nGot); + "%s: char out done, %d chars sent\n", __func__, nGot); spin_lock(&pdx->charOutLock); /* already at irq level */ pdx->dwNumOutput -= nGot; /* Now adjust the char send buffer */ pdx->dwOutBuffGet += nGot; /* to match what we did */ @@ -315,15 +315,15 @@ static void ced_writechar_callback(struct urb *pUrb) URB_NO_TRANSFER_DMA_MAP; usb_anchor_urb(pdx->pUrbCharOut, &pdx->submitted); /* in case we need to kill it */ iReturn = usb_submit_urb(pdx->pUrbCharOut, GFP_ATOMIC); - dev_dbg(&pdx->interface->dev, "%s n=%d>%s<", __func__, - dwCount, pDat); + dev_dbg(&pdx->interface->dev, "%s: n=%d>%s<\n", + __func__, dwCount, pDat); spin_lock(&pdx->charOutLock); /* grab lock for errors */ if (iReturn) { pdx->bPipeError[nPipe] = 1; /* Flag an error to be handled later */ pdx->bSendCharsPending = false; /* Allow other threads again */ usb_unanchor_urb(pdx->pUrbCharOut); dev_err(&pdx->interface->dev, - "%s usb_submit_urb() returned %d", + "%s: usb_submit_urb() returned %d\n", __func__, iReturn); } } else @@ -350,8 +350,8 @@ int SendChars(DEVICE_EXTENSION *pdx) pdx->bSendCharsPending = true; /* Set flag to lock out other threads */ dev_dbg(&pdx->interface->dev, - "Send %d chars to 1401, EP0 flag %d\n", dwCount, - pdx->nPipes == 3); + "Send %d chars to 1401, EP0 flag %d\n", + dwCount, pdx->nPipes == 3); /* If we have only 3 end points we must send the characters to the 1401 using EP0. */ if (pdx->nPipes == 3) { /* For EP0 character transmissions to the 1401, we have to hang about until they */ @@ -375,11 +375,11 @@ int SendChars(DEVICE_EXTENSION *pdx) if (nSent <= 0) { iReturn = nSent ? nSent : -ETIMEDOUT; /* if 0 chars says we timed out */ dev_err(&pdx->interface->dev, - "Send %d chars by EP0 failed: %d", + "Send %d chars by EP0 failed: %d\n", n, iReturn); } else { dev_dbg(&pdx->interface->dev, - "Sent %d chars by EP0", n); + "Sent %d chars by EP0\n", n); count -= nSent; index += nSent; } @@ -416,9 +416,9 @@ int SendChars(DEVICE_EXTENSION *pdx) } } else if (pdx->bSendCharsPending && (pdx->dwNumOutput > 0)) dev_dbg(&pdx->interface->dev, - "SendChars bSendCharsPending:true"); + "%s: bSendCharsPending:true\n", __func__); - dev_dbg(&pdx->interface->dev, "SendChars exit code: %d", iReturn); + dev_dbg(&pdx->interface->dev, "%s: exit code: %d\n", __func__, iReturn); spin_unlock_irq(&pdx->charOutLock); /* Now let go of the spinlock */ return iReturn; } @@ -446,7 +446,7 @@ static void CopyUserSpace(DEVICE_EXTENSION *pdx, int n) pdx->StagedDone + pdx->StagedOffset + pArea->dwBaseOffset; char *pCoherBuf = pdx->pCoherStagedIO; /* coherent buffer */ if (!pArea->bUsed) { - dev_err(&pdx->interface->dev, "%s area %d unused", + dev_err(&pdx->interface->dev, "%s: area %d unused\n", __func__, nArea); return; } @@ -474,21 +474,21 @@ static void CopyUserSpace(DEVICE_EXTENSION *pdx, int n) n -= uiXfer; } else { dev_err(&pdx->interface->dev, - "%s did not map page %d", + "%s: did not map page %d\n", __func__, nPage); return; } } else { dev_err(&pdx->interface->dev, - "%s exceeded pages %d", __func__, - nPage); + "%s: exceeded pages %d\n", + __func__, nPage); return; } } } else - dev_err(&pdx->interface->dev, "%s bad area %d", __func__, - nArea); + dev_err(&pdx->interface->dev, "%s: bad area %d\n", + __func__, nArea); } /* Forward declarations for stuff used circularly */ @@ -513,11 +513,11 @@ static void staged_callback(struct urb *pUrb) (pUrb->status == -ENOENT || pUrb->status == -ECONNRESET || pUrb->status == -ESHUTDOWN)) { dev_err(&pdx->interface->dev, - "%s - nonzero write bulk status received: %d", + "%s: nonzero write bulk status received: %d\n", __func__, pUrb->status); } else dev_info(&pdx->interface->dev, - "%s - staged xfer cancelled", __func__); + "%s: staged xfer cancelled\n", __func__); spin_lock(&pdx->err_lock); pdx->errors = pUrb->status; @@ -525,26 +525,26 @@ static void staged_callback(struct urb *pUrb) nGot = 0; /* and tidy up again if so */ bCancel = true; } else { - dev_dbg(&pdx->interface->dev, "%s %d chars xferred", __func__, - nGot); + dev_dbg(&pdx->interface->dev, "%s: %d chars xferred\n", + __func__, nGot); if (pdx->StagedRead) /* if reading, save to user space */ CopyUserSpace(pdx, nGot); /* copy from buffer to user */ if (nGot == 0) - dev_dbg(&pdx->interface->dev, "%s ZLP", __func__); + dev_dbg(&pdx->interface->dev, "%s: ZLP\n", __func__); } /* Update the transfer length based on the TransferBufferLength value in the URB */ pdx->StagedDone += nGot; - dev_dbg(&pdx->interface->dev, "%s, done %d bytes of %d", __func__, - pdx->StagedDone, pdx->StagedLength); + dev_dbg(&pdx->interface->dev, "%s: done %d bytes of %d\n", + __func__, pdx->StagedDone, pdx->StagedLength); if ((pdx->StagedDone == pdx->StagedLength) || /* If no more to do */ (bCancel)) { /* or this IRP was cancelled */ TRANSAREA *pArea = &pdx->rTransDef[pdx->StagedId]; /* Transfer area info */ dev_dbg(&pdx->interface->dev, - "%s transfer done, bytes %d, cancel %d", __func__, - pdx->StagedDone, bCancel); + "%s: transfer done, bytes %d, cancel %d\n", + __func__, pdx->StagedDone, bCancel); /* Here is where we sort out what to do with this transfer if using a circular buffer. We have */ /* a completed transfer that can be assumed to fit into the transfer area. We should be able to */ @@ -559,7 +559,7 @@ static void staged_callback(struct urb *pUrb) pArea->aBlocks[1].dwSize += pdx->StagedLength; dev_dbg(&pdx->interface->dev, - "RWM_Complete, circ block 1 now %d bytes at %d", + "RWM_Complete, circ block 1 now %d bytes at %d\n", pArea->aBlocks[1].dwSize, pArea->aBlocks[1].dwOffset); } else { @@ -569,7 +569,7 @@ static void staged_callback(struct urb *pUrb) pArea->aBlocks[1].dwSize = pdx->StagedLength; dev_err(&pdx->interface->dev, - "%s ERROR, circ block 1 re-started %d bytes at %d", + "%s: ERROR, circ block 1 re-started %d bytes at %d\n", __func__, pArea->aBlocks[1].dwSize, pArea->aBlocks[1].dwOffset); @@ -582,7 +582,7 @@ static void staged_callback(struct urb *pUrb) pArea->aBlocks[0].dwSize)) { pArea->aBlocks[0].dwSize += pdx->StagedLength; /* Just add this transfer in */ dev_dbg(&pdx->interface->dev, - "RWM_Complete, circ block 0 now %d bytes at %d", + "RWM_Complete, circ block 0 now %d bytes at %d\n", pArea->aBlocks[0]. dwSize, pArea->aBlocks[0]. @@ -593,7 +593,7 @@ static void staged_callback(struct urb *pUrb) pArea->aBlocks[1].dwSize = pdx->StagedLength; dev_dbg(&pdx->interface->dev, - "RWM_Complete, circ block 1 started %d bytes at %d", + "RWM_Complete, circ block 1 started %d bytes at %d\n", pArea->aBlocks[1]. dwSize, pArea->aBlocks[1]. @@ -605,7 +605,7 @@ static void staged_callback(struct urb *pUrb) pArea->aBlocks[0].dwSize = pdx->StagedLength; dev_dbg(&pdx->interface->dev, - "RWM_Complete, circ block 0 started %d bytes at %d", + "RWM_Complete, circ block 0 started %d bytes at %d\n", pArea->aBlocks[0].dwSize, pArea->aBlocks[0].dwOffset); } @@ -614,7 +614,7 @@ static void staged_callback(struct urb *pUrb) if (!bCancel) { /* Don't generate an event if cancelled */ dev_dbg(&pdx->interface->dev, - "RWM_Complete, bCircular %d, bToHost %d, eStart %d, eSize %d", + "RWM_Complete, bCircular %d, bToHost %d, eStart %d, eSize %d\n", pArea->bCircular, pArea->bEventToHost, pArea->dwEventSt, pArea->dwEventSz); if ((pArea->dwEventSz) && /* Set a user-mode event... */ @@ -641,7 +641,7 @@ static void staged_callback(struct urb *pUrb) if (iWakeUp) { dev_dbg(&pdx->interface->dev, - "About to set event to notify app"); + "About to set event to notify app\n"); wake_up_interruptible(&pArea->wqEvent); /* wake up waiting processes */ ++pArea->iWakeUp; /* increment wakeup count */ } @@ -655,7 +655,7 @@ static void staged_callback(struct urb *pUrb) if (pdx->bXFerWaiting) { /* Got a block xfer waiting? */ int iReturn; dev_info(&pdx->interface->dev, - "*** RWM_Complete *** pending transfer will now be set up!!!"); + "*** RWM_Complete *** pending transfer will now be set up!!!\n"); iReturn = ReadWriteMem(pdx, !pdx->rDMAInfo.bOutWard, pdx->rDMAInfo.wIdent, @@ -664,7 +664,7 @@ static void staged_callback(struct urb *pUrb) if (iReturn) dev_err(&pdx->interface->dev, - "RWM_Complete rw setup failed %d", + "RWM_Complete rw setup failed %d\n", iReturn); } } @@ -685,7 +685,7 @@ static void staged_callback(struct urb *pUrb) /* not be upset by char input during DMA... sigh. Needs sorting out. */ if (bRestartCharInput) /* may be out of date, but... */ Allowi(pdx); /* ...Allowi tests a lock too. */ - dev_dbg(&pdx->interface->dev, "%s done", __func__); + dev_dbg(&pdx->interface->dev, "%s: done\n", __func__); } /**************************************************************************** @@ -707,7 +707,7 @@ static int StageChunk(DEVICE_EXTENSION *pdx) return U14ERR_FAIL; if (!CanAcceptIoRequests(pdx)) { /* got sudden remove? */ - dev_info(&pdx->interface->dev, "%s sudden remove, giving up", + dev_info(&pdx->interface->dev, "%s: sudden remove, giving up\n", __func__); return U14ERR_FAIL; /* could do with a better error */ } @@ -731,11 +731,11 @@ static int StageChunk(DEVICE_EXTENSION *pdx) if (iReturn) { usb_unanchor_urb(pdx->pStagedUrb); /* kill it */ pdx->bPipeError[nPipe] = 1; /* Flag an error to be handled later */ - dev_err(&pdx->interface->dev, "%s submit urb failed, code %d", + dev_err(&pdx->interface->dev, "%s: submit urb failed, code %d\n", __func__, iReturn); } else pdx->bStagedUrbPending = true; /* Set the flag for staged URB pending */ - dev_dbg(&pdx->interface->dev, "%s done so far:%d, this size:%d", + dev_dbg(&pdx->interface->dev, "%s: done so far:%d, this size:%d\n", __func__, pdx->StagedDone, ChunkSize); return iReturn; @@ -764,28 +764,28 @@ int ReadWriteMem(DEVICE_EXTENSION *pdx, bool Read, unsigned short wIdent, TRANSAREA *pArea = &pdx->rTransDef[wIdent]; /* Transfer area info */ if (!CanAcceptIoRequests(pdx)) { /* Are we in a state to accept new requests? */ - dev_err(&pdx->interface->dev, "%s can't accept requests", + dev_err(&pdx->interface->dev, "%s: can't accept requests\n", __func__); return U14ERR_FAIL; } dev_dbg(&pdx->interface->dev, - "%s xfer %d bytes to %s, offset %d, area %d", __func__, dwLen, - Read ? "host" : "1401", dwOffs, wIdent); + "%s: xfer %d bytes to %s, offset %d, area %d\n", + __func__, dwLen, Read ? "host" : "1401", dwOffs, wIdent); /* Amazingly, we can get an escape sequence back before the current staged Urb is done, so we */ /* have to check for this situation and, if so, wait until all is OK. */ if (pdx->bStagedUrbPending) { pdx->bXFerWaiting = true; /* Flag we are waiting */ dev_info(&pdx->interface->dev, - "%s xfer is waiting, as previous staged pending", + "%s: xfer is waiting, as previous staged pending\n", __func__); return U14ERR_NOERROR; } if (dwLen == 0) { /* allow 0-len read or write; just return success */ dev_dbg(&pdx->interface->dev, - "%s OK; zero-len read/write request", __func__); + "%s: OK; zero-len read/write request\n", __func__); return U14ERR_NOERROR; } @@ -795,7 +795,7 @@ int ReadWriteMem(DEVICE_EXTENSION *pdx, bool Read, unsigned short wIdent, bool bWait = false; /* Flag for transfer having to wait */ dev_dbg(&pdx->interface->dev, - "Circular buffers are %d at %d and %d at %d", + "Circular buffers are %d at %d and %d at %d\n", pArea->aBlocks[0].dwSize, pArea->aBlocks[0].dwOffset, pArea->aBlocks[1].dwSize, pArea->aBlocks[1].dwOffset); if (pArea->aBlocks[1].dwSize > 0) { /* Using the second block already? */ @@ -819,14 +819,14 @@ int ReadWriteMem(DEVICE_EXTENSION *pdx, bool Read, unsigned short wIdent, if (bWait) { /* This transfer will have to wait? */ pdx->bXFerWaiting = true; /* Flag we are waiting */ dev_dbg(&pdx->interface->dev, - "%s xfer waiting for circular buffer space", + "%s: xfer waiting for circular buffer space\n", __func__); return U14ERR_NOERROR; } dev_dbg(&pdx->interface->dev, - "%s circular xfer, %d bytes starting at %d", __func__, - dwLen, dwOffs); + "%s: circular xfer, %d bytes starting at %d\n", + __func__, dwLen, dwOffs); } /* Save the parameters for the read\write transfer */ pdx->StagedRead = Read; /* Save the parameters for this read */ @@ -948,7 +948,7 @@ static bool ReadDMAInfo(volatile DMADESC *pDmaDesc, DEVICE_EXTENSION *pdx, unsigned char ucData; unsigned int dDone = 0; /* We haven't parsed anything so far */ - dev_dbg(&pdx->interface->dev, "%s", __func__); + dev_dbg(&pdx->interface->dev, "%s\n", __func__); if (ReadChar(&ucData, pBuf, &dDone, dwCount)) { unsigned char ucTransCode = (ucData & 0x0F); /* get code for transfer type */ @@ -960,8 +960,8 @@ static bool ReadDMAInfo(volatile DMADESC *pDmaDesc, DEVICE_EXTENSION *pdx, pDmaDesc->dwSize = 0; /* initialise other bits */ pDmaDesc->dwOffset = 0; - dev_dbg(&pdx->interface->dev, "%s type: %d ident: %d", __func__, - pDmaDesc->wTransType, pDmaDesc->wIdent); + dev_dbg(&pdx->interface->dev, "%s: type: %d ident: %d\n", + __func__, pDmaDesc->wTransType, pDmaDesc->wIdent); pDmaDesc->bOutWard = (ucTransCode != TM_EXTTOHOST); /* set transfer direction */ @@ -976,7 +976,7 @@ static bool ReadDMAInfo(volatile DMADESC *pDmaDesc, DEVICE_EXTENSION *pdx, &dDone, dwCount); if (bResult) { dev_dbg(&pdx->interface->dev, - "%s xfer offset & size %d %d", + "%s: xfer offset & size %d %d\n", __func__, pDmaDesc->dwOffset, pDmaDesc->dwSize); @@ -989,7 +989,7 @@ static bool ReadDMAInfo(volatile DMADESC *pDmaDesc, DEVICE_EXTENSION *pdx, dwLength))) { bResult = false; /* bad parameter(s) */ dev_dbg(&pdx->interface->dev, - "%s bad param - id %d, bUsed %d, offset %d, size %d, area length %d", + "%s: bad param - id %d, bUsed %d, offset %d, size %d, area length %d\n", __func__, wIdent, pdx->rTransDef[wIdent]. bUsed, @@ -1008,7 +1008,7 @@ static bool ReadDMAInfo(volatile DMADESC *pDmaDesc, DEVICE_EXTENSION *pdx, bResult = false; if (!bResult) /* now check parameters for validity */ - dev_err(&pdx->interface->dev, "%s error reading Esc sequence", + dev_err(&pdx->interface->dev, "%s: error reading Esc sequence\n", __func__); return bResult; @@ -1045,15 +1045,15 @@ static int Handle1401Esc(DEVICE_EXTENSION *pdx, char *pCh, unsigned short wTransType = pdx->rDMAInfo.wTransType; /* check transfer type */ dev_dbg(&pdx->interface->dev, - "%s xfer to %s, offset %d, length %d", __func__, + "%s: xfer to %s, offset %d, length %d\n", + __func__, pdx->rDMAInfo.bOutWard ? "1401" : "host", pdx->rDMAInfo.dwOffset, pdx->rDMAInfo.dwSize); if (pdx->bXFerWaiting) { /* Check here for badly out of kilter... */ /* This can never happen, really */ dev_err(&pdx->interface->dev, - "ERROR: DMA setup while transfer still waiting"); - spin_unlock(&pdx->stagedLock); + "ERROR: DMA setup while transfer still waiting\n"); } else { if ((wTransType == TM_EXTTOHOST) || (wTransType == TM_EXTTO1401)) { @@ -1066,21 +1066,21 @@ static int Handle1401Esc(DEVICE_EXTENSION *pdx, char *pCh, pdx->rDMAInfo.dwSize); if (iReturn != U14ERR_NOERROR) dev_err(&pdx->interface->dev, - "%s ReadWriteMem() failed %d", + "%s: ReadWriteMem() failed %d\n", __func__, iReturn); } else /* This covers non-linear transfer setup */ dev_err(&pdx->interface->dev, - "%s Unknown block xfer type %d", + "%s: Unknown block xfer type %d\n", __func__, wTransType); } } else /* Failed to read parameters */ - dev_err(&pdx->interface->dev, "%s ReadDMAInfo() fail", + dev_err(&pdx->interface->dev, "%s: ReadDMAInfo() fail\n", __func__); spin_unlock(&pdx->stagedLock); /* OK here */ } - dev_dbg(&pdx->interface->dev, "%s returns %d", __func__, iReturn); + dev_dbg(&pdx->interface->dev, "%s: returns %d\n", __func__, iReturn); return iReturn; } @@ -1100,11 +1100,11 @@ static void ced_readchar_callback(struct urb *pUrb) (pUrb->status == -ENOENT || pUrb->status == -ECONNRESET || pUrb->status == -ESHUTDOWN)) { dev_err(&pdx->interface->dev, - "%s - nonzero write bulk status received: %d", + "%s: nonzero write bulk status received: %d\n", __func__, pUrb->status); } else dev_dbg(&pdx->interface->dev, - "%s - 0 chars pUrb->status=%d (shutdown?)", + "%s: 0 chars pUrb->status=%d (shutdown?)\n", __func__, pUrb->status); spin_lock(&pdx->err_lock); @@ -1125,7 +1125,7 @@ static void ced_readchar_callback(struct urb *pUrb) if (nGot < INBUF_SZ) { pdx->pCoherCharIn[nGot] = 0; /* tidy the string */ dev_dbg(&pdx->interface->dev, - "%s got %d chars >%s<", + "%s: got %d chars >%s<\n", __func__, nGot, pdx->pCoherCharIn); } @@ -1140,7 +1140,7 @@ static void ced_readchar_callback(struct urb *pUrb) if ((pdx->dwNumInput + nGot) <= INBUF_SZ) pdx->dwNumInput += nGot; /* Adjust the buffer count accordingly */ } else - dev_dbg(&pdx->interface->dev, "%s read ZLP", + dev_dbg(&pdx->interface->dev, "%s: read ZLP\n", __func__); } } @@ -1178,7 +1178,7 @@ int Allowi(DEVICE_EXTENSION *pdx) unsigned int nMax = INBUF_SZ - pdx->dwNumInput; /* max we could read */ int nPipe = pdx->nPipes == 4 ? 1 : 0; /* The pipe number to use */ - dev_dbg(&pdx->interface->dev, "%s %d chars in input buffer", + dev_dbg(&pdx->interface->dev, "%s: %d chars in input buffer\n", __func__, pdx->dwNumInput); usb_fill_int_urb(pdx->pUrbCharIn, pdx->udev, @@ -1192,7 +1192,8 @@ int Allowi(DEVICE_EXTENSION *pdx) usb_unanchor_urb(pdx->pUrbCharIn); /* remove from list of active Urbs */ pdx->bPipeError[nPipe] = 1; /* Flag an error to be handled later */ dev_err(&pdx->interface->dev, - "%s submit urb failed: %d", __func__, iReturn); + "%s: submit urb failed: %d\n", + __func__, iReturn); } else pdx->bReadCharsPending = true; /* Flag that we are active here */ } @@ -1250,13 +1251,13 @@ static long ced_ioctl(struct file *file, unsigned int cmd, unsigned long ulArg) return GetString(pdx, (char __user *)ulArg, _IOC_SIZE(cmd)); case _IOC_NR(IOCTL_CED_SETTRANSFER): - return SetTransfer(pdx, (TRANSFERDESC __user *) ulArg); + return SetTransfer(pdx, (struct transfer_area_desc __user *) ulArg); case _IOC_NR(IOCTL_CED_UNSETTRANSFER): return UnsetTransfer(pdx, (int)ulArg); case _IOC_NR(IOCTL_CED_SETEVENT): - return SetEvent(pdx, (TRANSFEREVENT __user *) ulArg); + return SetEvent(pdx, (struct transfer_event __user *) ulArg); case _IOC_NR(IOCTL_CED_GETOUTBUFSPACE): return GetOutBufSpace(pdx); @@ -1315,7 +1316,7 @@ static long ced_ioctl(struct file *file, unsigned int cmd, unsigned long ulArg) break; case _IOC_NR(IOCTL_CED_SETCIRCULAR): - return SetCircular(pdx, (TRANSFERDESC __user *) ulArg); + return SetCircular(pdx, (struct transfer_area_desc __user *) ulArg); case _IOC_NR(IOCTL_CED_GETCIRCBLOCK): return GetCircBlock(pdx, (TCIRCBLOCK __user *) ulArg); @@ -1397,7 +1398,7 @@ static int ced_probe(struct usb_interface *interface, else if ((i >= 1) && (i <= 23)) pdx->s1401Type = i + 2; else { - dev_err(&interface->dev, "%s Unknown device. bcdDevice = %d", + dev_err(&interface->dev, "%s: Unknown device. bcdDevice = %d\n", __func__, bcdDevice); goto error; } @@ -1405,7 +1406,7 @@ static int ced_probe(struct usb_interface *interface, /* we know that we are dealing with a 1401 device. */ iface_desc = interface->cur_altsetting; pdx->nPipes = iface_desc->desc.bNumEndpoints; - dev_info(&interface->dev, "1401Type=%d with %d End Points", + dev_info(&interface->dev, "1401Type=%d with %d End Points\n", pdx->s1401Type, pdx->nPipes); if ((pdx->nPipes < 3) || (pdx->nPipes > 4)) goto error; @@ -1415,7 +1416,7 @@ static int ced_probe(struct usb_interface *interface, pdx->pUrbCharIn = usb_alloc_urb(0, GFP_KERNEL); /* character input URB */ pdx->pStagedUrb = usb_alloc_urb(0, GFP_KERNEL); /* block transfer URB */ if (!pdx->pUrbCharOut || !pdx->pUrbCharIn || !pdx->pStagedUrb) { - dev_err(&interface->dev, "%s URB alloc failed", __func__); + dev_err(&interface->dev, "%s: URB alloc failed\n", __func__); goto error; } @@ -1429,7 +1430,7 @@ static int ced_probe(struct usb_interface *interface, usb_alloc_coherent(pdx->udev, INBUF_SZ, GFP_KERNEL, &pdx->pUrbCharIn->transfer_dma); if (!pdx->pCoherCharOut || !pdx->pCoherCharIn || !pdx->pCoherStagedIO) { - dev_err(&interface->dev, "%s Coherent buffer alloc failed", + dev_err(&interface->dev, "%s: Coherent buffer alloc failed\n", __func__); goto error; } @@ -1437,19 +1438,19 @@ static int ced_probe(struct usb_interface *interface, for (i = 0; i < pdx->nPipes; ++i) { endpoint = &iface_desc->endpoint[i].desc; pdx->epAddr[i] = endpoint->bEndpointAddress; - dev_info(&interface->dev, "Pipe %d, ep address %02x", i, - pdx->epAddr[i]); + dev_info(&interface->dev, "Pipe %d, ep address %02x\n", + i, pdx->epAddr[i]); if (((pdx->nPipes == 3) && (i == 0)) || /* if char input end point */ ((pdx->nPipes == 4) && (i == 1))) { pdx->bInterval = endpoint->bInterval; /* save the endpoint interrupt interval */ - dev_info(&interface->dev, "Pipe %d, bInterval = %d", i, - pdx->bInterval); + dev_info(&interface->dev, "Pipe %d, bInterval = %d\n", + i, pdx->bInterval); } /* Detect USB2 by checking last ep size (64 if USB1) */ if (i == pdx->nPipes - 1) { /* if this is the last ep (bulk) */ pdx->bIsUSB2 = le16_to_cpu(endpoint->wMaxPacketSize) > 64; - dev_info(&pdx->interface->dev, "USB%d", + dev_info(&pdx->interface->dev, "USB%d\n", pdx->bIsUSB2 + 1); } } @@ -1462,14 +1463,14 @@ static int ced_probe(struct usb_interface *interface, if (retval) { /* something prevented us from registering this driver */ dev_err(&interface->dev, - "Not able to get a minor for this device.\n"); + "Not able to get a minor for this device\n"); usb_set_intfdata(interface, NULL); goto error; } /* let the user know what node this device is now attached to */ dev_info(&interface->dev, - "USB CEDUSB device now attached to cedusb #%d", + "USB CEDUSB device now attached to cedusb #%d\n", interface->minor); return 0; @@ -1493,7 +1494,7 @@ static void ced_disconnect(struct usb_interface *interface) for (i = 0; i < MAX_TRANSAREAS; ++i) { int iErr = ClearArea(pdx, i); /* ...release any used memory */ if (iErr == U14ERR_UNLOCKFAIL) - dev_err(&pdx->interface->dev, "%s Area %d was in used", + dev_err(&pdx->interface->dev, "%s: Area %d was in used\n", __func__, i); } pdx->interface = NULL; /* ...we kill off link to interface */ @@ -1503,7 +1504,7 @@ static void ced_disconnect(struct usb_interface *interface) kref_put(&pdx->kref, ced_delete); /* decrement our usage count */ - dev_info(&interface->dev, "USB cedusb #%d now disconnected", minor); + dev_info(&interface->dev, "USB cedusb #%d now disconnected\n", minor); } /* Wait for all the urbs we know of to be done with, then kill off any that */ @@ -1513,13 +1514,13 @@ static void ced_disconnect(struct usb_interface *interface) void ced_draw_down(DEVICE_EXTENSION *pdx) { int time; - dev_dbg(&pdx->interface->dev, "%s called", __func__); + dev_dbg(&pdx->interface->dev, "%s: called\n", __func__); pdx->bInDrawDown = true; time = usb_wait_anchor_empty_timeout(&pdx->submitted, 3000); if (!time) { /* if we timed out we kill the urbs */ usb_kill_anchored_urbs(&pdx->submitted); - dev_err(&pdx->interface->dev, "%s timed out", __func__); + dev_err(&pdx->interface->dev, "%s: timed out\n", __func__); } pdx->bInDrawDown = false; } @@ -1531,7 +1532,7 @@ static int ced_suspend(struct usb_interface *intf, pm_message_t message) return 0; ced_draw_down(pdx); - dev_dbg(&pdx->interface->dev, "%s called", __func__); + dev_dbg(&pdx->interface->dev, "%s: called\n", __func__); return 0; } @@ -1540,14 +1541,14 @@ static int ced_resume(struct usb_interface *intf) DEVICE_EXTENSION *pdx = usb_get_intfdata(intf); if (!pdx) return 0; - dev_dbg(&pdx->interface->dev, "%s called", __func__); + dev_dbg(&pdx->interface->dev, "%s: called\n", __func__); return 0; } static int ced_pre_reset(struct usb_interface *intf) { DEVICE_EXTENSION *pdx = usb_get_intfdata(intf); - dev_dbg(&pdx->interface->dev, "%s", __func__); + dev_dbg(&pdx->interface->dev, "%s\n", __func__); mutex_lock(&pdx->io_mutex); ced_draw_down(pdx); return 0; @@ -1556,7 +1557,7 @@ static int ced_pre_reset(struct usb_interface *intf) static int ced_post_reset(struct usb_interface *intf) { DEVICE_EXTENSION *pdx = usb_get_intfdata(intf); - dev_dbg(&pdx->interface->dev, "%s", __func__); + dev_dbg(&pdx->interface->dev, "%s\n", __func__); /* we are sure no URBs are active - no locking needed */ pdx->errors = -EPIPE; diff --git a/drivers/staging/ced1401/usb1401.h b/drivers/staging/ced1401/usb1401.h index f031e3a2c7cf..ea0fe6398a01 100644 --- a/drivers/staging/ced1401/usb1401.h +++ b/drivers/staging/ced1401/usb1401.h @@ -218,9 +218,9 @@ extern bool QuickCheck(DEVICE_EXTENSION *pdx, bool bTestBuff, bool bCanReset); extern int Reset1401(DEVICE_EXTENSION *pdx); extern int GetChar(DEVICE_EXTENSION *pdx); extern int GetString(DEVICE_EXTENSION *pdx, char __user *pUser, int n); -extern int SetTransfer(DEVICE_EXTENSION *pdx, TRANSFERDESC __user *pTD); +extern int SetTransfer(DEVICE_EXTENSION *pdx, struct transfer_area_desc __user *pTD); extern int UnsetTransfer(DEVICE_EXTENSION *pdx, int nArea); -extern int SetEvent(DEVICE_EXTENSION *pdx, TRANSFEREVENT __user *pTE); +extern int SetEvent(DEVICE_EXTENSION *pdx, struct transfer_event __user *pTE); extern int Stat1401(DEVICE_EXTENSION *pdx); extern int LineCount(DEVICE_EXTENSION *pdx); extern int GetOutBufSpace(DEVICE_EXTENSION *pdx); @@ -238,7 +238,7 @@ extern int DbgRampData(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB); extern int DbgRampAddr(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB); extern int DbgGetData(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB); extern int DbgStopLoop(DEVICE_EXTENSION *pdx); -extern int SetCircular(DEVICE_EXTENSION *pdx, TRANSFERDESC __user *pTD); +extern int SetCircular(DEVICE_EXTENSION *pdx, struct transfer_area_desc __user *pTD); extern int GetCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user *pCB); extern int FreeCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user *pCB); extern int WaitEvent(DEVICE_EXTENSION *pdx, int nArea, int msTimeOut); diff --git a/drivers/staging/ced1401/use14_ioc.h b/drivers/staging/ced1401/use14_ioc.h index 97d7913840dc..42d2e4e6e9a9 100644 --- a/drivers/staging/ced1401/use14_ioc.h +++ b/drivers/staging/ced1401/use14_ioc.h @@ -276,15 +276,14 @@ typedef struct paramBlk { typedef PARAMBLK* PPARAMBLK; -typedef struct TransferDesc /* Structure and type for SetTransArea */ +struct transfer_area_desc /* Structure and type for SetTransArea */ { unsigned short wArea; /* number of transfer area to set up */ void FAR *lpvBuff; /* address of transfer area */ unsigned int dwLength; /* length of area to set up */ short eSize; /* size to move (for swapping on MAC) */ -} TRANSFERDESC; +}; -typedef TRANSFERDESC FAR *LPTRANSFERDESC; /* This is the structure used to set up a transfer area */ typedef struct VXTransferDesc /* use1401.c and use1432x.x use only */ diff --git a/drivers/staging/ced1401/userspace/use1401.c b/drivers/staging/ced1401/userspace/use1401.c index c9bc2ebfef1a..7b8a2227fe5b 100644 --- a/drivers/staging/ced1401/userspace/use1401.c +++ b/drivers/staging/ced1401/userspace/use1401.c @@ -2231,7 +2231,7 @@ U14API(short) U14UnSetTransfer(short hand, unsigned short wArea) U14API(short) U14SetTransArea(short hand, unsigned short wArea, void *pvBuff, unsigned int dwLength, short eSz) { - TRANSFERDESC td; + struct transfer_area_desc td; short sErr = CheckHandle(hand); if (sErr != U14ERR_NOERROR) return sErr; @@ -2292,7 +2292,7 @@ U14API(short) U14SetTransArea(short hand, unsigned short wArea, void *pvBuff, td.eSize = 0; // Dummy element size if (DeviceIoControl(aHand1401[hand],(unsigned int)U14_SETTRANSFER, - &td,sizeof(TRANSFERDESC), + &td,sizeof(struct transfer_area_desc), &rWork,sizeof(PARAMBLK),&dwBytes,NULL)) { if (dwBytes >= sizeof(PARAMBLK)) // maybe error from driver? @@ -2496,14 +2496,14 @@ U14API(short) U14SetCircular(short hand, unsigned short wArea, BOOL bToHost, { PARAMBLK rWork; unsigned int dwBytes; - TRANSFERDESC txDesc; + struct transfer_area_desc txDesc; txDesc.wArea = wArea; /* Pure NT - put data into struct */ txDesc.lpvBuff = pvBuff; txDesc.dwLength = dwLength; txDesc.eSize = (short)bToHost; /* Use this for direction flag */ if (DeviceIoControl(aHand1401[hand],(unsigned int)U14_SETCIRCULAR, - &txDesc, sizeof(TRANSFERDESC), + &txDesc, sizeof(struct transfer_area_desc), &rWork, sizeof(PARAMBLK),&dwBytes,NULL)) { if (dwBytes >= sizeof(PARAMBLK)) /* error from driver? */ @@ -2528,7 +2528,7 @@ U14API(short) U14SetCircular(short hand, unsigned short wArea, BOOL bToHost, #ifdef LINUX else { - TRANSFERDESC td; + struct transfer_area_desc td; td.lpvBuff = (long long)((unsigned long)pvBuff); td.wAreaNum = wArea; td.dwLength = dwLength; diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 89e25b4203ad..703c5d40ae5c 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -177,6 +177,7 @@ config COMEDI_PCL730 config COMEDI_PCL812 tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216" depends on VIRT_TO_BUS && ISA_DMA_API + select COMEDI_FC ---help--- Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA, @@ -188,6 +189,7 @@ config COMEDI_PCL812 config COMEDI_PCL816 tristate "Advantech PCL-814 and PCL-816 ISA card support" depends on VIRT_TO_BUS && ISA_DMA_API + select COMEDI_FC ---help--- Enable support for Advantech PCL-814 and PCL-816 ISA cards @@ -197,6 +199,7 @@ config COMEDI_PCL816 config COMEDI_PCL818 tristate "Advantech PCL-718 and PCL-818 ISA card support" depends on VIRT_TO_BUS && ISA_DMA_API + select COMEDI_FC ---help--- Enable support for Advantech PCL-818 ISA cards PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718 @@ -257,6 +260,14 @@ config COMEDI_RTI802 To compile this driver as a module, choose M here: the module will be called rti802. +config COMEDI_DAC02 + tristate "Keithley Metrabyte DAC02 compatible ISA card support" + ---help--- + Enable support for Keithley Metrabyte DAC02 compatible ISA cards. + + To compile this driver as a module, choose M here: the module will be + called dac02. + config COMEDI_DAS16M1 tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support" select COMEDI_8255 @@ -559,15 +570,6 @@ config COMEDI_MULTIQ3 To compile this driver as a module, choose M here: the module will be called multiq3. -config COMEDI_POC - tristate "Generic driver for very simple devices" - ---help--- - Enable generic support for very simple / POC (Piece of Crap) boards, - Keithley Metrabyte DAC-02 (dac02). - - To compile this driver as a module, choose M here: the module will be - called poc. - config COMEDI_S526 tristate "Sensoray s526 support" ---help--- @@ -753,6 +755,7 @@ config COMEDI_ADL_PCI9118 config COMEDI_ADV_PCI1710 tristate "Advantech PCI-171x, PCI-1720 and PCI-1731 support" + select COMEDI_FC ---help--- Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, PCI-1720 and PCI-1731 @@ -856,6 +859,7 @@ config COMEDI_DAS08_PCI config COMEDI_DT3000 tristate "Data Translation DT3000 series support" + select COMEDI_FC ---help--- Enable support for Data Translation DT3000 series DT3001, DT3001-PGL, DT3002, DT3003, DT3003-PGL, DT3004, DT3005 and @@ -1101,6 +1105,7 @@ config COMEDI_S626 config COMEDI_MITE depends on HAS_DMA + select COMEDI_FC tristate config COMEDI_NI_TIOCMD @@ -1179,6 +1184,7 @@ config COMEDI_NI_MIO_CS config COMEDI_QUATECH_DAQP_CS tristate "Quatech DAQP PCMCIA data capture card support" + select COMEDI_FC ---help--- Enable support for the Quatech DAQP PCMCIA data capture cards DAQP-208 and DAQP-308 diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index c22c617b0da1..ea6dc36d753b 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -297,7 +297,7 @@ static ssize_t max_read_buffer_kb_show(struct device *csdev, mutex_unlock(&dev->mutex); comedi_dev_put(dev); - return snprintf(buf, PAGE_SIZE, "%i\n", size); + return snprintf(buf, PAGE_SIZE, "%u\n", size); } static ssize_t max_read_buffer_kb_store(struct device *csdev, @@ -353,7 +353,7 @@ static ssize_t read_buffer_kb_show(struct device *csdev, mutex_unlock(&dev->mutex); comedi_dev_put(dev); - return snprintf(buf, PAGE_SIZE, "%i\n", size); + return snprintf(buf, PAGE_SIZE, "%u\n", size); } static ssize_t read_buffer_kb_store(struct device *csdev, @@ -410,7 +410,7 @@ static ssize_t max_write_buffer_kb_show(struct device *csdev, mutex_unlock(&dev->mutex); comedi_dev_put(dev); - return snprintf(buf, PAGE_SIZE, "%i\n", size); + return snprintf(buf, PAGE_SIZE, "%u\n", size); } static ssize_t max_write_buffer_kb_store(struct device *csdev, @@ -466,7 +466,7 @@ static ssize_t write_buffer_kb_show(struct device *csdev, mutex_unlock(&dev->mutex); comedi_dev_put(dev); - return snprintf(buf, PAGE_SIZE, "%i\n", size); + return snprintf(buf, PAGE_SIZE, "%u\n", size); } static ssize_t write_buffer_kb_store(struct device *csdev, @@ -1194,6 +1194,11 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, switch (insn->insn) { case INSN_READ: ret = s->insn_read(dev, s, insn, data); + if (ret == -ETIMEDOUT) { + dev_dbg(dev->class_dev, + "subdevice %d read instruction timed out\n", + s->index); + } break; case INSN_WRITE: maxdata = s->maxdata_list @@ -1207,8 +1212,14 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, break; } } - if (ret == 0) + if (ret == 0) { ret = s->insn_write(dev, s, insn, data); + if (ret == -ETIMEDOUT) { + dev_dbg(dev->class_dev, + "subdevice %d write instruction timed out\n", + s->index); + } + } break; case INSN_BITS: if (insn->n != 2) { @@ -1405,41 +1416,94 @@ error: return ret; } +static int __comedi_get_user_cmd(struct comedi_device *dev, + struct comedi_cmd __user *arg, + struct comedi_cmd *cmd) +{ + struct comedi_subdevice *s; + + if (copy_from_user(cmd, arg, sizeof(*cmd))) { + dev_dbg(dev->class_dev, "bad cmd address\n"); + return -EFAULT; + } + + if (cmd->subdev >= dev->n_subdevices) { + dev_dbg(dev->class_dev, "%d no such subdevice\n", cmd->subdev); + return -ENODEV; + } + + s = &dev->subdevices[cmd->subdev]; + + if (s->type == COMEDI_SUBD_UNUSED) { + dev_dbg(dev->class_dev, "%d not valid subdevice\n", cmd->subdev); + return -EIO; + } + + if (!s->do_cmd || !s->do_cmdtest || !s->async) { + dev_dbg(dev->class_dev, + "subdevice %d does not support commands\n", cmd->subdev); + return -EIO; + } + + /* make sure channel/gain list isn't too long */ + if (cmd->chanlist_len > s->len_chanlist) { + dev_dbg(dev->class_dev, "channel/gain list too long %d > %d\n", + cmd->chanlist_len, s->len_chanlist); + return -EINVAL; + } + + return 0; +} + +static int __comedi_get_user_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int __user *user_chanlist, + struct comedi_cmd *cmd) +{ + unsigned int *chanlist; + int ret; + + /* user_chanlist could be NULL for do_cmdtest ioctls */ + if (!user_chanlist) + return 0; + + chanlist = memdup_user(user_chanlist, + cmd->chanlist_len * sizeof(unsigned int)); + if (IS_ERR(chanlist)) + return PTR_ERR(chanlist); + + /* make sure each element in channel/gain list is valid */ + ret = comedi_check_chanlist(s, cmd->chanlist_len, chanlist); + if (ret < 0) { + kfree(chanlist); + return ret; + } + + cmd->chanlist = chanlist; + + return 0; +} + static int do_cmd_ioctl(struct comedi_device *dev, struct comedi_cmd __user *arg, void *file) { struct comedi_cmd cmd; struct comedi_subdevice *s; struct comedi_async *async; - int ret = 0; unsigned int __user *user_chanlist; + int ret; + + /* get the user's cmd and do some simple validation */ + ret = __comedi_get_user_cmd(dev, arg, &cmd); + if (ret) + return ret; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - dev_dbg(dev->class_dev, "bad cmd address\n"); - return -EFAULT; - } /* save user's chanlist pointer so it can be restored later */ user_chanlist = (unsigned int __user *)cmd.chanlist; - if (cmd.subdev >= dev->n_subdevices) { - dev_dbg(dev->class_dev, "%d no such subdevice\n", cmd.subdev); - return -ENODEV; - } - s = &dev->subdevices[cmd.subdev]; async = s->async; - if (s->type == COMEDI_SUBD_UNUSED) { - dev_dbg(dev->class_dev, "%d not valid subdevice\n", cmd.subdev); - return -EIO; - } - - if (!s->do_cmd || !s->do_cmdtest || !s->async) { - dev_dbg(dev->class_dev, - "subdevice %i does not support commands\n", cmd.subdev); - return -EIO; - } - /* are we locked? (ioctl lock) */ if (s->lock && s->lock != file) { dev_dbg(dev->class_dev, "subdevice locked\n"); @@ -1452,13 +1516,6 @@ static int do_cmd_ioctl(struct comedi_device *dev, return -EBUSY; } - /* make sure channel/gain list isn't too long */ - if (cmd.chanlist_len > s->len_chanlist) { - dev_dbg(dev->class_dev, "channel/gain list too long %u > %d\n", - cmd.chanlist_len, s->len_chanlist); - return -EINVAL; - } - /* make sure channel/gain list isn't too short */ if (cmd.chanlist_len < 1) { dev_dbg(dev->class_dev, "channel/gain list too short %u < 1\n", @@ -1468,25 +1525,11 @@ static int do_cmd_ioctl(struct comedi_device *dev, async->cmd = cmd; async->cmd.data = NULL; - /* load channel/gain list */ - async->cmd.chanlist = memdup_user(user_chanlist, - async->cmd.chanlist_len * sizeof(int)); - if (IS_ERR(async->cmd.chanlist)) { - ret = PTR_ERR(async->cmd.chanlist); - async->cmd.chanlist = NULL; - dev_dbg(dev->class_dev, "memdup_user failed with code %d\n", - ret); - goto cleanup; - } - /* make sure each element in channel/gain list is valid */ - ret = comedi_check_chanlist(s, - async->cmd.chanlist_len, - async->cmd.chanlist); - if (ret < 0) { - dev_dbg(dev->class_dev, "bad chanlist\n"); + /* load channel/gain list */ + ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &async->cmd); + if (ret) goto cleanup; - } ret = s->do_cmdtest(dev, s, &async->cmd); @@ -1554,63 +1597,24 @@ static int do_cmdtest_ioctl(struct comedi_device *dev, { struct comedi_cmd cmd; struct comedi_subdevice *s; - int ret = 0; unsigned int *chanlist = NULL; unsigned int __user *user_chanlist; + int ret; + + /* get the user's cmd and do some simple validation */ + ret = __comedi_get_user_cmd(dev, arg, &cmd); + if (ret) + return ret; - if (copy_from_user(&cmd, arg, sizeof(cmd))) { - dev_dbg(dev->class_dev, "bad cmd address\n"); - return -EFAULT; - } /* save user's chanlist pointer so it can be restored later */ user_chanlist = (unsigned int __user *)cmd.chanlist; - if (cmd.subdev >= dev->n_subdevices) { - dev_dbg(dev->class_dev, "%d no such subdevice\n", cmd.subdev); - return -ENODEV; - } - s = &dev->subdevices[cmd.subdev]; - if (s->type == COMEDI_SUBD_UNUSED) { - dev_dbg(dev->class_dev, "%d not valid subdevice\n", cmd.subdev); - return -EIO; - } - - if (!s->do_cmd || !s->do_cmdtest) { - dev_dbg(dev->class_dev, - "subdevice %i does not support commands\n", cmd.subdev); - return -EIO; - } - - /* make sure channel/gain list isn't too long */ - if (cmd.chanlist_len > s->len_chanlist) { - dev_dbg(dev->class_dev, "channel/gain list too long %d > %d\n", - cmd.chanlist_len, s->len_chanlist); - ret = -EINVAL; - goto cleanup; - } /* load channel/gain list */ - if (cmd.chanlist) { - chanlist = memdup_user(user_chanlist, - cmd.chanlist_len * sizeof(int)); - if (IS_ERR(chanlist)) { - ret = PTR_ERR(chanlist); - chanlist = NULL; - dev_dbg(dev->class_dev, - "memdup_user exited with code %d", ret); - goto cleanup; - } - - /* make sure each element in channel/gain list is valid */ - ret = comedi_check_chanlist(s, cmd.chanlist_len, chanlist); - if (ret < 0) { - dev_dbg(dev->class_dev, "bad chanlist\n"); - goto cleanup; - } - - cmd.chanlist = chanlist; - } + ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &cmd); + if (ret) + return ret; ret = s->do_cmdtest(dev, s, &cmd); @@ -1620,9 +1624,8 @@ static int do_cmdtest_ioctl(struct comedi_device *dev, if (copy_to_user(arg, &cmd, sizeof(cmd))) { dev_dbg(dev->class_dev, "bad cmd address\n"); ret = -EFAULT; - goto cleanup; } -cleanup: + kfree(chanlist); return ret; diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h index f82bd4256d51..d46123a97582 100644 --- a/drivers/staging/comedi/comedidev.h +++ b/drivers/staging/comedi/comedidev.h @@ -61,31 +61,31 @@ struct comedi_subdevice { unsigned int *chanlist; /* driver-owned chanlist (not used) */ - int (*insn_read) (struct comedi_device *, struct comedi_subdevice *, + int (*insn_read)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*insn_write)(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *, unsigned int *); - int (*insn_write) (struct comedi_device *, struct comedi_subdevice *, + int (*insn_bits)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*insn_config)(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *, unsigned int *); - int (*insn_bits) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*insn_config) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*do_cmd) (struct comedi_device *, struct comedi_subdevice *); - int (*do_cmdtest) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_cmd *); - int (*poll) (struct comedi_device *, struct comedi_subdevice *); - int (*cancel) (struct comedi_device *, struct comedi_subdevice *); + int (*do_cmd)(struct comedi_device *, struct comedi_subdevice *); + int (*do_cmdtest)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_cmd *); + int (*poll)(struct comedi_device *, struct comedi_subdevice *); + int (*cancel)(struct comedi_device *, struct comedi_subdevice *); /* int (*do_lock)(struct comedi_device *, struct comedi_subdevice *); */ /* int (*do_unlock)(struct comedi_device *, \ struct comedi_subdevice *); */ /* called when the buffer changes */ - int (*buf_change) (struct comedi_device *dev, - struct comedi_subdevice *s, unsigned long new_size); + int (*buf_change)(struct comedi_device *dev, + struct comedi_subdevice *s, unsigned long new_size); - void (*munge) (struct comedi_device *dev, struct comedi_subdevice *s, - void *data, unsigned int num_bytes, - unsigned int start_chan_index); + void (*munge)(struct comedi_device *dev, struct comedi_subdevice *s, + void *data, unsigned int num_bytes, + unsigned int start_chan_index); enum dma_data_direction async_dma_dir; unsigned int state; @@ -146,8 +146,8 @@ struct comedi_async { unsigned int cb_mask; - int (*inttrig) (struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int x); + int (*inttrig)(struct comedi_device *dev, struct comedi_subdevice *s, + unsigned int x); }; struct comedi_driver { @@ -155,9 +155,9 @@ struct comedi_driver { const char *driver_name; struct module *module; - int (*attach) (struct comedi_device *, struct comedi_devconfig *); - void (*detach) (struct comedi_device *); - int (*auto_attach) (struct comedi_device *, unsigned long); + int (*attach)(struct comedi_device *, struct comedi_devconfig *); + void (*detach)(struct comedi_device *); + int (*auto_attach)(struct comedi_device *, unsigned long); /* number of elements in board_name and board_id arrays */ unsigned int num_names; @@ -202,8 +202,8 @@ struct comedi_device { struct fasync_struct *async_queue; - int (*open) (struct comedi_device *dev); - void (*close) (struct comedi_device *dev); + int (*open)(struct comedi_device *dev); + void (*close)(struct comedi_device *dev); }; static inline const void *comedi_board(const struct comedi_device *dev) @@ -353,6 +353,14 @@ void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset, /* drivers.c - general comedi driver functions */ +#define COMEDI_TIMEOUT_MS 1000 + +int comedi_timeout(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, + int (*cb)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned long context), + unsigned long context); + int comedi_dio_insn_config(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *, unsigned int *data, unsigned int mask); diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index 5b15033a94bf..ab0e8ed47291 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -154,6 +154,36 @@ int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s, return -EINVAL; } +/** + * comedi_timeout() - busy-wait for a driver condition to occur. + * @dev: comedi_device struct + * @s: comedi_subdevice struct + * @insn: comedi_insn struct + * @cb: callback to check for the condition + * @context: private context from the driver + */ +int comedi_timeout(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + int (*cb)(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context), + unsigned long context) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(COMEDI_TIMEOUT_MS); + int ret; + + while (time_before(jiffies, timeout)) { + ret = cb(dev, s, insn, context); + if (ret != -EBUSY) + return ret; /* success (0) or non EBUSY errno */ + cpu_relax(); + } + return -ETIMEDOUT; +} +EXPORT_SYMBOL_GPL(comedi_timeout); + /** * comedi_dio_insn_config() - boilerplate (*insn_config) for DIO subdevices. * @dev: comedi_device struct diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c index 8a57c3c1ade0..46a385c29ba8 100644 --- a/drivers/staging/comedi/drivers/8255_pci.c +++ b/drivers/staging/comedi/drivers/8255_pci.c @@ -56,6 +56,7 @@ Configuration Options: not applicable, uses PCI auto config #include "../comedidev.h" #include "8255.h" +#include "mite.h" enum pci_8255_boardid { BOARD_ADLINK_PCI7224, @@ -79,6 +80,7 @@ struct pci_8255_boardinfo { const char *name; int dio_badr; int n_8255; + unsigned int has_mite:1; }; static const struct pci_8255_boardinfo pci_8255_boards[] = { @@ -126,36 +128,43 @@ static const struct pci_8255_boardinfo pci_8255_boards[] = { .name = "ni_pci-dio-96", .dio_badr = 1, .n_8255 = 4, + .has_mite = 1, }, [BOARD_NI_PCIDIO96B] = { .name = "ni_pci-dio-96b", .dio_badr = 1, .n_8255 = 4, + .has_mite = 1, }, [BOARD_NI_PXI6508] = { .name = "ni_pxi-6508", .dio_badr = 1, .n_8255 = 4, + .has_mite = 1, }, [BOARD_NI_PCI6503] = { .name = "ni_pci-6503", .dio_badr = 1, .n_8255 = 1, + .has_mite = 1, }, [BOARD_NI_PCI6503B] = { .name = "ni_pci-6503b", .dio_badr = 1, .n_8255 = 1, + .has_mite = 1, }, [BOARD_NI_PCI6503X] = { .name = "ni_pci-6503x", .dio_badr = 1, .n_8255 = 1, + .has_mite = 1, }, [BOARD_NI_PXI_6503] = { .name = "ni_pxi-6503", .dio_badr = 1, .n_8255 = 1, + .has_mite = 1, }, }; @@ -163,6 +172,25 @@ struct pci_8255_private { void __iomem *mmio_base; }; +static int pci_8255_mite_init(struct pci_dev *pcidev) +{ + void __iomem *mite_base; + u32 main_phys_addr; + + /* ioremap the MITE registers (BAR 0) temporarily */ + mite_base = pci_ioremap_bar(pcidev, 0); + if (!mite_base) + return -ENOMEM; + + /* set data window to main registers (BAR 1) */ + main_phys_addr = pci_resource_start(pcidev, 1); + writel(main_phys_addr | WENAB, mite_base + MITE_IODWBSR); + + /* finished with MITE registers */ + iounmap(mite_base); + return 0; +} + static int pci_8255_mmio(int dir, int port, int data, unsigned long iobase) { void __iomem *mmio_base = (void __iomem *)iobase; @@ -201,6 +229,12 @@ static int pci_8255_auto_attach(struct comedi_device *dev, if (ret) return ret; + if (board->has_mite) { + ret = pci_8255_mite_init(pcidev); + if (ret) + return ret; + } + is_mmio = (pci_resource_flags(pcidev, board->dio_badr) & IORESOURCE_MEM) != 0; if (is_mmio) { @@ -235,9 +269,6 @@ static int pci_8255_auto_attach(struct comedi_device *dev, return ret; } - dev_info(dev->class_dev, "%s attached (%d digital i/o channels)\n", - dev->board_name, board->n_8255 * 24); - return 0; } diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile index 2706f583d8f0..0757a82ddcfa 100644 --- a/drivers/staging/comedi/drivers/Makefile +++ b/drivers/staging/comedi/drivers/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_COMEDI_PCL818) += pcl818.o obj-$(CONFIG_COMEDI_PCM3724) += pcm3724.o obj-$(CONFIG_COMEDI_RTI800) += rti800.o obj-$(CONFIG_COMEDI_RTI802) += rti802.o +obj-$(CONFIG_COMEDI_DAC02) += dac02.o obj-$(CONFIG_COMEDI_DAS16M1) += das16m1.o obj-$(CONFIG_COMEDI_DAS08_ISA) += das08_isa.o obj-$(CONFIG_COMEDI_DAS16) += das16.o @@ -53,7 +54,6 @@ obj-$(CONFIG_COMEDI_PCMDA12) += pcmda12.o obj-$(CONFIG_COMEDI_PCMMIO) += pcmmio.o obj-$(CONFIG_COMEDI_PCMUIO) += pcmuio.o obj-$(CONFIG_COMEDI_MULTIQ3) += multiq3.o -obj-$(CONFIG_COMEDI_POC) += poc.o obj-$(CONFIG_COMEDI_S526) += s526.o # Comedi PCI drivers diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c index 1128c22e7517..28450f65a134 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c @@ -1,46 +1,24 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -@endverbatim -*/ /* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-035 | Compiler : GCC | - | Module name : hwdrv_apci035.c | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-035 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + */ /* Card Specific information */ #define APCI035_ADDRESS_RANGE 255 @@ -106,99 +84,66 @@ static struct comedi_lrange range_apci035_ai = { } }; -static int i_WatchdogNbr = 0; -static int i_Temp = 0; +static int i_WatchdogNbr; +static int i_Temp; static int i_Flag = 1; + /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_ConfigTimerWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Configure As Timer | -| 1 Configure As Watchdog | -| data[1] : Watchdog number -| data[2] : Time base Unit | -| data[3] : Reload Value | -| data[4] : External Trigger | -| 1:Enable -| 0:Disable -| data[5] :External Trigger Level -| 00 Trigger Disabled -| 01 Trigger Enabled (Low level) -| 10 Trigger Enabled (High Level) -| 11 Trigger Enabled (High/Low level) -| data[6] : External Gate | -| 1:Enable -| 0:Disable -| data[7] : External Gate level -| 00 Gate Disabled -| 01 Gate Enabled (Low level) -| 10 Gate Enabled (High Level) -| data[8] :Warning Relay -| 1: ENABLE -| 0: DISABLE -| data[9] :Warning Delay available -| data[10] :Warning Relay Time unit -| data[11] :Warning Relay Time Reload value -| data[12] :Reset Relay -| 1 : ENABLE -| 0 : DISABLE -| data[13] :Interrupt -| 1 : ENABLE -| 0 : DISABLE -| -| -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures The Timer , Counter or Watchdog + * + * data[0] 0 = Configure As Timer, 1 = Configure As Watchdog + * data[1] Watchdog number + * data[2] Time base Unit + * data[3] Reload Value + * data[4] External Trigger, 1 = Enable, 0 = Disable + * data[5] External Trigger Level + * 00 = Trigger Disabled + * 01 = Trigger Enabled (Low level) + * 10 = Trigger Enabled (High Level) + * 11 = Trigger Enabled (High/Low level) + * data[6] External Gate, 1 = Enable, 0 = Disable + * data[7] External Gate level + * 00 = Gate Disabled + * 01 = Gate Enabled (Low level) + * 10 = Gate Enabled (High Level) + * data[8] Warning Relay, 1 = Enable, 0 = Disable + * data[9] Warning Delay available + * data[10] Warning Relay Time unit + * data[11] Warning Relay Time Reload value + * data[12] Reset Relay, 1 = Enable, 0 = Disable + * data[13] Interrupt, 1 = Enable, 0 = Disable + */ +static int apci035_timer_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int ui_Status = 0; - unsigned int ui_Command = 0; - unsigned int ui_Mode = 0; + unsigned int ui_Status; + unsigned int ui_Command; + unsigned int ui_Mode; i_Temp = 0; devpriv->tsk_Current = current; devpriv->b_TimerSelectMode = data[0]; i_WatchdogNbr = data[1]; - if (data[0] == 0) { + if (data[0] == 0) ui_Mode = 2; - } else { + else ui_Mode = 0; - } -/* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); */ + ui_Command = 0; -/* ui_Command = ui_Command & 0xFFFFF9FEUL; */ outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/************************/ -/* Set the reload value */ -/************************/ + + /* Set the reload value */ outl(data[3], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 4); -/*********************/ -/* Set the time unit */ -/*********************/ + + /* Set the time unit */ outl(data[2], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 8); if (data[0] == ADDIDATA_TIMER) { - /******************************/ /* Set the mode : */ /* - Disable the hardware */ /* - Disable the counter mode */ @@ -206,101 +151,82 @@ static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, /* - Disable the reset */ /* - Enable the timer mode */ /* - Set the timer mode */ - /******************************/ ui_Command = (ui_Command & 0xFFF719E2UL) | ui_Mode << 13UL | 0x10UL; - } /* if (data[0] == ADDIDATA_TIMER) */ - else { - if (data[0] == ADDIDATA_WATCHDOG) { + } else if (data[0] == ADDIDATA_WATCHDOG) { - /******************************/ - /* Set the mode : */ - /* - Disable the hardware */ - /* - Disable the counter mode */ - /* - Disable the warning */ - /* - Disable the reset */ - /* - Disable the timer mode */ - /******************************/ + /* Set the mode : */ + /* - Disable the hardware */ + /* - Disable the counter mode */ + /* - Disable the warning */ + /* - Disable the reset */ + /* - Disable the timer mode */ - ui_Command = ui_Command & 0xFFF819E2UL; + ui_Command = ui_Command & 0xFFF819E2UL; - } else { - printk("\n The parameter for Timer/watchdog selection is in error\n"); - return -EINVAL; - } + } else { + dev_err(dev->class_dev, "The parameter for Timer/watchdog selection is in error\n"); + return -EINVAL; } + outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/********************************/ -/* Disable the hardware trigger */ -/********************************/ + + /* Disable the hardware trigger */ ui_Command = ui_Command & 0xFFFFF89FUL; if (data[4] == ADDIDATA_ENABLE) { - /**********************************/ + /* Set the hardware trigger level */ - /**********************************/ ui_Command = ui_Command | (data[5] << 5); } outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/*****************************/ -/* Disable the hardware gate */ -/*****************************/ + + /* Disable the hardware gate */ ui_Command = ui_Command & 0xFFFFF87FUL; if (data[6] == ADDIDATA_ENABLE) { -/*******************************/ -/* Set the hardware gate level */ -/*******************************/ + + /* Set the hardware gate level */ ui_Command = ui_Command | (data[7] << 7); } outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/*******************************/ -/* Disable the hardware output */ -/*******************************/ + + /* Disable the hardware output */ ui_Command = ui_Command & 0xFFFFF9FBUL; -/*********************************/ -/* Set the hardware output level */ -/*********************************/ + + /* Set the hardware output level */ ui_Command = ui_Command | (data[8] << 2); outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); if (data[9] == ADDIDATA_ENABLE) { - /************************/ + /* Set the reload value */ - /************************/ outl(data[11], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 24); - /**********************/ + /* Set the time unite */ - /**********************/ outl(data[10], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 28); } - ui_Command = 0; ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /*******************************/ + /* Disable the hardware output */ - /*******************************/ ui_Command = ui_Command & 0xFFFFF9F7UL; - /*********************************/ + /* Set the hardware output level */ - /*********************************/ ui_Command = ui_Command | (data[12] << 3); outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /*************************************/ - /** Enable the watchdog interrupt **/ - /*************************************/ - ui_Command = 0; + + /* Enable the watchdog interrupt */ ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/*******************************/ -/* Set the interrupt selection */ -/*******************************/ + + /* Set the interrupt selection */ ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16); ui_Command = (ui_Command & 0xFFFFF9FDUL) | (data[13] << 1); @@ -310,82 +236,63 @@ static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_StartStopWriteTimerWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Start / Stop The Selected Timer , or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 - Stop Selected Timer/Watchdog | -| 1 - Start Selected Timer/Watchdog | -| 2 - Trigger Selected Timer/Watchdog | -| 3 - Stop All Timer/Watchdog | -| 4 - Start All Timer/Watchdog | -| 5 - Trigger All Timer/Watchdog | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Start / Stop The Selected Timer , or Watchdog + * + * data[0] + * 0 - Stop Selected Timer/Watchdog + * 1 - Start Selected Timer/Watch*dog + * 2 - Trigger Selected Timer/Watchdog + * 3 - Stop All Timer/Watchdog + * 4 - Start All Timer/Watchdog + * 5 - Trigger All Timer/Watchdog + */ +static int apci035_timer_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int ui_Command = 0; - int i_Count = 0; + unsigned int ui_Command; + int i_Count; if (data[0] == 1) { ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /**********************/ + /* Start the hardware */ - /**********************/ ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x1UL; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - } /* if (data[0]==1) */ + } if (data[0] == 2) { ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /***************************/ + /* Set the trigger command */ - /***************************/ ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x200UL; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); } - if (data[0] == 0) /* Stop The Watchdog */ - { + if (data[0] == 0) { /* Stop The Watchdog */ ui_Command = 0; -/* -* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); -* ui_Command = ui_Command & 0xFFFFF9FEUL; -*/ + /* + * ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); + * ui_Command = ui_Command & 0xFFFFF9FEUL; + */ outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - } /* if (data[1]==0) */ - if (data[0] == 3) /* stop all Watchdogs */ - { + } + if (data[0] == 3) { + /* stop all Watchdogs */ ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { - if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { + if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) ui_Command = 0x2UL; - } else { + else ui_Command = 0x10UL; - } + i_WatchdogNbr = i_Count; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + @@ -393,30 +300,29 @@ static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, } } - if (data[0] == 4) /* start all Watchdogs */ - { + if (data[0] == 4) { + /* start all Watchdogs */ ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { - if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { + if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) ui_Command = 0x1UL; - } else { + else ui_Command = 0x8UL; - } + i_WatchdogNbr = i_Count; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); } } - if (data[0] == 5) /* trigger all Watchdogs */ - { + if (data[0] == 5) { + /* trigger all Watchdogs */ ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { - if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { + if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) ui_Command = 0x4UL; - } else { + else ui_Command = 0x20UL; - } i_WatchdogNbr = i_Count; outl(ui_Command, @@ -429,109 +335,61 @@ static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_ReadTimerWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read The Selected Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] : software trigger status -| data[1] : hardware trigger status -| data[2] : Software clear status -| data[3] : Overflow status -| data[4] : Timer actual value -| - -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_ReadTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read The Selected Timer , Counter or Watchdog + * + * data[0] software trigger status + * data[1] hardware trigger status + * data[2] Software clear status + * data[3] Overflow status + * data[4] Timer actual value + */ +static int apci035_timer_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int ui_Status = 0; /* Status register */ + unsigned int ui_Status; /* Status register */ i_WatchdogNbr = insn->unused[0]; - /******************/ /* Get the status */ - /******************/ - ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16); - /***********************************/ /* Get the software trigger status */ - /***********************************/ - data[0] = ((ui_Status >> 1) & 1); - /***********************************/ - /* Get the hardware trigger status */ - /***********************************/ - data[1] = ((ui_Status >> 2) & 1); - /*********************************/ - /* Get the software clear status */ - /*********************************/ - data[2] = ((ui_Status >> 3) & 1); - /***************************/ - /* Get the overflow status */ - /***************************/ - data[3] = ((ui_Status >> 0) & 1); - if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { - data[4] = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ + /* Get the hardware trigger status */ + data[1] = ((ui_Status >> 2) & 1); + + /* Get the software clear status */ + data[2] = ((ui_Status >> 3) & 1); + + /* Get the overflow status */ + data[3] = ((ui_Status >> 0) & 1); + if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) + data[4] = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_ConfigAnalogInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Analog Input Subdevice | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s : Subdevice Pointer | -| struct comedi_insn *insn : Insn Structure Pointer | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| data[0] : Warning delay value -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_ConfigAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures The Analog Input Subdevice + * + * data[0] Warning delay value + */ +static int apci035_ai_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; devpriv->tsk_Current = current; outl(0x200 | 0, devpriv->iobase + 128 + 0x4); outl(0, devpriv->iobase + 128 + 0); -/********************************/ -/* Initialise the warning value */ -/********************************/ + + /* Initialise the warning value */ outl(0x300 | 0, devpriv->iobase + 128 + 0x4); outl((data[0] << 8), devpriv->iobase + 128 + 0); outl(0x200000UL, devpriv->iobase + 128 + 12); @@ -540,145 +398,88 @@ static int i_APCI035_ConfigAnalogInput(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_ReadAnalogInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read value of the selected channel | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -| data[0] : Digital Value Of Input | -| | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_ReadAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read value of the selected channel + * + * data[0] Digital Value Of Input + */ +static int apci035_ai_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int ui_CommandRegister = 0; + unsigned int ui_CommandRegister; -/******************/ -/* Set the start */ -/******************/ + /* Set the start */ ui_CommandRegister = 0x80000; - /******************************/ + /* Write the command register */ - /******************************/ outl(ui_CommandRegister, devpriv->iobase + 128 + 8); -/***************************************/ -/* Read the digital value of the input */ -/***************************************/ + /* Read the digital value of the input */ data[0] = inl(devpriv->iobase + 128 + 28); return insn->n; } -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_Reset(struct comedi_device *dev) | -| | -+----------------------------------------------------------------------------+ -| Task :Resets the registers of the card | -+----------------------------------------------------------------------------+ -| Input Parameters : | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI035_Reset(struct comedi_device *dev) +static int apci035_reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; - int i_Count = 0; + int i_Count; for (i_Count = 1; i_Count <= 4; i_Count++) { i_WatchdogNbr = i_Count; - outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); /* stop all timers */ + + /* stop all timers */ + outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); } outl(0x0, devpriv->iobase + 128 + 12); /* Disable the warning delay */ return 0; } -/* -+----------------------------------------------------------------------------+ -| Function Name : static void v_APCI035_Interrupt | -| (int irq , void *d) | -+----------------------------------------------------------------------------+ -| Task : Interrupt processing Routine | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq : irq number | -| void *d : void pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static void v_APCI035_Interrupt(int irq, void *d) +static void apci035_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; - unsigned int ui_StatusRegister1 = 0; - unsigned int ui_StatusRegister2 = 0; - unsigned int ui_ReadCommand = 0; - unsigned int ui_ChannelNumber = 0; - unsigned int ui_DigitalTemperature = 0; + unsigned int ui_StatusRegister1; + unsigned int ui_StatusRegister2; + unsigned int ui_ReadCommand; + unsigned int ui_ChannelNumber; + unsigned int ui_DigitalTemperature; if (i_Temp == 1) { i_WatchdogNbr = i_Flag; i_Flag = i_Flag + 1; } - /**************************************/ - /* Read the interrupt status register of temperature Warning */ - /**************************************/ - ui_StatusRegister1 = inl(devpriv->iobase + 128 + 16); - /**************************************/ - /* Read the interrupt status register for Watchdog/timer */ - /**************************************/ + /* Read the interrupt status register of temperature Warning */ + ui_StatusRegister1 = inl(devpriv->iobase + 128 + 16); + + /* Read the interrupt status register for Watchdog/timer */ ui_StatusRegister2 = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 20); - if ((((ui_StatusRegister1) & 0x8) == 0x8)) /* Test if warning relay interrupt */ - { - /**********************************/ + /* Test if warning relay interrupt */ + if ((((ui_StatusRegister1) & 0x8) == 0x8)) { + /* Disable the temperature warning */ - /**********************************/ ui_ReadCommand = inl(devpriv->iobase + 128 + 12); ui_ReadCommand = ui_ReadCommand & 0xFFDF0000UL; outl(ui_ReadCommand, devpriv->iobase + 128 + 12); - /***************************/ - /* Read the channel number */ - /***************************/ - ui_ChannelNumber = inl(devpriv->iobase + 128 + 60); - /**************************************/ - /* Read the digital temperature value */ - /**************************************/ - ui_DigitalTemperature = inl(devpriv->iobase + 128 + 60); - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - } /* if (((ui_StatusRegister1 & 0x8) == 0x8)) */ - else { - if ((ui_StatusRegister2 & 0x1) == 0x1) { - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - } - } /* else if (((ui_StatusRegister1 & 0x8) == 0x8)) */ + /* Read the channel number */ + ui_ChannelNumber = inl(devpriv->iobase + 128 + 60); + + /* Read the digital temperature value */ + ui_DigitalTemperature = inl(devpriv->iobase + 128 + 60); + + /* send signal to the sample */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + + } else if ((ui_StatusRegister2 & 0x1) == 0x1) { + /* send signal to the sample */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + } return; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c index 054910511e9e..a633957890d7 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c @@ -1,48 +1,25 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -@endverbatim -*/ /* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-1500 | Compiler : GCC | - | Module name : hwdrv_apci1500.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-1500 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -/********* Definitions for APCI-1500 card *****/ + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + */ /* Card Specific information */ #define APCI1500_ADDRESS_RANGE 4 @@ -141,99 +118,45 @@ enum { APCI1500_RW_PORT_B_PATTERN_MASK }; -static int i_TimerCounter1Init = 0; -static int i_TimerCounter2Init = 0; -static int i_WatchdogCounter3Init = 0; -static int i_Event1Status = 0, i_Event2Status = 0; -static int i_TimerCounterWatchdogInterrupt = 0; -static int i_Logic = 0, i_CounterLogic = 0; -static int i_InterruptMask = 0; -static int i_InputChannel = 0; -static int i_TimerCounter1Enabled = 0, i_TimerCounter2Enabled = 0, - i_WatchdogCounter3Enabled = 0; +static int i_TimerCounter1Init; +static int i_TimerCounter2Init; +static int i_WatchdogCounter3Init; +static int i_Event1Status, i_Event2Status; +static int i_TimerCounterWatchdogInterrupt; +static int i_Logic, i_CounterLogic; +static int i_InterruptMask; +static int i_InputChannel; +static int i_TimerCounter1Enabled, i_TimerCounter2Enabled, + i_WatchdogCounter3Enabled; /* - +----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ConfigDigitalInputEvent | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : An event can be generated for each port. | -| The first event is related to the first 8 channels | -| (port 1) and the second to the following 6 channels | -| (port 2). An interrupt is generated when one or both | -| events have occurred | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] :Number of the input port on | -| which the event will take place | -| (1 or 2) -| data[1] : The event logic for port 1 has | -| three possibilities | -| :0 APCI1500_AND :This logic | -| links | -| the inputs | -| with an AND | -| logic. | -| 1 APCI1500_OR :This logic | -| links | -| the inputs | -| with a | -| OR logic. | -| 2 APCI1500_OR_PRIORITY | -| :This logic | -| links | -| the inputs | -| with a | -| priority | -| OR logic. | -| Input 1 | -| has the | -| highest | -| priority | -| level and | -| input 8 | -| the smallest| -| For the second port the user has| -| 1 possibility: | -| APCI1500_OR :This logic | -| links | -| the inputs | -| with a | -| polarity | -| OR logic | -| data[2] : These 8-character word for port1| -| and 6-character word for port 2 | -| give the mask of the event. | -| Each place gives the state | -| of the input channels and can | -| have one of these six characters| -| | -| 0 : This input must be on 0 | -| 1 : This input must be on 1 | -| 2 : This input reacts to | -| a falling edge | -| 3 : This input reacts to a | -| rising edge | -| 4 : This input reacts to both edges | -| -| 5 : This input is not | -| used for event | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * An event can be generated for each port. The first event is related to the + * first 8 channels (port 1) and the second to the following 6 channels (port 2) + * An interrupt is generated when one or both events have occurred. + * + * data[0] Number of the input port on which the event will take place (1 or 2) + * data[1] The event logic for port 1 has three possibilities: + * APCI1500_AND This logic links the inputs with an AND logic. + * APCI1500_OR This logic links the inputs with a OR logic. + * APCI1500_OR_PRIORITY This logic links the inputs with a priority OR + * logic. Input 1 has the highest priority level + * and input 8 the smallest. + * For the second port the user has 1 possibility: + * APCI1500_OR This logic links the inputs with a polarity OR logic + * data[2] These 8-character word for port1 and 6-character word for port 2 + * give the mask of the event. Each place gives the state of the input + * channels and can have one of these six characters + * 0 This input must be on 0 + * 1 This input must be on 1 + * 2 This input reacts to a falling edge + * 3 This input reacts to a rising edge + * 4 This input reacts to both edges + * 5 This input is not used for event + */ +static int apci1500_di_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_PatternPolarity = 0, i_PatternTransition = 0, i_PatternMask = 0; @@ -241,14 +164,10 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, int i_PatternTransitionCount = 0, i_RegValue; int i; - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Disables the main interrupt on the board */ - /**********************************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if (data[0] == 1) { @@ -259,7 +178,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, i_MaxChannel = 6; } /* if(data[0]==2) */ else { - printk("\nThe specified port event does not exist\n"); + dev_warn(dev->hw_dev, + "The specified port event does not exist\n"); return -EINVAL; } /* else if(data[0]==2) */ } /* else if (data[0] == 1) */ @@ -274,7 +194,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, data[1] = APCI1500_OR_PRIORITY; break; default: - printk("\nThe specified interrupt logic does not exist\n"); + dev_warn(dev->hw_dev, + "The specified interrupt logic does not exist\n"); return -EINVAL; } /* switch(data[1]); */ @@ -318,37 +239,30 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, case 5: break; default: - printk("\nThe option indicated in the event mask does not exist\n"); + dev_warn(dev->hw_dev, + "The option indicated in the event mask does not exist\n"); return -EINVAL; } /* switch(i_EventMask) */ } /* for (i_Count = i_MaxChannel; i_Count >0;i_Count --) */ if (data[0] == 1) { - /****************************/ /* Test the interrupt logic */ - /****************************/ if (data[1] == APCI1500_AND || data[1] == APCI1500_OR || data[1] == APCI1500_OR_PRIORITY) { - /**************************************/ /* Tests if a transition was declared */ /* for a OR PRIORITY logic */ - /**************************************/ if (data[1] == APCI1500_OR_PRIORITY && i_PatternTransition != 0) { - /********************************************/ - /* Transition error on an OR PRIORITY logic */ - /********************************************/ - printk("\nTransition error on an OR PRIORITY logic\n"); + dev_warn(dev->hw_dev, + "Transition error on an OR PRIORITY logic\n"); return -EINVAL; } /* if (data[1]== APCI1500_OR_PRIORITY && i_PatternTransition != 0) */ - /*************************************/ /* Tests if more than one transition */ /* was declared for an AND logic */ - /*************************************/ if (data[1] == APCI1500_AND) { for (i_Count = 0; i_Count < 8; i_Count++) { @@ -360,29 +274,21 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, } /* for (i_Count = 0; i_Count < 8; i_Count++) */ if (i_PatternTransitionCount > 1) { - /****************************************/ - /* Transition error on an AND logic */ - /****************************************/ - printk("\n Transition error on an AND logic\n"); + dev_warn(dev->hw_dev, + "Transition error on an AND logic\n"); return -EINVAL; } /* if (i_PatternTransitionCount > 1) */ } /* if (data[1]== APCI1500_AND) */ - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port A */ - /******************/ outb(0xF0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Selects the polarity register of port 1 */ - /**********************************************/ outb(APCI1500_RW_PORT_A_PATTERN_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -390,20 +296,16 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Selects the pattern mask register of */ /* port 1 */ - /*********************************************/ outb(APCI1500_RW_PORT_A_PATTERN_MASK, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_PatternMask, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************************/ /* Selects the pattern transition register */ /* of port 1 */ - /********************************************/ outb(APCI1500_RW_PORT_A_PATTERN_TRANSITION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -411,10 +313,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port 1 */ - /******************************************/ outb(APCI1500_RW_PORT_A_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -422,17 +322,13 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port 1 */ - /******************************************/ outb(APCI1500_RW_PORT_A_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************/ /* Port A new mode */ - /**********************/ i_RegValue = (i_RegValue & 0xF9) | data[1] | 0x9; outb(i_RegValue, @@ -441,53 +337,40 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, i_Event1Status = 1; - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port A */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */ else { - printk("\nThe choice for interrupt logic does not exist\n"); + dev_warn(dev->hw_dev, + "The choice for interrupt logic does not exist\n"); return -EINVAL; } /* else }// if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */ } /* if (data[0]== 1) */ - /************************************/ /* Test if event setting for port 2 */ - /************************************/ if (data[0] == 2) { - /************************/ /* Test the event logic */ - /************************/ if (data[1] == APCI1500_OR) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port B */ - /******************/ outb(0x74, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the mode specification mask */ /* register of port B */ - /****************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -495,10 +378,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port B */ - /******************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -507,37 +388,29 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************/ /* Selects error channels 1 and 2 */ - /**********************************/ i_PatternMask = (i_PatternMask | 0xC0); i_PatternPolarity = (i_PatternPolarity | 0xC0); i_PatternTransition = (i_PatternTransition | 0xC0); - /**********************************************/ /* Selects the polarity register of port 2 */ - /**********************************************/ outb(APCI1500_RW_PORT_B_PATTERN_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_PatternPolarity, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Selects the pattern transition register */ /* of port 2 */ - /**********************************************/ outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_PatternTransition, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Selects the pattern Mask register */ /* of port 2 */ - /**********************************************/ outb(APCI1500_RW_PORT_B_PATTERN_MASK, devpriv->iobase + @@ -546,20 +419,16 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port 2 */ - /******************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port 2 */ - /******************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -569,23 +438,20 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); i_Event2Status = 1; - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port B */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if (data[1] == APCI1500_OR) */ else { - printk("\nThe choice for interrupt logic does not exist\n"); + dev_warn(dev->hw_dev, + "The choice for interrupt logic does not exist\n"); return -EINVAL; } /* elseif (data[1] == APCI1500_OR) */ } /* if(data[0]==2) */ @@ -594,31 +460,15 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_StartStopInputEvent | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Allows or disallows a port event | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_Channel : Channel number to read | -| unsigned int *data : Data Pointer to read status | -| data[0] :0 Start input event -| 1 Stop input event -| data[1] :No of port (1 or 2) -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Allows or disallows a port event + * + * data[0] 0 = Start input event, 1 = Stop input event + * data[1] Number of port (1 or 2) + */ +static int apci1500_di_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_Event1InterruptStatus = 0, i_Event2InterruptStatus = @@ -626,48 +476,30 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, switch (data[0]) { case START: - /*************************/ /* Tests the port number */ - /*************************/ if (data[1] == 1 || data[1] == 2) { - /***************************/ /* Test if port 1 selected */ - /***************************/ if (data[1] == 1) { - /*****************************/ /* Test if event initialised */ - /*****************************/ if (i_Event1Status == 1) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port A */ - /******************/ outb(0xF0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the command and status register of */ /* port 1 */ - /***************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Allows the pattern interrupt */ - /*************************************/ outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port A */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -680,185 +512,142 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Authorizes the main interrupt on the board */ - /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if(i_Event1Status==1) */ else { - printk("\nEvent 1 not initialised\n"); + dev_warn(dev->hw_dev, + "Event 1 not initialised\n"); return -EINVAL; } /* else if(i_Event1Status==1) */ } /* if (data[1]==1) */ if (data[1] == 2) { if (i_Event2Status == 1) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port B */ - /******************/ outb(0x74, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the command and status register of */ /* port 2 */ - /***************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Allows the pattern interrupt */ - /*************************************/ outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port B */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Authorizes the main interrupt on the board */ - /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event2InterruptStatus = 1; } /* if(i_Event2Status==1) */ else { - printk("\nEvent 2 not initialised\n"); + dev_warn(dev->hw_dev, + "Event 2 not initialised\n"); return -EINVAL; } /* else if(i_Event2Status==1) */ } /* if(data[1]==2) */ } /* if (data[1] == 1 || data[0] == 2) */ else { - printk("\nThe port parameter is in error\n"); + dev_warn(dev->hw_dev, + "The port parameter is in error\n"); return -EINVAL; } /* else if (data[1] == 1 || data[0] == 2) */ break; case STOP: - /*************************/ /* Tests the port number */ - /*************************/ if (data[1] == 1 || data[1] == 2) { - /***************************/ /* Test if port 1 selected */ - /***************************/ if (data[1] == 1) { - /*****************************/ /* Test if event initialised */ - /*****************************/ if (i_Event1Status == 1) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port A */ - /******************/ outb(0xF0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the command and status register of */ /* port 1 */ - /***************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Inhibits the pattern interrupt */ - /*************************************/ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port A */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event1InterruptStatus = 0; } /* if(i_Event1Status==1) */ else { - printk("\nEvent 1 not initialised\n"); + dev_warn(dev->hw_dev, + "Event 1 not initialised\n"); return -EINVAL; } /* else if(i_Event1Status==1) */ } /* if (data[1]==1) */ if (data[1] == 2) { - /*****************************/ /* Test if event initialised */ - /*****************************/ if (i_Event2Status == 1) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port B */ - /******************/ outb(0x74, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the command and status register of */ /* port 2 */ - /***************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Inhibits the pattern interrupt */ - /*************************************/ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port B */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event2InterruptStatus = 0; } /* if(i_Event2Status==1) */ else { - printk("\nEvent 2 not initialised\n"); + dev_warn(dev->hw_dev, + "Event 2 not initialised\n"); return -EINVAL; } /* else if(i_Event2Status==1) */ } /* if(data[1]==2) */ } /* if (data[1] == 1 || data[1] == 2) */ else { - printk("\nThe port parameter is in error\n"); + dev_warn(dev->hw_dev, + "The port parameter is in error\n"); return -EINVAL; } /* else if (data[1] == 1 || data[1] == 2) */ break; default: - printk("\nThe option of START/STOP logic does not exist\n"); + dev_warn(dev->hw_dev, + "The option of START/STOP logic does not exist\n"); return -EINVAL; } /* switch(data[0]) */ @@ -866,35 +655,17 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_Initialisation | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Return the status of the digital input | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_Channel : Channel number to read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_Initialisation(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Return the status of the digital input + */ +static int apci1500_di_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_DummyRead = 0; - /******************/ /* Software reset */ - /******************/ i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -902,16 +673,12 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the master configuration control register */ - /*****************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the mode specification register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -943,9 +710,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, /* Deletes the register */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the mode specification register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -975,9 +740,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, /* Deletes the register */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the data path polarity register of port C */ - /*****************************************************/ outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* High level of port C means 1 */ @@ -992,9 +755,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes it */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 1 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -1004,9 +765,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates the interrupt management of timer 1 */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 2 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -1016,9 +775,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates Timer 2 interrupt management: */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 3 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -1028,9 +785,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates interrupt management of timer 3: */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes all interrupts */ @@ -1051,37 +806,15 @@ static int apci1500_di_insn_bits(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ConfigDigitalOutputErrorInterrupt -| (struct comedi_device *dev,struct comedi_subdevice *s struct comedi_insn -| *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task : Configures the digital output memory and the digital -| output error interrupt | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| data[0] :1:Memory on | -| 0:Memory off | -| data[1] :1 Enable the voltage error interrupt -| :0 Disable the voltage error interrupt | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures the digital output memory and the digital output error interrupt + * + * data[1] 1 = Enable the voltage error interrupt + * 2 = Disable the voltage error interrupt + */ +static int apci1500_do_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; @@ -1090,31 +823,15 @@ static int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device *de } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_WriteDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Writes port value To the selected port | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To Write | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Writes port value to the selected port + */ +static int apci1500_do_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; - static unsigned int ui_Temp = 0; + static unsigned int ui_Temp; unsigned int ui_Temp1; unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ @@ -1165,7 +882,9 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, APCI1500_DIGITAL_OP); } /* if(data[1]==1) */ else { - printk("\nSpecified channel not supported\n"); + dev_warn(dev->hw_dev, + "Specified channel not supported\n"); + return -EINVAL; } /* else if(data[1]==1) */ } /* elseif(data[1]==0) */ } /* if(data[3]==0) */ @@ -1242,12 +961,15 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, APCI1500_DIGITAL_OP); } /* if(data[1]==1) */ else { - printk("\nSpecified channel not supported\n"); + dev_warn(dev->hw_dev, + "Specified channel not supported\n"); + return -EINVAL; } /* else if(data[1]==1) */ } /* elseif(data[1]==0) */ } /* if(data[3]==1); */ else { - printk("\nSpecified functionality does not exist\n"); + dev_warn(dev->hw_dev, + "Specified functionality does not exist\n"); return -EINVAL; } /* if else data[3]==1) */ } /* if else data[3]==0) */ @@ -1256,57 +978,23 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ConfigCounterTimerWatchdog(comedi_device -| *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)| -| | -+----------------------------------------------------------------------------+ -| Task : Configures The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status data[0] : 2 APCI1500_1_8_KHZ -| 1 APCI1500_3_6_KHZ | -| 0 APCI1500_115_KHZ -| data[1] : 0 Counter1/Timer1 -| 1 Counter2/Timer2 -| 2 Counter3/Watchdog -| data[2] : 0 Counter -| 1 Timer/Watchdog -| data[3] : This parameter has | -| two meanings. | -| - If the counter/timer | -| is used as a counter | -| the limit value of | -| the counter is given | -| | -| - If the counter/timer | -| is used as a timer, | -| the divider factor | -| for the output is | -| given. -| data[4] : 0 APCI1500_CONTINUOUS -| 1 APCI1500_SINGLE -| data[5] : 0 Software Trigger -| 1 Hardware Trigger -| -| data[6] :0 Software gate -| 1 Hardware gate -| data[7] :0 Interrupt Disable -| 1 Interrupt Enable -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures The Watchdog + * + * data[0] 0 = APCI1500_115_KHZ, 1 = APCI1500_3_6_KHZ, 2 = APCI1500_1_8_KHZ + * data[1] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog + * data[2] 0 = Counter, 1 = Timer/Watchdog + * data[3] This parameter has two meanings. If the counter/timer is used as + * a counter the limit value of the counter is given. If the counter/timer + * is used as a timer, the divider factor for the output is given. + * data[4] 0 = APCI1500_CONTINUOUS, 1 = APCI1500_SINGLE + * data[5] 0 = Software Trigger, 1 = Hardware Trigger + * data[6] 0 = Software gate, 1 = Hardware gate + * data[7] 0 = Interrupt Disable, 1 = Interrupt Enable + */ +static int apci1500_timer_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_TimerCounterMode, i_MasterConfiguration; @@ -1319,7 +1007,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, } /* if(data[0]==0||data[0]==1||data[0]==2) */ else { if (data[0] != 3) { - printk("\nThe option for input clock selection does not exist\n"); + dev_warn(dev->hw_dev, + "The option for input clock selection does not exist\n"); return -EINVAL; } /* if(data[0]!=3) */ } /* elseif(data[0]==0||data[0]==1||data[0]==2) */ @@ -1335,7 +1024,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[2] = APCI1500_TIMER; break; default: - printk("\nThis choice is not a timer nor a counter\n"); + dev_warn(dev->hw_dev, + "This choice is not a timer nor a counter\n"); return -EINVAL; } /* switch(data[2]) */ @@ -1348,139 +1038,110 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[4] = APCI1500_SINGLE; break; default: - printk("\nThis option for single/continuous mode does not exist\n"); + dev_warn(dev->hw_dev, + "This option for single/continuous mode does not exist\n"); return -EINVAL; } /* switch(data[4]) */ i_TimerCounterMode = data[2] | data[4] | 7; - /*************************/ /* Test the reload value */ - /*************************/ if ((data[3] >= 0) && (data[3] <= 65535)) { if (data[7] == APCI1500_ENABLE || data[7] == APCI1500_DISABLE) { - /************************************************/ /* Selects the mode register of timer/counter 1 */ - /************************************************/ outb(APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************/ /* Writes the new mode */ - /***********************/ outb(i_TimerCounterMode, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of timer/counter 1 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR1_TIME_CST_LOW, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************/ /* Writes the low value */ - /*************************/ outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of timer/counter 1 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR1_TIME_CST_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**************************/ /* Writes the high value */ - /**************************/ data[3] = data[3] >> 8; outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************/ /* Reads the register */ - /**********************/ i_MasterConfiguration = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************************************/ /* Enables timer/counter 1 and triggers timer/counter 1 */ - /********************************************************/ i_MasterConfiguration = i_MasterConfiguration | 0x40; - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************/ /* Writes the new configuration */ - /********************************/ outb(i_MasterConfiguration, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the commands register of */ /* timer/counter 1 */ - /****************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Disable timer/counter 1 */ - /***************************/ outb(0x0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the commands register of */ /* timer/counter 1 */ - /****************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Trigger timer/counter 1 */ - /***************************/ outb(0x2, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ else { - printk("\nError in selection of interrupt enable or disable\n"); + dev_warn(dev->hw_dev, + "Error in selection of interrupt enable or disable\n"); return -EINVAL; } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ else { - printk("\nError in selection of reload value\n"); + dev_warn(dev->hw_dev, + "Error in selection of reload value\n"); return -EINVAL; } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ i_TimerCounterWatchdogInterrupt = data[7]; @@ -1496,7 +1157,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[2] = APCI1500_TIMER; break; default: - printk("\nThis choice is not a timer nor a counter\n"); + dev_warn(dev->hw_dev, + "This choice is not a timer nor a counter\n"); return -EINVAL; } /* switch(data[2]) */ @@ -1509,7 +1171,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[4] = APCI1500_SINGLE; break; default: - printk("\nThis option for single/continuous mode does not exist\n"); + dev_warn(dev->hw_dev, + "This option for single/continuous mode does not exist\n"); return -EINVAL; } /* switch(data[4]) */ @@ -1522,7 +1185,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[5] = APCI1500_HARDWARE_TRIGGER; break; default: - printk("\nThis choice for software or hardware trigger does not exist\n"); + dev_warn(dev->hw_dev, + "This choice for software or hardware trigger does not exist\n"); return -EINVAL; } /* switch(data[5]) */ @@ -1535,140 +1199,111 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[6] = APCI1500_HARDWARE_GATE; break; default: - printk("\nThis choice for software or hardware gate does not exist\n"); + dev_warn(dev->hw_dev, + "This choice for software or hardware gate does not exist\n"); return -EINVAL; } /* switch(data[6]) */ i_TimerCounterMode = data[2] | data[4] | data[5] | data[6] | 7; - /*************************/ /* Test the reload value */ - /*************************/ if ((data[3] >= 0) && (data[3] <= 65535)) { if (data[7] == APCI1500_ENABLE || data[7] == APCI1500_DISABLE) { - /************************************************/ /* Selects the mode register of timer/counter 2 */ - /************************************************/ outb(APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************/ /* Writes the new mode */ - /***********************/ outb(i_TimerCounterMode, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of timer/counter 2 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR2_TIME_CST_LOW, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************/ /* Writes the low value */ - /*************************/ outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of timer/counter 2 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR2_TIME_CST_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**************************/ /* Writes the high value */ - /**************************/ data[3] = data[3] >> 8; outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************/ /* Reads the register */ - /**********************/ i_MasterConfiguration = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************************************/ /* Enables timer/counter 2 and triggers timer/counter 2 */ - /********************************************************/ i_MasterConfiguration = i_MasterConfiguration | 0x20; - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************/ /* Writes the new configuration */ - /********************************/ outb(i_MasterConfiguration, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the commands register of */ /* timer/counter 2 */ - /****************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Disable timer/counter 2 */ - /***************************/ outb(0x0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the commands register of */ /* timer/counter 2 */ - /****************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Trigger timer/counter 1 */ - /***************************/ outb(0x2, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ else { - printk("\nError in selection of interrupt enable or disable\n"); + dev_warn(dev->hw_dev, + "Error in selection of interrupt enable or disable\n"); return -EINVAL; } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ else { - printk("\nError in selection of reload value\n"); + dev_warn(dev->hw_dev, + "Error in selection of reload value\n"); return -EINVAL; } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ i_TimerCounterWatchdogInterrupt = data[7]; @@ -1684,7 +1319,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[2] = APCI1500_WATCHDOG; break; default: - printk("\nThis choice is not a watchdog nor a counter\n"); + dev_warn(dev->hw_dev, + "This choice is not a watchdog nor a counter\n"); return -EINVAL; } /* switch(data[2]) */ @@ -1697,7 +1333,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[4] = APCI1500_SINGLE; break; default: - printk("\nThis option for single/continuous mode does not exist\n"); + dev_warn(dev->hw_dev, + "This option for single/continuous mode does not exist\n"); return -EINVAL; } /* switch(data[4]) */ @@ -1710,146 +1347,109 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[6] = APCI1500_HARDWARE_GATE; break; default: - printk("\nThis choice for software or hardware gate does not exist\n"); + dev_warn(dev->hw_dev, + "This choice for software or hardware gate does not exist\n"); return -EINVAL; } /* switch(data[6]) */ - /*****************************/ /* Test if used for watchdog */ - /*****************************/ if (data[2] == APCI1500_WATCHDOG) { - /*****************************/ /* - Enables the output line */ /* - Enables retrigger */ /* - Pulses output */ - /*****************************/ i_TimerCounterMode = data[2] | data[4] | 0x54; } /* if (data[2] == APCI1500_WATCHDOG) */ else { i_TimerCounterMode = data[2] | data[4] | data[6] | 7; } /* elseif (data[2] == APCI1500_WATCHDOG) */ - /*************************/ /* Test the reload value */ - /*************************/ if ((data[3] >= 0) && (data[3] <= 65535)) { if (data[7] == APCI1500_ENABLE || data[7] == APCI1500_DISABLE) { - /************************************************/ /* Selects the mode register of watchdog/counter 3 */ - /************************************************/ outb(APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************/ /* Writes the new mode */ - /***********************/ outb(i_TimerCounterMode, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of watchdog/counter 3 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR3_TIME_CST_LOW, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************/ /* Writes the low value */ - /*************************/ outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of watchdog/counter 3 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR3_TIME_CST_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**************************/ /* Writes the high value */ - /**************************/ data[3] = data[3] >> 8; outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************/ /* Reads the register */ - /**********************/ i_MasterConfiguration = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************************************/ /* Enables watchdog/counter 3 and triggers watchdog/counter 3 */ - /********************************************************/ i_MasterConfiguration = i_MasterConfiguration | 0x10; - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************/ /* Writes the new configuration */ - /********************************/ outb(i_MasterConfiguration, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************/ /* Test if COUNTER */ - /********************/ if (data[2] == APCI1500_COUNTER) { - /*************************************/ /* Selects the command register of */ /* watchdog/counter 3 */ - /*************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Disable the watchdog/counter 3 and starts it */ - /*************************************************/ outb(0x0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Selects the command register of */ /* watchdog/counter 3 */ - /*************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Trigger the watchdog/counter 3 and starts it */ - /*************************************************/ outb(0x2, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1858,12 +1458,14 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ else { - printk("\nError in selection of interrupt enable or disable\n"); + dev_warn(dev->hw_dev, + "Error in selection of interrupt enable or disable\n"); return -EINVAL; } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ else { - printk("\nError in selection of reload value\n"); + dev_warn(dev->hw_dev, + "Error in selection of reload value\n"); return -EINVAL; } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ i_TimerCounterWatchdogInterrupt = data[7]; @@ -1871,44 +1473,25 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, break; default: - printk("\nThe specified counter\timer option does not exist\n"); + dev_warn(dev->hw_dev, + "The specified counter/timer option does not exist\n"); + return -EINVAL; } /* switch(data[1]) */ i_CounterLogic = data[2]; return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_StartStopTriggerTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, -| struct comedi_insn *insn,unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Start / Stop or trigger the timer counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -| data[0] : 0 Counter1/Timer1 -| 1 Counter2/Timer2 -| 2 Counter3/Watchdog -| data[1] : 0 start -| 1 stop -| 2 Trigger -| data[2] : 0 Counter -| 1 Timer/Watchdog -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Start / Stop or trigger the timer counter or Watchdog + * + * data[0] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog + * data[1] 0 = Start, 1 = Stop, 2 = Trigger + * data[2] 0 = Counter, 1 = Timer/Watchdog + */ +static int apci1500_timer_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_CommandAndStatusValue; @@ -1924,13 +1507,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device else { i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ - /**************************/ /* Starts timer/counter 1 */ - /**************************/ i_TimerCounter1Enabled = 1; - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1939,20 +1518,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter1Init==1) */ else { - printk("\nCounter/Timer1 not configured\n"); + dev_warn(dev->hw_dev, + "Counter/Timer1 not configured\n"); return -EINVAL; } break; case STOP: - /**************************/ /* Stop timer/counter 1 */ - /**************************/ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1965,23 +1541,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device case TRIGGER: if (i_TimerCounter1Init == 1) { if (i_TimerCounter1Enabled == 1) { - /************************/ /* Set Trigger and gate */ - /************************/ i_CommandAndStatusValue = 0x6; } /* if( i_TimerCounter1Enabled==1) */ else { - /***************/ /* Set Trigger */ - /***************/ i_CommandAndStatusValue = 0x2; } /* elseif(i_TimerCounter1Enabled==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1990,13 +1560,15 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter1Init==1) */ else { - printk("\nCounter/Timer1 not configured\n"); + dev_warn(dev->hw_dev, + "Counter/Timer1 not configured\n"); return -EINVAL; } break; default: - printk("\nThe specified option for start/stop/trigger does not exist\n"); + dev_warn(dev->hw_dev, + "The specified option for start/stop/trigger does not exist\n"); return -EINVAL; } /* switch(data[1]) */ break; @@ -2011,13 +1583,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device else { i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ - /**************************/ /* Starts timer/counter 2 */ - /**************************/ i_TimerCounter2Enabled = 1; - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2026,20 +1594,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter2Init==1) */ else { - printk("\nCounter/Timer2 not configured\n"); + dev_warn(dev->hw_dev, + "Counter/Timer2 not configured\n"); return -EINVAL; } break; case STOP: - /**************************/ /* Stop timer/counter 2 */ - /**************************/ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2051,23 +1616,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device case TRIGGER: if (i_TimerCounter2Init == 1) { if (i_TimerCounter2Enabled == 1) { - /************************/ /* Set Trigger and gate */ - /************************/ i_CommandAndStatusValue = 0x6; } /* if( i_TimerCounter2Enabled==1) */ else { - /***************/ /* Set Trigger */ - /***************/ i_CommandAndStatusValue = 0x2; } /* elseif(i_TimerCounter2Enabled==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2076,12 +1635,14 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter2Init==1) */ else { - printk("\nCounter/Timer2 not configured\n"); + dev_warn(dev->hw_dev, + "Counter/Timer2 not configured\n"); return -EINVAL; } break; default: - printk("\nThe specified option for start/stop/trigger does not exist\n"); + dev_warn(dev->hw_dev, + "The specified option for start/stop/trigger does not exist\n"); return -EINVAL; } /* switch(data[1]) */ break; @@ -2096,13 +1657,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device else { i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ - /**************************/ /* Starts Watchdog/counter 3 */ - /**************************/ i_WatchdogCounter3Enabled = 1; - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2112,20 +1669,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device } /* if( i_WatchdogCounter3init==1) */ else { - printk("\nWatchdog/Counter3 not configured\n"); + dev_warn(dev->hw_dev, + "Watchdog/Counter3 not configured\n"); return -EINVAL; } break; case STOP: - /**************************/ /* Stop Watchdog/counter 3 */ - /**************************/ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2140,23 +1694,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device case 0: /* triggering counter 3 */ if (i_WatchdogCounter3Init == 1) { if (i_WatchdogCounter3Enabled == 1) { - /************************/ /* Set Trigger and gate */ - /************************/ i_CommandAndStatusValue = 0x6; } /* if( i_WatchdogCounter3Enabled==1) */ else { - /***************/ /* Set Trigger */ - /***************/ i_CommandAndStatusValue = 0x2; } /* elseif(i_WatchdogCounter3Enabled==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2165,7 +1713,8 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_WatchdogCounter3Init==1) */ else { - printk("\nCounter3 not configured\n"); + dev_warn(dev->hw_dev, + "Counter3 not configured\n"); return -EINVAL; } break; @@ -2173,9 +1722,7 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device /* triggering Watchdog 3 */ if (i_WatchdogCounter3Init == 1) { - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2184,55 +1731,40 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_WatchdogCounter3Init==1) */ else { - printk("\nWatchdog 3 not configured\n"); + dev_warn(dev->hw_dev, + "Watchdog 3 not configured\n"); return -EINVAL; } break; default: - printk("\nWrong choice of watchdog/counter3\n"); + dev_warn(dev->hw_dev, + "Wrong choice of watchdog/counter3\n"); return -EINVAL; } /* switch(data[2]) */ break; default: - printk("\nThe specified option for start/stop/trigger does not exist\n"); + dev_warn(dev->hw_dev, + "The specified option for start/stop/trigger does not exist\n"); return -EINVAL; } /* switch(data[1]) */ break; default: - printk("\nThe specified choice for counter/watchdog/timer does not exist\n"); + dev_warn(dev->hw_dev, + "The specified choice for counter/watchdog/timer does not exist\n"); return -EINVAL; } /* switch(data[0]) */ return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ReadCounterTimerWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Read The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -| data[0] : 0 Counter1/Timer1 -| 1 Counter2/Timer2 -| 2 Counter3/Watchdog -| -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read The Watchdog + * + * data[0] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog + */ +static int apci1500_timer_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; int i_CommandAndStatusValue; @@ -2242,23 +1774,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, /* Read counter/timer1 */ if (i_TimerCounter1Init == 1) { if (i_TimerCounter1Enabled == 1) { - /************************/ /* Set RCC and gate */ - /************************/ i_CommandAndStatusValue = 0xC; } /* if( i_TimerCounter1Init==1) */ else { - /***************/ /* Set RCC */ - /***************/ i_CommandAndStatusValue = 0x8; } /* elseif(i_TimerCounter1Init==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2266,9 +1792,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************/ /* Selects the counter register (high) */ - /***************************************/ outb(APCI1500_R_CPT_TMR1_VALUE_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2285,7 +1809,8 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter1Init==1) */ else { - printk("\nTimer/Counter1 not configured\n"); + dev_warn(dev->hw_dev, + "Timer/Counter1 not configured\n"); return -EINVAL; } /* elseif( i_TimerCounter1Init==1) */ break; @@ -2293,23 +1818,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, /* Read counter/timer2 */ if (i_TimerCounter2Init == 1) { if (i_TimerCounter2Enabled == 1) { - /************************/ /* Set RCC and gate */ - /************************/ i_CommandAndStatusValue = 0xC; } /* if( i_TimerCounter2Init==1) */ else { - /***************/ /* Set RCC */ - /***************/ i_CommandAndStatusValue = 0x8; } /* elseif(i_TimerCounter2Init==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2317,9 +1836,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************/ /* Selects the counter register (high) */ - /***************************************/ outb(APCI1500_R_CPT_TMR2_VALUE_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2336,7 +1853,8 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter2Init==1) */ else { - printk("\nTimer/Counter2 not configured\n"); + dev_warn(dev->hw_dev, + "Timer/Counter2 not configured\n"); return -EINVAL; } /* elseif( i_TimerCounter2Init==1) */ break; @@ -2344,23 +1862,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, /* Read counter/watchdog2 */ if (i_WatchdogCounter3Init == 1) { if (i_WatchdogCounter3Enabled == 1) { - /************************/ /* Set RCC and gate */ - /************************/ i_CommandAndStatusValue = 0xC; } /* if( i_TimerCounter2Init==1) */ else { - /***************/ /* Set RCC */ - /***************/ i_CommandAndStatusValue = 0x8; } /* elseif(i_WatchdogCounter3Init==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2368,9 +1880,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************/ /* Selects the counter register (high) */ - /***************************************/ outb(APCI1500_R_CPT_TMR3_VALUE_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2387,12 +1897,14 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_WatchdogCounter3Init==1) */ else { - printk("\nWatchdogCounter3 not configured\n"); + dev_warn(dev->hw_dev, + "WatchdogCounter3 not configured\n"); return -EINVAL; } /* elseif( i_WatchdogCounter3Init==1) */ break; default: - printk("\nThe choice of timer/counter/watchdog does not exist\n"); + dev_warn(dev->hw_dev, + "The choice of timer/counter/watchdog does not exist\n"); return -EINVAL; } /* switch(data[0]) */ @@ -2400,31 +1912,15 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ReadInterruptMask | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Read the interrupt mask | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | - - -+----------------------------------------------------------------------------+ -| Output Parameters : -- data[0]:The interrupt mask value data[1]:Channel no -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ReadInterruptMask(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read the interrupt mask + * + * data[0] The interrupt mask value + * data[1] Channel Number + */ +static int apci1500_timer_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { data[0] = i_InterruptMask; data[1] = i_InputChannel; @@ -2433,31 +1929,12 @@ static int i_APCI1500_ReadInterruptMask(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ConfigureInterrupt | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Configures the interrupt registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer | -| - -+----------------------------------------------------------------------------+ -| Output Parameters : -- -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures the interrupt registers + */ +static int apci1500_do_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ui_Status; @@ -2474,140 +1951,101 @@ static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev, i_Constant = 0x00; } /* if{data[0]==0) */ else { - printk("\nThe parameter passed to driver is in error for enabling the voltage interrupt\n"); + dev_warn(dev->hw_dev, + "The parameter passed to driver is in error for enabling the voltage interrupt\n"); return -EINVAL; } /* else if(data[0]==0) */ } /* elseif(data[0]==1) */ - /*****************************************************/ /* Selects the mode specification register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Writes the new configuration (APCI1500_OR) */ - /*********************************************/ i_RegValue = (i_RegValue & 0xF9) | APCI1500_OR; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************/ /* Authorises the interrupt on the board */ - /*****************************************/ outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the pattern polarity register of port B */ - /***************************************************/ outb(APCI1500_RW_PORT_B_PATTERN_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the pattern transition register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************************/ /* Selects the pattern mask register of port B */ - /***********************************************/ outb(APCI1500_RW_PORT_B_PATTERN_MASK, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of port A */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of port B */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of timer 1 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 1 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of timer 2 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 2 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of timer 3 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 3 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Authorizes the main interrupt on the board */ - /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Enables the PCI interrupt */ - /*****************************/ outl(0x3000, devpriv->i_IobaseAmcc + 0x38); ui_Status = inl(devpriv->i_IobaseAmcc + 0x10); ui_Status = inl(devpriv->i_IobaseAmcc + 0x38); @@ -2616,24 +2054,7 @@ static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev, return insn->n; } -/* -+----------------------------------------------------------------------------+ -| Function Name : static void v_APCI1500_Interrupt | -| (int irq , void *d) | -+----------------------------------------------------------------------------+ -| Task : Interrupt handler | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq : irq number | -| void *d : void pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static void v_APCI1500_Interrupt(int irq, void *d) +static void apci1500_interrupt(int irq, void *d) { struct comedi_device *dev = d; @@ -2642,44 +2063,28 @@ static void v_APCI1500_Interrupt(int irq, void *d) int i_RegValue = 0; i_InterruptMask = 0; - /***********************************/ /* Read the board interrupt status */ - /***********************************/ ui_InterruptStatus = inl(devpriv->i_IobaseAmcc + 0x38); - /***************************************/ /* Test if board generated a interrupt */ - /***************************************/ if ((ui_InterruptStatus & 0x800000) == 0x800000) { - /************************/ /* Disable all Interrupt */ - /************************/ - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ /* outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); */ - /**********************************************/ /* Disables the main interrupt on the board */ - /**********************************************/ /* outb(0x00,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); */ - /*****************************************************/ /* Selects the command and status register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of port A */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + @@ -2693,9 +2098,7 @@ static void v_APCI1500_Interrupt(int irq, void *d) inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the interrupt vector register of port A */ - /***************************************************/ outb(APCI1500_RW_PORT_A_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2711,45 +2114,32 @@ static void v_APCI1500_Interrupt(int irq, void *d) } /* elseif(i_Logic==APCI1500_OR_PRIORITY) */ } /* if ((i_RegValue & 0x60) == 0x60) */ - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of port B */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - printk("\n\n\n"); - /****************/ /* Reads port B */ - /****************/ i_RegValue = inb((unsigned int) devpriv->iobase + APCI1500_Z8536_PORT_B); i_RegValue = i_RegValue & 0xC0; - /**************************************/ /* Tests if this is an external error */ - /**************************************/ if (i_RegValue) { /* Disable the interrupt */ - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outl(0x0, devpriv->i_IobaseAmcc + 0x38); if (i_RegValue & 0x80) { @@ -2767,46 +2157,34 @@ static void v_APCI1500_Interrupt(int irq, void *d) } /* if (i_RegValue) */ } /* if ((i_RegValue & 0x60) == 0x60) */ - /*****************************************************/ /* Selects the command and status register of timer 1 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of timer 1 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 1 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_InterruptMask = i_InterruptMask | 4; } /* if ((i_RegValue & 0x60) == 0x60) */ - /*****************************************************/ /* Selects the command and status register of timer 2 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of timer 2 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 2 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + @@ -2814,23 +2192,17 @@ static void v_APCI1500_Interrupt(int irq, void *d) i_InterruptMask = i_InterruptMask | 8; } /* if ((i_RegValue & 0x60) == 0x60) */ - /*****************************************************/ /* Selects the command and status register of timer 3 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of timer 3 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 3 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + @@ -2844,42 +2216,23 @@ static void v_APCI1500_Interrupt(int irq, void *d) } /* if ((i_RegValue & 0x60) == 0x60) */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - /***********************/ /* Enable all Interrupts */ - /***********************/ - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Authorizes the main interrupt on the board */ - /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if ((ui_InterruptStatus & 0x800000) == 0x800000) */ else { - printk("\nInterrupt from unknown source\n"); + dev_warn(dev->hw_dev, + "Interrupt from unknown source\n"); } /* else if ((ui_InterruptStatus & 0x800000) == 0x800000) */ return; } -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_Reset(struct comedi_device *dev) | | -+----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_Reset(struct comedi_device *dev) +static int apci1500_reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; int i_DummyRead = 0; @@ -2898,9 +2251,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) i_TimerCounter2Enabled = 0; i_WatchdogCounter3Enabled = 0; - /******************/ /* Software reset */ - /******************/ i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2908,16 +2259,12 @@ static int i_APCI1500_Reset(struct comedi_device *dev) outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the master configuration control register */ - /*****************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the mode specification register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2949,9 +2296,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) /* Deletes the register */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the mode specification register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2981,9 +2326,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) /* Deletes the register */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the data path polarity register of port C */ - /*****************************************************/ outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* High level of port C means 1 */ @@ -2998,9 +2341,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes it */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 1 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -3010,9 +2351,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates the interrupt management of timer 1 */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 2 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -3022,9 +2361,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates Timer 2 interrupt management: */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 3 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -3034,71 +2371,43 @@ static int i_APCI1500_Reset(struct comedi_device *dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates interrupt management of timer 3: */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes all interrupts */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* reset all the digital outputs */ outw(0x0, devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP); -/*******************************/ /* Disable the board interrupt */ -/*******************************/ - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/*****************************************************/ /* Selects the command and status register of timer 1 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/*****************************************************/ /* Selects the command and status register of timer 2 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/*****************************************************/ /* Selects the command and status register of timer 3*/ -/*****************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); return 0; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c index 84668544f52d..9c86b02eb6da 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c @@ -1,74 +1,32 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -@endverbatim -*/ /* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-1564 | Compiler : GCC | - | Module name : hwdrv_apci1564.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-1564 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -/********* Definitions for APCI-1564 card *****/ + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + */ #define APCI1564_ADDRESS_RANGE 128 -/* DIGITAL INPUT-OUTPUT DEFINE */ -/* Input defines */ -#define APCI1564_DIGITAL_IP 0x04 -#define APCI1564_DIGITAL_IP_INTERRUPT_MODE1 4 -#define APCI1564_DIGITAL_IP_INTERRUPT_MODE2 8 -#define APCI1564_DIGITAL_IP_IRQ 16 - -/* Output defines */ -#define APCI1564_DIGITAL_OP 0x18 -#define APCI1564_DIGITAL_OP_RW 0 -#define APCI1564_DIGITAL_OP_INTERRUPT 4 -#define APCI1564_DIGITAL_OP_IRQ 12 - /* Digital Input IRQ Function Selection */ #define ADDIDATA_OR 0 #define ADDIDATA_AND 1 -/* Digital Input Interrupt Status */ -#define APCI1564_DIGITAL_IP_INTERRUPT_STATUS 12 - -/* Digital Output Interrupt Status */ -#define APCI1564_DIGITAL_OP_INTERRUPT_STATUS 8 - /* Digital Input Interrupt Enable Disable. */ #define APCI1564_DIGITAL_IP_INTERRUPT_ENABLE 0x4 #define APCI1564_DIGITAL_IP_INTERRUPT_DISABLE 0xfffffffb @@ -80,98 +38,91 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY #define APCI1564_DIGITAL_OP_CC_INTERRUPT_DISABLE 0xfffffffd /* TIMER COUNTER WATCHDOG DEFINES */ - #define ADDIDATA_TIMER 0 #define ADDIDATA_COUNTER 1 #define ADDIDATA_WATCHDOG 2 -#define APCI1564_DIGITAL_OP_WATCHDOG 0x28 -#define APCI1564_TIMER 0x48 -#define APCI1564_COUNTER1 0x0 -#define APCI1564_COUNTER2 0x20 -#define APCI1564_COUNTER3 0x40 -#define APCI1564_COUNTER4 0x60 -#define APCI1564_TCW_SYNC_ENABLEDISABLE 0 -#define APCI1564_TCW_RELOAD_VALUE 4 -#define APCI1564_TCW_TIMEBASE 8 -#define APCI1564_TCW_PROG 12 -#define APCI1564_TCW_TRIG_STATUS 16 -#define APCI1564_TCW_IRQ 20 -#define APCI1564_TCW_WARN_TIMEVAL 24 -#define APCI1564_TCW_WARN_TIMEBASE 28 +#define APCI1564_COUNTER1 0 +#define APCI1564_COUNTER2 1 +#define APCI1564_COUNTER3 2 +#define APCI1564_COUNTER4 3 + +/* + * devpriv->i_IobaseAmcc Register Map + */ +#define APCI1564_DI_REG 0x04 +#define APCI1564_DI_INT_MODE1_REG 0x08 +#define APCI1564_DI_INT_MODE2_REG 0x0c +#define APCI1564_DI_INT_STATUS_REG 0x10 +#define APCI1564_DI_IRQ_REG 0x14 +#define APCI1564_DO_REG 0x18 +#define APCI1564_DO_INT_CTRL_REG 0x1c +#define APCI1564_DO_INT_STATUS_REG 0x20 +#define APCI1564_DO_IRQ_REG 0x24 +#define APCI1564_WDOG_REG 0x28 +#define APCI1564_WDOG_RELOAD_REG 0x2c +#define APCI1564_WDOG_TIMEBASE_REG 0x30 +#define APCI1564_WDOG_CTRL_REG 0x34 +#define APCI1564_WDOG_STATUS_REG 0x38 +#define APCI1564_WDOG_IRQ_REG 0x3c +#define APCI1564_WDOG_WARN_TIMEVAL_REG 0x40 +#define APCI1564_WDOG_WARN_TIMEBASE_REG 0x44 +#define APCI1564_TIMER_REG 0x48 +#define APCI1564_TIMER_RELOAD_REG 0x4c +#define APCI1564_TIMER_TIMEBASE_REG 0x50 +#define APCI1564_TIMER_CTRL_REG 0x54 +#define APCI1564_TIMER_STATUS_REG 0x58 +#define APCI1564_TIMER_IRQ_REG 0x5c +#define APCI1564_TIMER_WARN_TIMEVAL_REG 0x60 +#define APCI1564_TIMER_WARN_TIMEBASE_REG 0x64 + +/* + * devpriv->iobase Register Map + */ +#define APCI1564_TCW_REG(x) (0x00 + ((x) * 0x20)) +#define APCI1564_TCW_RELOAD_REG(x) (0x04 + ((x) * 0x20)) +#define APCI1564_TCW_TIMEBASE_REG(x) (0x08 + ((x) * 0x20)) +#define APCI1564_TCW_CTRL_REG(x) (0x0c + ((x) * 0x20)) +#define APCI1564_TCW_STATUS_REG(x) (0x10 + ((x) * 0x20)) +#define APCI1564_TCW_IRQ_REG(x) (0x14 + ((x) * 0x20)) +#define APCI1564_TCW_WARN_TIMEVAL_REG(x) (0x18 + ((x) * 0x20)) +#define APCI1564_TCW_WARN_TIMEBASE_REG(x) (0x1c + ((x) * 0x20)) /* Global variables */ -static unsigned int ui_InterruptStatus_1564 = 0; +static unsigned int ui_InterruptStatus_1564; static unsigned int ui_InterruptData, ui_Type; /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ConfigDigitalInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures the digital input Subdevice | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 1 Enable Digital Input Interrupt | -| 0 Disable Digital Input Interrupt | -| data[1] : 0 ADDIDATA Interrupt OR LOGIC | -| : 1 ADDIDATA Interrupt AND LOGIC | -| data[2] : Interrupt mask for the mode 1 | -| data[3] : Interrupt mask for the mode 2 | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1564_ConfigDigitalInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures the digital input Subdevice + * + * data[0] 1 = Enable interrupt, 0 = Disable interrupt + * data[1] 0 = ADDIDATA Interrupt OR LOGIC, 1 = ADDIDATA Interrupt AND LOGIC + * data[2] Interrupt mask for the mode 1 + * data[3] Interrupt mask for the mode 2 + */ +static int apci1564_di_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; devpriv->tsk_Current = current; - /*******************************/ + /* Set the digital input logic */ - /*******************************/ if (data[0] == ADDIDATA_ENABLE) { data[2] = data[2] << 4; data[3] = data[3] << 4; - outl(data[2], - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_MODE1); - outl(data[3], - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_MODE2); - if (data[1] == ADDIDATA_OR) { - outl(0x4, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - } /* if (data[1] == ADDIDATA_OR) */ - else { - outl(0x6, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - } /* else if (data[1] == ADDIDATA_OR) */ - } /* if (data[0] == ADDIDATA_ENABLE) */ - else { - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_MODE1); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_MODE2); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - } /* else if (data[0] == ADDIDATA_ENABLE) */ + outl(data[2], devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG); + outl(data[3], devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG); + if (data[1] == ADDIDATA_OR) + outl(0x4, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + else + outl(0x6, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + } else { + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + } return insn->n; } @@ -183,40 +134,21 @@ static int apci1564_di_insn_bits(struct comedi_device *dev, { struct addi_private *devpriv = dev->private; - data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP); + data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_DI_REG); return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ConfigDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Digital Output Subdevice. | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[1] : 1 Enable VCC Interrupt | -| 0 Disable VCC Interrupt | -| data[2] : 1 Enable CC Interrupt | -| 0 Disable CC Interrupt | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1564_ConfigDigitalOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures The Digital Output Subdevice. + * + * data[1] 0 = Disable VCC Interrupt, 1 = Enable VCC Interrupt + * data[2] 0 = Disable CC Interrupt, 1 = Enable CC Interrupt + */ +static int apci1564_do_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ul_Command = 0; @@ -225,31 +157,25 @@ static int i_APCI1564_ConfigDigitalOutput(struct comedi_device *dev, comedi_error(dev, "Not a valid Data !!! ,Data should be 1 or 0\n"); return -EINVAL; - } /* if ((data[0]!=0) && (data[0]!=1)) */ - if (data[0]) { + } + + if (data[0]) devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE; - } /* if (data[0]) */ - else { + else devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE; - } /* else if (data[0]) */ - if (data[1] == ADDIDATA_ENABLE) { + + if (data[1] == ADDIDATA_ENABLE) ul_Command = ul_Command | 0x1; - } /* if (data[1] == ADDIDATA_ENABLE) */ - else { + else ul_Command = ul_Command & 0xFFFFFFFE; - } /* else if (data[1] == ADDIDATA_ENABLE) */ - if (data[2] == ADDIDATA_ENABLE) { + + if (data[2] == ADDIDATA_ENABLE) ul_Command = ul_Command | 0x2; - } /* if (data[2] == ADDIDATA_ENABLE) */ - else { + else ul_Command = ul_Command & 0xFFFFFFFD; - } /* else if (data[2] == ADDIDATA_ENABLE) */ - outl(ul_Command, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_INTERRUPT); - ui_InterruptData = - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_INTERRUPT); + + outl(ul_Command, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); + ui_InterruptData = inl(devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); devpriv->tsk_Current = current; return insn->n; } @@ -261,12 +187,10 @@ static int apci1564_do_insn_bits(struct comedi_device *dev, { struct addi_private *devpriv = dev->private; - s->state = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_RW); + s->state = inl(devpriv->i_IobaseAmcc + APCI1564_DO_REG); if (comedi_dio_update_state(s, data)) - outl(s->state, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_RW); + outl(s->state, devpriv->i_IobaseAmcc + APCI1564_DO_REG); data[1] = s->state; @@ -274,39 +198,20 @@ static int apci1564_do_insn_bits(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ConfigTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Configure As Timer | -| 1 Configure As Counter | -| 2 Configure As Watchdog | -| data[1] : 1 Enable Interrupt | -| 0 Disable Interrupt | -| data[2] : Time Unit | -| data[3] : Reload Value | -| data[4] : Timer Mode | -| data[5] : Timer Counter Watchdog Number| - data[6] : Counter Direction -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures The Timer, Counter or Watchdog + * + * data[0] Configure as: 0 = Timer, 1 = Counter, 2 = Watchdog + * data[1] 1 = Enable Interrupt, 0 = Disable Interrupt + * data[2] Time Unit + * data[3] Reload Value + * data[4] Timer Mode + * data[5] Timer Counter Watchdog Number + * data[6] Counter Direction + */ +static int apci1564_timer_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ul_Command1 = 0; @@ -316,89 +221,59 @@ static int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev, devpriv->b_TimerSelectMode = ADDIDATA_WATCHDOG; /* Disable the watchdog */ - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_PROG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG); /* Loading the Reload value */ - outl(data[3], - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_RELOAD_VALUE); - } /* if (data[0]==ADDIDATA_WATCHDOG) */ - else if (data[0] == ADDIDATA_TIMER) { + outl(data[3], devpriv->i_IobaseAmcc + APCI1564_WDOG_RELOAD_REG); + } else if (data[0] == ADDIDATA_TIMER) { /* First Stop The Timer */ - ul_Command1 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* Stop The Timer */ + /* Stop The Timer */ + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); devpriv->b_TimerSelectMode = ADDIDATA_TIMER; if (data[1] == 1) { - outl(0x02, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */ + /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */ + outl(0x02, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_IRQ_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_IRQ_REG); outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); + devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)); outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_IRQ); + devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)); outl(0x0, - devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_IRQ); + devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_IRQ); - outl(0x0, - devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_IRQ); - outl(0x0, - devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_IRQ); - outl(0x0, - devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_IRQ); - } /* if (data[1]==1) */ - else { - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* disable Timer interrupt */ - } /* else if (data[1]==1) */ + devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4)); + } else { + /* disable Timer interrupt */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + } /* Loading Timebase */ - - outl(data[2], - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_TIMEBASE); + outl(data[2], devpriv->i_IobaseAmcc + APCI1564_TIMER_TIMEBASE_REG); /* Loading the Reload value */ - outl(data[3], - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_RELOAD_VALUE); + outl(data[3], devpriv->i_IobaseAmcc + APCI1564_TIMER_RELOAD_REG); - ul_Command1 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - ul_Command1 = - (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL; - outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* mode 2 */ - } /* else if (data[0]==ADDIDATA_TIMER) */ - else if (data[0] == ADDIDATA_COUNTER) { + ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + ul_Command1 = (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL; + /* mode 2 */ + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + } else if (data[0] == ADDIDATA_COUNTER) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; devpriv->b_ModeSelectRegister = data[5]; /* First Stop The Counter */ - ul_Command1 = - inl(devpriv->iobase + ((data[5] - 1) * 0x20) + - APCI1564_TCW_PROG); + ul_Command1 = inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, devpriv->iobase + ((data[5] - 1) * 0x20) + APCI1564_TCW_PROG); /* Stop The Timer */ + /* Stop The Timer */ + outl(ul_Command1, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); - /************************/ /* Set the reload value */ - /************************/ - outl(data[3], - devpriv->iobase + ((data[5] - 1) * 0x20) + - APCI1564_TCW_RELOAD_VALUE); + outl(data[3], devpriv->iobase + APCI1564_TCW_RELOAD_REG(data[5] - 1)); - /******************************/ /* Set the mode : */ /* - Disable the hardware */ /* - Disable the counter mode */ @@ -406,65 +281,36 @@ static int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev, /* - Disable the reset */ /* - Disable the timer mode */ /* - Enable the counter mode */ - /******************************/ + ul_Command1 = (ul_Command1 & 0xFFFC19E2UL) | 0x80000UL | (unsigned int) ((unsigned int) data[4] << 16UL); - outl(ul_Command1, - devpriv->iobase + ((data[5] - 1) * 0x20) + - APCI1564_TCW_PROG); + outl(ul_Command1, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); /* Enable or Disable Interrupt */ ul_Command1 = (ul_Command1 & 0xFFFFF9FD) | (data[1] << 1); - outl(ul_Command1, - devpriv->iobase + ((data[5] - 1) * 0x20) + - APCI1564_TCW_PROG); + outl(ul_Command1, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); - /*****************************/ /* Set the Up/Down selection */ - /*****************************/ ul_Command1 = (ul_Command1 & 0xFFFBF9FFUL) | (data[6] << 18); - outl(ul_Command1, - devpriv->iobase + ((data[5] - 1) * 0x20) + - APCI1564_TCW_PROG); - } /* else if (data[0]==ADDIDATA_COUNTER) */ - else { - printk(" Invalid subdevice."); - } /* else if (data[0]==ADDIDATA_WATCHDOG) */ + outl(ul_Command1, devpriv->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); + } else { + dev_err(dev->class_dev, "Invalid subdevice.\n"); + } return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_StartStopWriteTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Start / Stop The Selected Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Timer | -| 1 Counter | -| 2 Watchdog | | data[1] : 1 Start | -| 0 Stop | -| 2 Trigger | -| Clear (Only Counter) | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Start / Stop The Selected Timer, Counter or Watchdog + * + * data[0] Configure as: 0 = Timer, 1 = Counter, 2 = Watchdog + * data[1] 0 = Stop, 1 = Start, 2 = Trigger Clear (Only Counter) + */ +static int apci1564_timer_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ul_Command1 = 0; @@ -472,203 +318,122 @@ static int i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device *d if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { switch (data[1]) { case 0: /* stop the watchdog */ - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + APCI1564_TCW_PROG); /* disable the watchdog */ + /* disable the watchdog */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG); break; case 1: /* start the watchdog */ - outl(0x0001, - devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_PROG); + outl(0x0001, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG); break; case 2: /* Software trigger */ - outl(0x0201, - devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_PROG); + outl(0x0201, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG); break; default: - printk("\nSpecified functionality does not exist\n"); + dev_err(dev->class_dev, "Specified functionality does not exist.\n"); return -EINVAL; - } /* switch (data[1]) */ - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */ + } + } if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { if (data[1] == 1) { - ul_Command1 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; /* Enable the Timer */ - outl(ul_Command1, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - } /* if (data[1]==1) */ - else if (data[1] == 0) { + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + } else if (data[1] == 0) { /* Stop The Timer */ - ul_Command1 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - } /* else if(data[1]==0) */ - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + } + } if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) { ul_Command1 = - inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister - - 1) * 0x20) + APCI1564_TCW_PROG); + inl(devpriv->iobase + + APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1)); if (data[1] == 1) { /* Start the Counter subdevice */ ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; - } /* if (data[1] == 1) */ - else if (data[1] == 0) { + } else if (data[1] == 0) { /* Stops the Counter subdevice */ ul_Command1 = 0; - } /* else if (data[1] == 0) */ - else if (data[1] == 2) { + } else if (data[1] == 2) { /* Clears the Counter subdevice */ ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x400; - } /* else if (data[1] == 3) */ + } outl(ul_Command1, - devpriv->iobase + ((devpriv->b_ModeSelectRegister - - 1) * 0x20) + APCI1564_TCW_PROG); - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER) */ + devpriv->iobase + + APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1)); + } return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ReadTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read The Selected Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | - -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1564_ReadTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read The Selected Timer, Counter or Watchdog + */ +static int apci1564_timer_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ul_Command1 = 0; if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { /* Stores the status of the Watchdog */ - data[0] = - inl(devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_TRIG_STATUS) & 0x1; - data[1] = - inl(devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG); - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */ - else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { + data[0] = inl(devpriv->i_IobaseAmcc + APCI1564_WDOG_STATUS_REG) & 0x1; + data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_WDOG_REG); + } else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { /* Stores the status of the Timer */ - data[0] = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_TRIG_STATUS) & 0x1; + data[0] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_STATUS_REG) & 0x1; /* Stores the Actual value of the Timer */ - data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER); - } /* else if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ - else if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) { + data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_REG); + } else if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) { /* Read the Counter Actual Value. */ data[0] = - inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister - - 1) * 0x20) + - APCI1564_TCW_SYNC_ENABLEDISABLE); + inl(devpriv->iobase + + APCI1564_TCW_REG(devpriv->b_ModeSelectRegister - 1)); ul_Command1 = - inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister - - 1) * 0x20) + APCI1564_TCW_TRIG_STATUS); + inl(devpriv->iobase + + APCI1564_TCW_STATUS_REG(devpriv->b_ModeSelectRegister - 1)); - /***********************************/ /* Get the software trigger status */ - /***********************************/ data[1] = (unsigned char) ((ul_Command1 >> 1) & 1); - /***********************************/ /* Get the hardware trigger status */ - /***********************************/ data[2] = (unsigned char) ((ul_Command1 >> 2) & 1); - /*********************************/ /* Get the software clear status */ - /*********************************/ data[3] = (unsigned char) ((ul_Command1 >> 3) & 1); - /***************************/ /* Get the overflow status */ - /***************************/ data[4] = (unsigned char) ((ul_Command1 >> 0) & 1); - } /* else if (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER) */ - else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER) + } else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode != ADDIDATA_WATCHDOG) && (devpriv->b_TimerSelectMode != ADDIDATA_COUNTER)) { - printk("\n Invalid Subdevice !!!\n"); - } /* else if ((devpriv->b_TimerSelectMode!=ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode!=ADDIDATA_WATCHDOG)&& (devpriv->b_TimerSelectMode!=ADDIDATA_COUNTER)) */ + dev_err(dev->class_dev, "Invalid Subdevice!\n"); + } return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ReadInterruptStatus | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task :Reads the interrupt status register | -+----------------------------------------------------------------------------+ -| Input Parameters : | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1564_ReadInterruptStatus(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Reads the interrupt status register + */ +static int apci1564_do_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { *data = ui_Type; return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : static void v_APCI1564_Interrupt | -| (int irq , void *d) | -+----------------------------------------------------------------------------+ -| Task : Interrupt handler for the interruptible digital inputs | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq : irq number | -| void *d : void pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static void v_APCI1564_Interrupt(int irq, void *d) + * Interrupt handler for the interruptible digital inputs + */ +static void apci1564_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; @@ -677,79 +442,63 @@ static void v_APCI1564_Interrupt(int irq, void *d) unsigned int ui_C1, ui_C2, ui_C3, ui_C4; unsigned int ul_Command2 = 0; - ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ) & 0x01; - ui_DO = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_IRQ) & 0x01; - ui_Timer = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_IRQ) & 0x01; - ui_C1 = inl(devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_IRQ) & 0x1; - ui_C2 = inl(devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_IRQ) & 0x1; - ui_C3 = inl(devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_IRQ) & 0x1; - ui_C4 = inl(devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_IRQ) & 0x1; + ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG) & 0x01; + ui_DO = inl(devpriv->i_IobaseAmcc + APCI1564_DO_IRQ_REG) & 0x01; + ui_Timer = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_IRQ_REG) & 0x01; + ui_C1 = + inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)) & 0x1; + ui_C2 = + inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)) & 0x1; + ui_C3 = + inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)) & 0x1; + ui_C4 = + inl(devpriv->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4)) & 0x1; if (ui_DI == 0 && ui_DO == 0 && ui_Timer == 0 && ui_C1 == 0 && ui_C2 == 0 && ui_C3 == 0 && ui_C4 == 0) { - printk("\nInterrupt from unknown source\n"); - } /* if(ui_DI==0 && ui_DO==0 && ui_Timer==0 && ui_C1==0 && ui_C2==0 && ui_C3==0 && ui_C4==0) */ + dev_err(dev->class_dev, "Interrupt from unknown source.\n"); + } if (ui_DI == 1) { - ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); + ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); ui_InterruptStatus_1564 = - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_STATUS); + inl(devpriv->i_IobaseAmcc + APCI1564_DI_INT_STATUS_REG); ui_InterruptStatus_1564 = ui_InterruptStatus_1564 & 0X000FFFF0; - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - outl(ui_DI, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + APCI1564_DIGITAL_IP_IRQ); /* enable the interrupt */ + /* send signal to the sample */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + /* enable the interrupt */ + outl(ui_DI, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); return; } if (ui_DO == 1) { - /* Check for Digital Output interrupt Type - 1: Vcc interrupt 2: CC interrupt. */ - ui_Type = - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_INTERRUPT_STATUS) & 0x3; + /* Check for Digital Output interrupt Type */ + /* 1: VCC interrupt */ + /* 2: CC interrupt */ + ui_Type = inl(devpriv->i_IobaseAmcc + APCI1564_DO_INT_STATUS_REG) & 0x3; /* Disable the Interrupt */ - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_INTERRUPT); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); /* Sends signal to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); - - } /* if (ui_DO) */ + } if (ui_Timer == 1) { devpriv->b_TimerSelectMode = ADDIDATA_TIMER; if (devpriv->b_TimerSelectMode) { /* Disable Timer Interrupt */ - ul_Command2 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + ul_Command2 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Timer Interrupt */ - outl(ul_Command2, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + outl(ul_Command2, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); } - }/* if (ui_Timer == 1) */ - + } if (ui_C1 == 1) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; @@ -757,21 +506,18 @@ static void v_APCI1564_Interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_PROG); + inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_PROG); + devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Counter Interrupt */ outl(ul_Command2, - devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_PROG); + devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); } - } /* if (ui_C1 == 1) */ + } if (ui_C2 == 1) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; @@ -779,21 +525,18 @@ static void v_APCI1564_Interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_PROG); + inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_PROG); + devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Counter Interrupt */ outl(ul_Command2, - devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_PROG); + devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); } - } /* if ((ui_C2 == 1) */ + } if (ui_C3 == 1) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; @@ -801,21 +544,18 @@ static void v_APCI1564_Interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_PROG); + inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_PROG); + devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Counter Interrupt */ outl(ul_Command2, - devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_PROG); + devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); } - } /* if ((ui_C3 == 1) */ + } if (ui_C4 == 1) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; @@ -823,60 +563,45 @@ static void v_APCI1564_Interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_PROG); + inl(devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_PROG); + devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Counter Interrupt */ outl(ul_Command2, - devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_PROG); + devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); } - } /* if (ui_C4 == 1) */ + } return; } -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_Reset(struct comedi_device *dev) | | -+----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI1564_Reset(struct comedi_device *dev) +static int apci1564_reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_IRQ); /* disable the interrupts */ - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_STATUS); /* Reset the interrupt status register */ - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE1); /* Disable the and/or interrupt */ - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE2); + /* disable the interrupts */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + /* Reset the interrupt status register */ + inl(devpriv->i_IobaseAmcc + APCI1564_DI_INT_STATUS_REG); + /* Disable the and/or interrupt */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG); devpriv->b_DigitalOutputRegister = 0; ui_Type = 0; - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP); /* Resets the output channels */ - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_INTERRUPT); /* Disables the interrupt. */ - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_RELOAD_VALUE); - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER); - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); + /* Resets the output channels */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_REG); + /* Disables the interrupt. */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_RELOAD_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); - outl(0x0, devpriv->iobase + APCI1564_COUNTER1 + APCI1564_TCW_PROG); - outl(0x0, devpriv->iobase + APCI1564_COUNTER2 + APCI1564_TCW_PROG); - outl(0x0, devpriv->iobase + APCI1564_COUNTER3 + APCI1564_TCW_PROG); - outl(0x0, devpriv->iobase + APCI1564_COUNTER4 + APCI1564_TCW_PROG); + outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); + outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); + outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); + outl(0x0, devpriv->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); return 0; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c index bd05857b82f2..70e8f426285c 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c @@ -248,10 +248,10 @@ static const struct comedi_lrange range_apci3120_ao = { +----------------------------------------------------------------------------+ */ -static int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3120_ai_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { const struct addi_board *this_board = comedi_board(dev); struct addi_private *devpriv = dev->private; @@ -304,11 +304,11 @@ static int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, * If the last argument of function "check"is 1 then it only checks * the channel list is ok or not. */ -static int i_APCI3120_SetupChannelList(struct comedi_device *dev, - struct comedi_subdevice *s, - int n_chan, - unsigned int *chanlist, - char check) +static int apci3120_setup_chan_list(struct comedi_device *dev, + struct comedi_subdevice *s, + int n_chan, + unsigned int *chanlist, + char check) { struct addi_private *devpriv = dev->private; unsigned int i; /* , differencial=0, bipolar=0; */ @@ -358,10 +358,10 @@ static int i_APCI3120_SetupChannelList(struct comedi_device *dev, * as per configured if no conversion time is set uses default * conversion time 10 microsec. */ -static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3120_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { const struct addi_board *this_board = comedi_board(dev); struct addi_private *devpriv = dev->private; @@ -417,10 +417,7 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, inw(devpriv->iobase + APCI3120_RESET_FIFO); /* Initialize the sequence array */ - - /* if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL; */ - - if (!i_APCI3120_SetupChannelList(dev, s, 1, + if (!apci3120_setup_chan_list(dev, s, 1, &insn->chanspec, 0)) return -EINVAL; @@ -512,7 +509,7 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS); - if (!i_APCI3120_SetupChannelList(dev, s, + if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels, devpriv->ui_AiChannelList, 0)) return -EINVAL; @@ -606,7 +603,7 @@ static int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, } -static int i_APCI3120_Reset(struct comedi_device *dev) +static int apci3120_reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; unsigned int i; @@ -663,7 +660,7 @@ static int i_APCI3120_Reset(struct comedi_device *dev) return 0; } -static int i_APCI3120_ExttrigEnable(struct comedi_device *dev) +static int apci3120_exttrig_enable(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; @@ -672,7 +669,7 @@ static int i_APCI3120_ExttrigEnable(struct comedi_device *dev) return 0; } -static int i_APCI3120_ExttrigDisable(struct comedi_device *dev) +static int apci3120_exttrig_disable(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; @@ -681,8 +678,8 @@ static int i_APCI3120_ExttrigDisable(struct comedi_device *dev) return 0; } -static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, - struct comedi_subdevice *s) +static int apci3120_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { struct addi_private *devpriv = dev->private; @@ -705,7 +702,7 @@ static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */ /* Disable ext trigger */ - i_APCI3120_ExttrigDisable(dev); + apci3120_exttrig_disable(dev); devpriv->us_OutputRegister = 0; /* stop counters */ @@ -729,13 +726,13 @@ static int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; devpriv->b_InterruptMode = APCI3120_EOC_MODE; devpriv->b_EocEosInterrupt = APCI3120_DISABLE; - i_APCI3120_Reset(dev); + apci3120_reset(dev); return 0; } -static int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int apci3120_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { const struct addi_board *this_board = comedi_board(dev); int err = 0; @@ -818,9 +815,9 @@ static int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, * If DMA is configured does DMA initialization otherwise does the * acquisition with EOS interrupt. */ -static int i_APCI3120_CyclicAnalogInput(int mode, - struct comedi_device *dev, - struct comedi_subdevice *s) +static int apci3120_cyclic_ai(int mode, + struct comedi_device *dev, + struct comedi_subdevice *s) { const struct addi_board *this_board = comedi_board(dev); struct addi_private *devpriv = dev->private; @@ -904,7 +901,7 @@ static int i_APCI3120_CyclicAnalogInput(int mode, /**********************************/ /* Initializes the sequence array */ /**********************************/ - if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels, + if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels, devpriv->pui_AiChannelList, 0)) return -EINVAL; @@ -957,7 +954,7 @@ static int i_APCI3120_CyclicAnalogInput(int mode, /*** EL241003 End ******************************************************************************/ if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) - i_APCI3120_ExttrigEnable(dev); /* activate EXT trigger */ + apci3120_exttrig_enable(dev); /* activate EXT trigger */ switch (mode) { case 1: /* init timer0 in mode 2 */ @@ -1333,8 +1330,8 @@ static int i_APCI3120_CyclicAnalogInput(int mode, * Does asynchronous acquisition. * Determines the mode 1 or 2. */ -static int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s) +static int apci3120_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { struct addi_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; @@ -1371,7 +1368,7 @@ static int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */ /* return this_board->ai_cmd(1,dev,s); */ - return i_APCI3120_CyclicAnalogInput(1, dev, s); + return apci3120_cyclic_ai(1, dev, s); } } @@ -1381,7 +1378,7 @@ static int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, devpriv->ui_AiTimer1 = cmd->scan_begin_arg; devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */ /* return this_board->ai_cmd(2,dev,s); */ - return i_APCI3120_CyclicAnalogInput(2, dev, s); + return apci3120_cyclic_ai(2, dev, s); } return -1; } @@ -1410,7 +1407,7 @@ static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev, * For continuous DMA it reinitializes the DMA operation. * For single mode DMA it stop the acquisition. */ -static void v_APCI3120_InterruptDma(int irq, void *d) +static void apci3120_interrupt_dma(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; @@ -1429,7 +1426,7 @@ static void v_APCI3120_InterruptDma(int irq, void *d) } if (samplesinbuf & 1) { comedi_error(dev, "Odd count of bytes in DMA ring!"); - i_APCI3120_StopCyclicAcquisition(dev, s); + apci3120_cancel(dev, s); devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; return; @@ -1500,7 +1497,7 @@ static void v_APCI3120_InterruptDma(int irq, void *d) if (!devpriv->b_AiContinuous) if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) { /* all data sampled */ - i_APCI3120_StopCyclicAcquisition(dev, s); + apci3120_cancel(dev, s); devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; s->async->events |= COMEDI_CB_EOA; comedi_event(dev, s); @@ -1565,7 +1562,7 @@ static void v_APCI3120_InterruptDma(int irq, void *d) * This function handles EOS interrupt. * This function copies the acquired data(from FIFO) to Comedi buffer. */ -static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) +static int apci3120_interrupt_handle_eos(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; @@ -1574,8 +1571,6 @@ static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) n_chan = devpriv->ui_AiNbrofChannels; - s->async->events = 0; - for (i = 0; i < n_chan; i++) err &= comedi_buf_put(s->async, inw(dev->iobase + 0)); @@ -1589,7 +1584,7 @@ static int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) return 0; } -static void v_APCI3120_Interrupt(int irq, void *d) +static void apci3120_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; @@ -1615,7 +1610,7 @@ static void v_APCI3120_Interrupt(int irq, void *d) if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) { /* Disable ext trigger */ - i_APCI3120_ExttrigDisable(dev); + apci3120_exttrig_disable(dev); devpriv->b_ExttrigEnable = APCI3120_DISABLE; } /* clear the timer 2 interrupt */ @@ -1655,7 +1650,7 @@ static void v_APCI3120_Interrupt(int irq, void *d) if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) { ui_Check = 0; - i_APCI3120_InterruptHandleEos(dev); + apci3120_interrupt_handle_eos(dev); devpriv->ui_AiActualScan++; devpriv->b_ModeSelectRegister = devpriv-> @@ -1711,7 +1706,7 @@ static void v_APCI3120_Interrupt(int irq, void *d) dev->iobase + APCI3120_WR_ADDRESS); /* stop timer 0 and timer 1 */ - i_APCI3120_StopCyclicAcquisition(dev, s); + apci3120_cancel(dev, s); devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */ @@ -1765,7 +1760,8 @@ static void v_APCI3120_Interrupt(int irq, void *d) /* Clears the timer status register */ /************************************/ inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); - v_APCI3120_InterruptDma(irq, d); /* do some data transfer */ + /* do some data transfer */ + apci3120_interrupt_dma(irq, d); } else { /* Stops the Timer */ outw(devpriv-> @@ -1787,7 +1783,7 @@ static void v_APCI3120_Interrupt(int irq, void *d) * data[1] = Timer constant * data[2] = Timer2 interrupt (1)enable or(0) disable */ -static int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, +static int apci3120_config_insn_timer(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -1932,7 +1928,7 @@ static int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, * = 1 Timer * = 2 Watch dog */ -static int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, +static int apci3120_write_insn_timer(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -2104,7 +2100,7 @@ static int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, * for watchdog: data[0] = 0 (still running) * = 1 (run down) */ -static int i_APCI3120_InsnReadTimer(struct comedi_device *dev, +static int apci3120_read_insn_timer(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -2189,10 +2185,10 @@ static int apci3120_do_insn_bits(struct comedi_device *dev, return insn->n; } -static int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3120_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ui_Range, ui_Channel; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c index 8c85a09d1c66..0536d8373861 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c @@ -1268,7 +1268,7 @@ static int i_APCI3200_ReadCJCCalGain(struct comedi_device *dev, return 0; } -static int i_APCI3200_Reset(struct comedi_device *dev) +static int apci3200_reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; int i_Temp; @@ -1322,10 +1322,10 @@ static int i_APCI3200_Reset(struct comedi_device *dev) * data[7] : Channel current source from eeprom * data[8] : Channle gain factor from eeprom */ -static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3200_ai_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { unsigned int ui_DummyValue = 0; int i_ConvertCJCCalibration; @@ -1336,7 +1336,7 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, if (s_BoardInfos[dev->minor].i_Initialised == 0) /* END JK 06.07.04: Management of sevrals boards */ { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(i_Initialised==0); */ @@ -1586,7 +1586,7 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, break; default: printk("\nThe parameters passed are in error\n"); - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* switch(insn->unused[0]) */ @@ -1626,10 +1626,10 @@ static int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, * = 2 RTD 3 wire connection * = 3 RTD 4 wire connection */ -static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3200_ai_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ul_Config = 0, ul_Temp = 0; @@ -1970,7 +1970,7 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, } /* switch(data[11]) */ } /* elseif(data[12]==0 || data[12]==1) */ if (i_err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(i_ScanType!=1) */ @@ -2079,7 +2079,7 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, /* END JK 06.07.04: Management of sevrals boards */ insn->unused[0] = 0; - i_APCI3200_ReadAnalogInput(dev, s, insn, &ui_Dummy); + apci3200_ai_read(dev, s, insn, &ui_Dummy); } return insn->n; @@ -2095,10 +2095,10 @@ static int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, * data[1] : calibration offset * data[2] : calibration gain */ -static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3200_ai_bits_test(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct addi_private *devpriv = dev->private; unsigned int ui_Configuration = 0; @@ -2107,12 +2107,12 @@ static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, /* if(i_Initialised==0) */ if (s_BoardInfos[dev->minor].i_Initialised == 0) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(i_Initialised==0); */ if (data[0] != 0 && data[0] != 1) { printk("\nError in selection of functionality\n"); - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(data[0]!=0 && data[0]!=1) */ @@ -2202,18 +2202,18 @@ static int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, return insn->n; } -static int i_APCI3200_InsnWriteReleaseAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3200_ai_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return insn->n; } -static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int apci3200_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; @@ -2241,7 +2241,7 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, err |= -EINVAL; if (err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return 1; } @@ -2267,7 +2267,7 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, } if (err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return 2; } /* i_FirstChannel=cmd->chanlist[0]; */ @@ -2308,7 +2308,7 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, printk("\nThe Delay time value is in error\n"); } if (err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return 3; } fpu_begin(); @@ -2366,15 +2366,15 @@ static int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, } /* else if(cmd->scan_begin_src==TRIG_FOLLOW) */ if (err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return 4; } return 0; } -static int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev, - struct comedi_subdevice *s) +static int apci3200_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { struct addi_private *devpriv = dev->private; unsigned int ui_Configuration = 0; @@ -2410,8 +2410,8 @@ static int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev, * Does asynchronous acquisition * Determines the mode 1 or 2. */ -static int i_APCI3200_CommandAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s) +static int apci3200_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { struct addi_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; @@ -2619,7 +2619,6 @@ static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev) /* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ /* This value is not used */ /* ui_ChannelNumber = inl(devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 24); */ - s->async->events = 0; /* END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ /*************************************/ @@ -2730,7 +2729,7 @@ static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev) return 0; } -static void v_APCI3200_Interrupt(int irq, void *d) +static void apci3200_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c index ebc1534a8df8..20e89b0bdc4d 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c @@ -16,10 +16,10 @@ * data[2] : Time Unit * data[3] : Reload Value */ -static int i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3501_config_insn_timer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct apci3501_private *devpriv = dev->private; unsigned int ul_Command1 = 0; @@ -86,10 +86,10 @@ static int i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev, * 0 Stop * 2 Trigger */ -static int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3501_write_insn_timer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct apci3501_private *devpriv = dev->private; unsigned int ul_Command1 = 0; @@ -153,10 +153,10 @@ static int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *d * 2 Watchdog * data[1] : Timer Counter Watchdog Number */ -static int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3501_read_insn_timer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct apci3501_private *devpriv = dev->private; diff --git a/drivers/staging/comedi/drivers/addi_apci_035.c b/drivers/staging/comedi/drivers/addi_apci_035.c index ccd49211ea17..4da9db35b8e2 100644 --- a/drivers/staging/comedi/drivers/addi_apci_035.c +++ b/drivers/staging/comedi/drivers/addi_apci_035.c @@ -27,13 +27,13 @@ static const struct addi_board apci035_boardtypes[] = { .i_Timer = 1, .ui_MinAcquisitiontimeNs = 10000, .ui_MinDelaytimeNs = 100000, - .interrupt = v_APCI035_Interrupt, - .reset = i_APCI035_Reset, - .ai_config = i_APCI035_ConfigAnalogInput, - .ai_read = i_APCI035_ReadAnalogInput, - .timer_config = i_APCI035_ConfigTimerWatchdog, - .timer_write = i_APCI035_StartStopWriteTimerWatchdog, - .timer_read = i_APCI035_ReadTimerWatchdog, + .interrupt = apci035_interrupt, + .reset = apci035_reset, + .ai_config = apci035_ai_config, + .ai_read = apci035_ai_read, + .timer_config = apci035_timer_config, + .timer_write = apci035_timer_write, + .timer_read = apci035_timer_read, }, }; diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c index 74f7ace8adbc..bd8e08ca14c0 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1500.c +++ b/drivers/staging/comedi/drivers/addi_apci_1500.c @@ -20,19 +20,19 @@ static const struct addi_board apci1500_boardtypes[] = { .i_NbrDoChannel = 16, .i_DoMaxdata = 0xffff, .i_Timer = 1, - .interrupt = v_APCI1500_Interrupt, - .reset = i_APCI1500_Reset, - .di_config = i_APCI1500_ConfigDigitalInputEvent, - .di_read = i_APCI1500_Initialisation, - .di_write = i_APCI1500_StartStopInputEvent, + .interrupt = apci1500_interrupt, + .reset = apci1500_reset, + .di_config = apci1500_di_config, + .di_read = apci1500_di_read, + .di_write = apci1500_di_write, .di_bits = apci1500_di_insn_bits, - .do_config = i_APCI1500_ConfigDigitalOutputErrorInterrupt, - .do_write = i_APCI1500_WriteDigitalOutput, - .do_bits = i_APCI1500_ConfigureInterrupt, - .timer_config = i_APCI1500_ConfigCounterTimerWatchdog, - .timer_write = i_APCI1500_StartStopTriggerTimerCounterWatchdog, - .timer_read = i_APCI1500_ReadInterruptMask, - .timer_bits = i_APCI1500_ReadCounterTimerWatchdog, + .do_config = apci1500_do_config, + .do_write = apci1500_do_write, + .do_bits = apci1500_do_bits, + .timer_config = apci1500_timer_config, + .timer_write = apci1500_timer_write, + .timer_read = apci1500_timer_read, + .timer_bits = apci1500_timer_bits, }, }; diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 6248284caaf5..27aa9ae1bdd9 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -21,16 +21,16 @@ static const struct addi_board apci1564_boardtypes[] = { .i_NbrDoChannel = 32, .i_DoMaxdata = 0xffffffff, .i_Timer = 1, - .interrupt = v_APCI1564_Interrupt, - .reset = i_APCI1564_Reset, - .di_config = i_APCI1564_ConfigDigitalInput, + .interrupt = apci1564_interrupt, + .reset = apci1564_reset, + .di_config = apci1564_di_config, .di_bits = apci1564_di_insn_bits, - .do_config = i_APCI1564_ConfigDigitalOutput, + .do_config = apci1564_do_config, .do_bits = apci1564_do_insn_bits, - .do_read = i_APCI1564_ReadInterruptStatus, - .timer_config = i_APCI1564_ConfigTimerCounterWatchdog, - .timer_write = i_APCI1564_StartStopWriteTimerCounterWatchdog, - .timer_read = i_APCI1564_ReadTimerCounterWatchdog, + .do_read = apci1564_do_read, + .timer_config = apci1564_timer_config, + .timer_write = apci1564_timer_write, + .timer_read = apci1564_timer_read, }, }; diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c index 1e6fa56c516e..57ee6e5c7635 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3120.c +++ b/drivers/staging/comedi/drivers/addi_apci_3120.c @@ -26,7 +26,7 @@ static const struct addi_board apci3120_boardtypes[] = { .i_NbrDiChannel = 4, .i_NbrDoChannel = 4, .i_DoMaxdata = 0x0f, - .interrupt = v_APCI3120_Interrupt, + .interrupt = apci3120_interrupt, }, [BOARD_APCI3001] = { .pc_DriverName = "apci3001", @@ -37,7 +37,7 @@ static const struct addi_board apci3120_boardtypes[] = { .i_NbrDiChannel = 4, .i_NbrDoChannel = 4, .i_DoMaxdata = 0x0f, - .interrupt = v_APCI3120_Interrupt, + .interrupt = apci3120_interrupt, }, }; @@ -136,11 +136,11 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->len_chanlist = this_board->i_AiChannelList; s->range_table = &range_apci3120_ai; - s->insn_config = i_APCI3120_InsnConfigAnalogInput; - s->insn_read = i_APCI3120_InsnReadAnalogInput; - s->do_cmdtest = i_APCI3120_CommandTestAnalogInput; - s->do_cmd = i_APCI3120_CommandAnalogInput; - s->cancel = i_APCI3120_StopCyclicAcquisition; + s->insn_config = apci3120_ai_insn_config; + s->insn_read = apci3120_ai_insn_read; + s->do_cmdtest = apci3120_ai_cmdtest; + s->do_cmd = apci3120_ai_cmd; + s->cancel = apci3120_cancel; /* Allocate and Initialise AO Subdevice Structures */ s = &dev->subdevices[1]; @@ -151,7 +151,7 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->maxdata = this_board->i_AoMaxdata; s->len_chanlist = this_board->i_NbrAoChannel; s->range_table = &range_apci3120_ao; - s->insn_write = i_APCI3120_InsnWriteAnalogOutput; + s->insn_write = apci3120_ao_insn_write; } else { s->type = COMEDI_SUBD_UNUSED; } @@ -186,11 +186,11 @@ static int apci3120_auto_attach(struct comedi_device *dev, s->len_chanlist = 1; s->range_table = &range_digital; - s->insn_write = i_APCI3120_InsnWriteTimer; - s->insn_read = i_APCI3120_InsnReadTimer; - s->insn_config = i_APCI3120_InsnConfigTimer; + s->insn_write = apci3120_write_insn_timer; + s->insn_read = apci3120_read_insn_timer; + s->insn_config = apci3120_config_insn_timer; - i_APCI3120_Reset(dev); + apci3120_reset(dev); return 0; } @@ -200,7 +200,7 @@ static void apci3120_detach(struct comedi_device *dev) if (devpriv) { if (dev->iobase) - i_APCI3120_Reset(dev); + apci3120_reset(dev); if (dev->irq) free_irq(dev->irq, dev); if (devpriv->ul_DmaBufferVirtual[0]) { diff --git a/drivers/staging/comedi/drivers/addi_apci_3200.c b/drivers/staging/comedi/drivers/addi_apci_3200.c index 9868a5369aff..f0f891a482a3 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3200.c +++ b/drivers/staging/comedi/drivers/addi_apci_3200.c @@ -43,15 +43,15 @@ static const struct addi_board apci3200_boardtypes[] = { .i_NbrDoChannel = 4, .ui_MinAcquisitiontimeNs = 10000, .ui_MinDelaytimeNs = 100000, - .interrupt = v_APCI3200_Interrupt, - .reset = i_APCI3200_Reset, - .ai_config = i_APCI3200_ConfigAnalogInput, - .ai_read = i_APCI3200_ReadAnalogInput, - .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput, - .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test, - .ai_cmdtest = i_APCI3200_CommandTestAnalogInput, - .ai_cmd = i_APCI3200_CommandAnalogInput, - .ai_cancel = i_APCI3200_StopCyclicAcquisition, + .interrupt = apci3200_interrupt, + .reset = apci3200_reset, + .ai_config = apci3200_ai_config, + .ai_read = apci3200_ai_read, + .ai_write = apci3200_ai_write, + .ai_bits = apci3200_ai_bits_test, + .ai_cmdtest = apci3200_ai_cmdtest, + .ai_cmd = apci3200_ai_cmd, + .ai_cancel = apci3200_cancel, .di_bits = apci3200_di_insn_bits, .do_bits = apci3200_do_insn_bits, }, @@ -68,15 +68,15 @@ static const struct addi_board apci3200_boardtypes[] = { .i_NbrDoChannel = 4, .ui_MinAcquisitiontimeNs = 10000, .ui_MinDelaytimeNs = 100000, - .interrupt = v_APCI3200_Interrupt, - .reset = i_APCI3200_Reset, - .ai_config = i_APCI3200_ConfigAnalogInput, - .ai_read = i_APCI3200_ReadAnalogInput, - .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput, - .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test, - .ai_cmdtest = i_APCI3200_CommandTestAnalogInput, - .ai_cmd = i_APCI3200_CommandAnalogInput, - .ai_cancel = i_APCI3200_StopCyclicAcquisition, + .interrupt = apci3200_interrupt, + .reset = apci3200_reset, + .ai_config = apci3200_ai_config, + .ai_read = apci3200_ai_read, + .ai_write = apci3200_ai_write, + .ai_bits = apci3200_ai_bits_test, + .ai_cmdtest = apci3200_ai_cmdtest, + .ai_cmd = apci3200_ai_cmd, + .ai_cancel = apci3200_cancel, .di_bits = apci3200_di_insn_bits, .do_bits = apci3200_do_insn_bits, }, diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c index 4cb69ec54c9b..49bf1fb840f6 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3501.c +++ b/drivers/staging/comedi/drivers/addi_apci_3501.c @@ -390,9 +390,9 @@ static int apci3501_auto_attach(struct comedi_device *dev, s->maxdata = 0; s->len_chanlist = 1; s->range_table = &range_digital; - s->insn_write = i_APCI3501_StartStopWriteTimerCounterWatchdog; - s->insn_read = i_APCI3501_ReadTimerCounterWatchdog; - s->insn_config = i_APCI3501_ConfigTimerCounterWatchdog; + s->insn_write = apci3501_write_insn_timer; + s->insn_read = apci3501_read_insn_timer; + s->insn_config = apci3501_config_insn_timer; /* Initialize the eeprom subdevice */ s = &dev->subdevices[4]; diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c index ceadf8eff47f..6dc11c407f57 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c +++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c @@ -434,13 +434,26 @@ static int apci3xxx_ai_setup(struct comedi_device *dev, unsigned int chanspec) return 0; } +static int apci3xxx_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->mmio + 20); + if (status & 0x1) + return 0; + return -EBUSY; +} + static int apci3xxx_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct apci3xxx_private *devpriv = dev->private; - unsigned int val; int ret; int i; @@ -453,10 +466,9 @@ static int apci3xxx_ai_insn_read(struct comedi_device *dev, writel(0x80000, devpriv->mmio + 8); /* Wait the EOS */ - do { - val = readl(devpriv->mmio + 20); - val &= 0x1; - } while (!val); + ret = comedi_timeout(dev, s, insn, apci3xxx_ai_eoc, 0); + if (ret) + return ret; /* Read the analog value */ data[i] = readl(devpriv->mmio + 28); @@ -622,6 +634,20 @@ static int apci3xxx_ai_cancel(struct comedi_device *dev, return 0; } +static int apci3xxx_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->mmio + 96); + if (status & 0x100) + return 0; + return -EBUSY; +} + static int apci3xxx_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -630,7 +656,7 @@ static int apci3xxx_ao_insn_write(struct comedi_device *dev, struct apci3xxx_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); - unsigned int status; + int ret; int i; for (i = 0; i < insn->n; i++) { @@ -641,9 +667,9 @@ static int apci3xxx_ao_insn_write(struct comedi_device *dev, writel((data[i] << 8) | chan, devpriv->mmio + 100); /* Wait the end of transfer */ - do { - status = readl(devpriv->mmio + 96); - } while ((status & 0x100) != 0x100); + ret = comedi_timeout(dev, s, insn, apci3xxx_ao_eoc, 0); + if (ret) + return ret; } return insn->n; @@ -680,7 +706,7 @@ static int apci3xxx_dio_insn_config(struct comedi_device *dev, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int mask; + unsigned int mask = 0; int ret; /* @@ -688,12 +714,13 @@ static int apci3xxx_dio_insn_config(struct comedi_device *dev, * Port 1 (channels 8-15) are always outputs * Port 2 (channels 16-23) are programmable i/o */ - if (chan < 16) { - if (data[0] != INSN_CONFIG_DIO_QUERY) + if (data[0] != INSN_CONFIG_DIO_QUERY) { + /* ignore all other instructions for ports 0 and 1 */ + if (chan < 16) return -EINVAL; - } else { - /* changing any channel in port 2 changes the entire port */ - mask = 0xff0000; + else + /* changing any channel in port 2 changes the entire port */ + mask = 0xff0000; } ret = comedi_dio_insn_config(dev, s, insn, data, mask); diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c index 5c1413abc52d..921f6942dfce 100644 --- a/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/drivers/staging/comedi/drivers/adl_pci6208.c @@ -73,19 +73,17 @@ struct pci6208_private { unsigned int ao_readback[PCI6208_MAX_AO_CHANNELS]; }; -static int pci6208_ao_wait_for_data_send(struct comedi_device *dev, - unsigned int timeout) +static int pci6208_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned int status; - while (timeout--) { - status = inw(dev->iobase + PCI6208_AO_STATUS); - if ((status & PCI6208_AO_STATUS_DATA_SEND) == 0) - return 0; - udelay(1); - } - - return -ETIME; + status = inw(dev->iobase + PCI6208_AO_STATUS); + if ((status & PCI6208_AO_STATUS_DATA_SEND) == 0) + return 0; + return -EBUSY; } static int pci6208_ao_insn_write(struct comedi_device *dev, @@ -102,8 +100,8 @@ static int pci6208_ao_insn_write(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { val = data[i]; - /* D/A transfer rate is 2.2us, wait up to 10us */ - ret = pci6208_ao_wait_for_data_send(dev, 10); + /* D/A transfer rate is 2.2us */ + ret = comedi_timeout(dev, s, insn, pci6208_ao_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c index 6f622b4de698..5e3cc77a8a0c 100644 --- a/drivers/staging/comedi/drivers/adl_pci7x3x.c +++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c @@ -239,9 +239,6 @@ static int adl_pci7x3x_auto_attach(struct comedi_device *dev, } } - dev_info(dev->class_dev, "%s attached (%d inputs/%d outputs)\n", - dev->board_name, board->di_nchan, board->do_nchan); - return 0; } diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c index 363f2e42a27f..a29ceacb966d 100644 --- a/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/drivers/staging/comedi/drivers/adl_pci9111.c @@ -84,7 +84,6 @@ TODO: #define PCI9111_RANGE_SETTING_DELAY 10 #define PCI9111_AI_INSTANT_READ_UDELAY_US 2 -#define PCI9111_AI_INSTANT_READ_TIMEOUT 100 /* * IO address map and bit defines @@ -490,29 +489,18 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, dev->iobase + PCI9111_AI_RANGE_STAT_REG); /* Set counter */ - - switch (async_cmd->stop_src) { - case TRIG_COUNT: + if (async_cmd->stop_src == TRIG_COUNT) { dev_private->stop_counter = async_cmd->stop_arg * async_cmd->chanlist_len; dev_private->stop_is_none = 0; - break; - - case TRIG_NONE: + } else { /* TRIG_NONE */ dev_private->stop_counter = 0; dev_private->stop_is_none = 1; - break; - - default: - comedi_error(dev, "Invalid stop trigger"); - return -1; } /* Set timer pacer */ - dev_private->scan_delay = 0; - switch (async_cmd->convert_src) { - case TRIG_TIMER: + if (async_cmd->convert_src == TRIG_TIMER) { pci9111_trigger_source_set(dev, software); pci9111_timer_set(dev); pci9111_fifo_reset(dev); @@ -528,11 +516,7 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, (async_cmd->convert_arg * async_cmd->chanlist_len)) - 1; } - - break; - - case TRIG_EXT: - + } else { /* TRIG_EXT */ pci9111_trigger_source_set(dev, external); pci9111_fifo_reset(dev); pci9111_interrupt_source_set(dev, irq_on_fifo_half_full, @@ -540,11 +524,6 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, plx9050_interrupt_control(dev_private->lcr_io_base, true, true, false, true, true); - break; - - default: - comedi_error(dev, "Invalid convert trigger"); - return -1; } dev_private->stop_counter *= (1 + dev_private->scan_delay); @@ -613,9 +592,8 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device) spin_unlock_irqrestore(&dev->spinlock, irq_flags); comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow"); outb(0, dev->iobase + PCI9111_INT_CLR_REG); - pci9111_ai_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -693,20 +671,31 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device) } } - if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) { + if (dev_private->stop_counter == 0 && !dev_private->stop_is_none) async->events |= COMEDI_CB_EOA; - pci9111_ai_cancel(dev, s); - } outb(0, dev->iobase + PCI9111_INT_CLR_REG); spin_unlock_irqrestore(&dev->spinlock, irq_flags); - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } +static int pci9111_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); + if (status & PCI9111_AI_STAT_FF_EF) + return 0; + return -EBUSY; +} + static int pci9111_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -717,7 +706,7 @@ static int pci9111_ai_insn_read(struct comedi_device *dev, unsigned int invert = (maxdata + 1) >> 1; unsigned int shift = (maxdata == 0xffff) ? 0 : 4; unsigned int status; - int timeout; + int ret; int i; outb(chan, dev->iobase + PCI9111_AI_CHANNEL_REG); @@ -734,22 +723,12 @@ static int pci9111_ai_insn_read(struct comedi_device *dev, /* Generate a software trigger */ outb(0, dev->iobase + PCI9111_SOFT_TRIG_REG); - timeout = PCI9111_AI_INSTANT_READ_TIMEOUT; - - while (timeout--) { - status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); - /* '1' means FIFO is not empty */ - if (status & PCI9111_AI_STAT_FF_EF) - goto conversion_done; + ret = comedi_timeout(dev, s, insn, pci9111_ai_eoc, 0); + if (ret) { + pci9111_fifo_reset(dev); + return ret; } - comedi_error(dev, "A/D read timeout"); - data[i] = 0; - pci9111_fifo_reset(dev); - return -ETIME; - -conversion_done: - data[i] = inw(dev->iobase + PCI9111_AI_FIFO_REG); data[i] = ((data[i] >> shift) & maxdata) ^ invert; } @@ -906,8 +885,6 @@ static int pci9111_auto_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = pci9111_do_insn_bits; - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c index 4bdd9720e9eb..3cfa1756fa6a 100644 --- a/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/drivers/staging/comedi/drivers/adl_pci9118.c @@ -571,12 +571,26 @@ static int setup_channel_list(struct comedi_device *dev, return 1; /* we can serve this with scan logic */ } +static int pci9118_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inl(dev->iobase + PCI9118_ADSTAT); + if (status & AdStatus_ADrdy) + return 0; + return -EBUSY; +} + static int pci9118_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct pci9118_private *devpriv = dev->private; - int n, timeout; + int ret; + int n; devpriv->AdControlReg = AdControl_Int & 0xff; devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; @@ -597,19 +611,13 @@ static int pci9118_insn_read_ai(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { outw(0, dev->iobase + PCI9118_SOFTTRG); /* start conversion */ udelay(2); - timeout = 100; - while (timeout--) { - if (inl(dev->iobase + PCI9118_ADSTAT) & AdStatus_ADrdy) - goto conv_finish; - udelay(1); + + ret = comedi_timeout(dev, s, insn, pci9118_ai_eoc, 0); + if (ret) { + outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ + return ret; } - comedi_error(dev, "A/D insn timeout"); - data[n] = 0; - outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ - return -ETIME; - -conv_finish: if (devpriv->ai16bits) { data[n] = (inl(dev->iobase + @@ -911,8 +919,7 @@ static char pci9118_decode_error_status(struct comedi_device *dev, } if (m & devpriv->ai_maskharderr) { s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - pci9118_ai_cancel(dev, s); - comedi_event(dev, s); + cfc_handle_events(dev, s); return 1; } @@ -948,8 +955,6 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, struct pci9118_private *devpriv = dev->private; unsigned short sampl; - s->async->events = 0; - if (int_adstat & devpriv->ai_maskerr) if (pci9118_decode_error_status(dev, s, int_adstat)) return; @@ -965,8 +970,7 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, sampl & 0x000f, devpriv->chanlist[s->async->cur_chan]); s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - pci9118_ai_cancel(dev, s); - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } } @@ -977,16 +981,14 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, /* one scan done */ s->async->cur_chan %= devpriv->ai_n_scanlen; devpriv->ai_act_scan++; - if (!(devpriv->ai_neverending)) - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - /* all data sampled */ - pci9118_ai_cancel(dev, s); + if (!devpriv->ai_neverending) { + /* all data sampled? */ + if (devpriv->ai_act_scan >= devpriv->ai_scans) s->async->events |= COMEDI_CB_EOA; - } + } } - if (s->async->events) - comedi_event(dev, s); + cfc_handle_events(dev, s); } static void interrupt_pci9118_ai_dma(struct comedi_device *dev, @@ -1001,16 +1003,14 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, if (int_amcc & MASTER_ABORT_INT) { comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!"); s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - pci9118_ai_cancel(dev, s); - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } if (int_amcc & TARGET_ABORT_INT) { comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!"); s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - pci9118_ai_cancel(dev, s); - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } if (int_adstat & devpriv->ai_maskerr) @@ -1048,12 +1048,11 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, m = m - sampls; /* m= how many samples was transferred */ } - if (!devpriv->ai_neverending) - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - /* all data sampled */ - pci9118_ai_cancel(dev, s); + if (!devpriv->ai_neverending) { + /* all data sampled? */ + if (devpriv->ai_act_scan >= devpriv->ai_scans) s->async->events |= COMEDI_CB_EOA; - } + } if (devpriv->dma_doublebuf) { /* switch dma buffers */ devpriv->dma_actbuf = 1 - devpriv->dma_actbuf; @@ -1066,7 +1065,7 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, interrupt_pci9118_ai_mode4_switch(dev); } - comedi_event(dev, s); + cfc_handle_events(dev, s); } static irqreturn_t interrupt_pci9118(int irq, void *d) @@ -1936,28 +1935,6 @@ static struct pci_dev *pci9118_find_pci(struct comedi_device *dev, return NULL; } -static void pci9118_report_attach(struct comedi_device *dev, unsigned int irq) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct pci9118_private *devpriv = dev->private; - char irqbuf[30]; - char muxbuf[30]; - - if (irq) - snprintf(irqbuf, sizeof(irqbuf), "irq %u%s", irq, - (dev->irq ? "" : " UNAVAILABLE")); - else - snprintf(irqbuf, sizeof(irqbuf), "irq DISABLED"); - if (devpriv->usemux) - snprintf(muxbuf, sizeof(muxbuf), "ext mux %u chans", - devpriv->usemux); - else - snprintf(muxbuf, sizeof(muxbuf), "no ext mux"); - dev_info(dev->class_dev, "%s (pci %s, %s, %sbus master, %s) attached\n", - dev->board_name, pci_name(pcidev), irqbuf, - (devpriv->master ? "" : "no "), muxbuf); -} - static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, int master, int ext_mux, int softsshdelay, int hw_err_mask) @@ -2113,7 +2090,6 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, break; } - pci9118_report_attach(dev, dev->irq); return 0; } diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c index 3190ef7d285e..b4ea37704eaf 100644 --- a/drivers/staging/comedi/drivers/adq12b.c +++ b/drivers/staging/comedi/drivers/adq12b.c @@ -94,8 +94,6 @@ If you do not specify any options, they will default to /* mask of the bit at STINR to check end of conversion */ #define ADQ12B_EOC 0x20 -#define TIMEOUT 20 - /* available ranges through the PGA gains */ static const struct comedi_lrange range_adq12b_ai_bipolar = { 4, { @@ -122,19 +120,28 @@ struct adq12b_private { int last_range; }; -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ +static int adq12b_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned char status; + + status = inb(dev->iobase + ADQ12B_STINR); + if (status & ADQ12B_EOC) + return 0; + return -EBUSY; +} static int adq12b_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct adq12b_private *devpriv = dev->private; - int n, i; + int n; int range, channel; unsigned char hi, lo, status; + int ret; /* change channel and range only if it is different from the previous */ range = CR_RANGE(insn->chanspec); @@ -151,13 +158,9 @@ static int adq12b_ai_rinsn(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { /* wait for end of conversion */ - i = 0; - do { - /* udelay(1); */ - status = inb(dev->iobase + ADQ12B_STINR); - status = status & ADQ12B_EOC; - } while (status == 0 && ++i < TIMEOUT); - /* } while (++i < 10); */ + ret = comedi_timeout(dev, s, insn, adq12b_ai_eoc, 0); + if (ret) + return ret; /* read data */ hi = inb(dev->iobase + ADQ12B_ADHIG); diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index d9ad2c0fdda2..28ec48548317 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -429,15 +429,26 @@ static void setup_channel_list(struct comedi_device *dev, outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); } -/* -============================================================================== -*/ +static int pci171x_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + PCI171x_STATUS); + if ((status & Status_FE) == 0) + return 0; + return -EBUSY; +} + static int pci171x_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct pci1710_private *devpriv = dev->private; - int n, timeout; + int ret; + int n; #ifdef PCI171x_PARANOIDCHECK const struct boardtype *this_board = comedi_board(dev); unsigned int idata; @@ -453,19 +464,14 @@ static int pci171x_insn_read_ai(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */ - /* udelay(1); */ - timeout = 100; - while (timeout--) { - if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE)) - goto conv_finish; - } - comedi_error(dev, "A/D insn timeout"); - outb(0, dev->iobase + PCI171x_CLRFIFO); - outb(0, dev->iobase + PCI171x_CLRINT); - data[n] = 0; - return -ETIME; -conv_finish: + ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0); + if (ret) { + outb(0, dev->iobase + PCI171x_CLRFIFO); + outb(0, dev->iobase + PCI171x_CLRINT); + return ret; + } + #ifdef PCI171x_PARANOIDCHECK idata = inw(dev->iobase + PCI171x_AD_DATA); if (this_board->cardtype != TYPE_PCI1713) @@ -753,17 +759,15 @@ static void interrupt_pci1710_every_sample(void *d) m = inw(dev->iobase + PCI171x_STATUS); if (m & Status_FE) { dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", m); - pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } if (m & Status_FF) { dev_dbg(dev->class_dev, "A/D FIFO Full status (Fatal Error!) (%4x)\n", m); - pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } @@ -782,10 +786,9 @@ static void interrupt_pci1710_every_sample(void *d) act_chanlist[s-> async->cur_chan] & 0xf000) >> 12); - pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } comedi_buf_put(s->async, sampl & 0x0fff); @@ -804,9 +807,8 @@ static void interrupt_pci1710_every_sample(void *d) if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) { /* all data sampled */ - pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } } @@ -814,7 +816,7 @@ static void interrupt_pci1710_every_sample(void *d) outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ - comedi_event(dev, s); + cfc_handle_events(dev, s); } /* @@ -842,10 +844,9 @@ static int move_block_from_fifo(struct comedi_device *dev, (devpriv->act_chanlist[j] & 0xf000) >> 12, i, j, devpriv->ai_act_scan, n, turn, sampl); - pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return 1; } comedi_buf_put(s->async, sampl & 0x0fff); @@ -877,17 +878,15 @@ static void interrupt_pci1710_half_fifo(void *d) m = inw(dev->iobase + PCI171x_STATUS); if (!(m & Status_FH)) { dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m); - pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } if (m & Status_FF) { dev_dbg(dev->class_dev, "A/D FIFO Full status (Fatal Error!) (%4x)\n", m); - pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } @@ -907,14 +906,13 @@ static void interrupt_pci1710_half_fifo(void *d) if (!devpriv->neverending_ai) if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data sampled */ - pci171x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ - comedi_event(dev, s); + cfc_handle_events(dev, s); } /* @@ -1354,9 +1352,6 @@ static int pci1710_auto_attach(struct comedi_device *dev, subdev++; } - dev_info(dev->class_dev, "%s attached, irq %sabled\n", - dev->board_name, dev->irq ? "en" : "dis"); - return 0; } diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c index 72394267ddfe..07b107d1ab33 100644 --- a/drivers/staging/comedi/drivers/adv_pci1723.c +++ b/drivers/staging/comedi/drivers/adv_pci1723.c @@ -280,8 +280,6 @@ static int pci1723_auto_attach(struct comedi_device *dev, pci1723_reset(dev); - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c index d4bd61d84daf..2d966a87f2e8 100644 --- a/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/drivers/staging/comedi/drivers/adv_pci_dio.c @@ -1130,10 +1130,12 @@ static int pci_dio_auto_attach(struct comedi_device *dev, for (i = 0; i < MAX_DIO_SUBDEVG; i++) for (j = 0; j < this_board->sdio[i].regs; j++) { s = &dev->subdevices[subdev]; - subdev_8255_init(dev, s, NULL, - dev->iobase + - this_board->sdio[i].addr + - SIZE_8255 * j); + ret = subdev_8255_init(dev, s, NULL, + dev->iobase + + this_board->sdio[i].addr + + SIZE_8255 * j); + if (ret) + return ret; subdev++; } diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c index 68c3fb3226ca..324746b14931 100644 --- a/drivers/staging/comedi/drivers/aio_aio12_8.c +++ b/drivers/staging/comedi/drivers/aio_aio12_8.c @@ -101,14 +101,27 @@ struct aio12_8_private { unsigned int ao_readback[4]; }; +static int aio_aio12_8_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + AIO12_8_STATUS_REG); + if (status & AIO12_8_STATUS_ADC_EOC) + return 0; + return -EBUSY; +} + static int aio_aio12_8_ai_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); unsigned int range = CR_RANGE(insn->chanspec); - unsigned int val; unsigned char control; + int ret; int n; /* @@ -122,20 +135,13 @@ static int aio_aio12_8_ai_read(struct comedi_device *dev, inb(dev->iobase + AIO12_8_STATUS_REG); for (n = 0; n < insn->n; n++) { - int timeout = 5; - /* Setup and start conversion */ outb(control, dev->iobase + AIO12_8_ADC_REG); /* Wait for conversion to complete */ - do { - val = inb(dev->iobase + AIO12_8_STATUS_REG); - timeout--; - if (timeout == 0) { - dev_err(dev->class_dev, "ADC timeout\n"); - return -ETIMEDOUT; - } - } while (!(val & AIO12_8_STATUS_ADC_EOC)); + ret = comedi_timeout(dev, s, insn, aio_aio12_8_ai_eoc, 0); + if (ret) + return ret; data[n] = inw(dev->iobase + AIO12_8_ADC_REG) & s->maxdata; } @@ -247,9 +253,6 @@ static int aio_aio12_8_attach(struct comedi_device *dev, /* 8254 counter/timer subdevice */ s->type = COMEDI_SUBD_UNUSED; - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c index 22b3dda135ff..781104aa533e 100644 --- a/drivers/staging/comedi/drivers/aio_iiro_16.c +++ b/drivers/staging/comedi/drivers/aio_iiro_16.c @@ -98,7 +98,7 @@ static int aio_iiro_16_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = aio_iiro_16_dio_insn_bits_read; - return 1; + return 0; } static struct comedi_driver aio_iiro_16_driver = { diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c index 9c9559ffc643..818a0d7e3d58 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200_common.c +++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c @@ -1208,7 +1208,7 @@ int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq, "warning! irq %u unavailable!\n", irq); } } - dev_info(dev->class_dev, "attached\n"); + return 0; } EXPORT_SYMBOL_GPL(amplc_dio200_common_attach); diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c index 31734e1142fd..b21d7b48f1da 100644 --- a/drivers/staging/comedi/drivers/amplc_pc236.c +++ b/drivers/staging/comedi/drivers/amplc_pc236.c @@ -368,32 +368,6 @@ static irqreturn_t pc236_interrupt(int irq, void *d) return IRQ_RETVAL(handled); } -static void pc236_report_attach(struct comedi_device *dev, unsigned int irq) -{ - const struct pc236_board *thisboard = comedi_board(dev); - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - char tmpbuf[60]; - int tmplen; - - if (is_isa_board(thisboard)) - tmplen = scnprintf(tmpbuf, sizeof(tmpbuf), - "(base %#lx) ", dev->iobase); - else if (is_pci_board(thisboard)) - tmplen = scnprintf(tmpbuf, sizeof(tmpbuf), - "(pci %s) ", pci_name(pcidev)); - else - tmplen = 0; - if (irq) - tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen, - "(irq %u%s) ", irq, - (dev->irq ? "" : " UNAVAILABLE")); - else - tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen, - "(no irq) "); - dev_info(dev->class_dev, "%s %sattached\n", - dev->board_name, tmpbuf); -} - static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase, unsigned int irq, unsigned long req_irq_flags) { @@ -411,10 +385,9 @@ static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase, s = &dev->subdevices[0]; /* digital i/o subdevice (8255) */ ret = subdev_8255_init(dev, s, NULL, iobase); - if (ret < 0) { - dev_err(dev->class_dev, "error! out of memory!\n"); + if (ret) return ret; - } + s = &dev->subdevices[1]; dev->read_subdev = s; s->type = COMEDI_SUBD_UNUSED; @@ -434,8 +407,8 @@ static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase, s->cancel = pc236_intr_cancel; } } - pc236_report_attach(dev, irq); - return 1; + + return 0; } static int pc236_pci_common_attach(struct comedi_device *dev, diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c index 5b4b5ab34e2e..7c10d28d2784 100644 --- a/drivers/staging/comedi/drivers/amplc_pc263.c +++ b/drivers/staging/comedi/drivers/amplc_pc263.c @@ -94,8 +94,6 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* read initial relay state */ s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8); - dev_info(dev->class_dev, "%s (base %#lx) attached\n", dev->board_name, - dev->iobase); return 0; } diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c index ae4048a624fa..29e01e280039 100644 --- a/drivers/staging/comedi/drivers/amplc_pci224.c +++ b/drivers/staging/comedi/drivers/amplc_pci224.c @@ -533,9 +533,8 @@ static void pci224_ao_start(struct comedi_device *dev, set_bit(AO_CMD_STARTED, &devpriv->state); if (!devpriv->ao_stop_continuous && devpriv->ao_stop_count == 0) { /* An empty acquisition! */ - pci224_ao_stop(dev, s); s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); } else { /* Enable interrupts. */ spin_lock_irqsave(&devpriv->ao_spinlock, flags); @@ -585,9 +584,8 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, room = PCI224_FIFO_ROOM_EMPTY; if (!devpriv->ao_stop_continuous && devpriv->ao_stop_count == 0) { /* FIFO empty at end of counted acquisition. */ - pci224_ao_stop(dev, s); s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } break; @@ -605,9 +603,8 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, /* FIFO is less than half-full. */ if (num_scans == 0) { /* Nothing left to put in the FIFO. */ - pci224_ao_stop(dev, s); - s->async->events |= COMEDI_CB_OVERFLOW; dev_err(dev->class_dev, "AO buffer underrun\n"); + s->async->events |= COMEDI_CB_OVERFLOW; } } /* Determine how many new scans can be put in the FIFO. */ @@ -670,9 +667,8 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, PCI224_DACCON_TRIG_MASK); outw(devpriv->daccon, dev->iobase + PCI224_DACCON); } - if (s->async->events) - comedi_event(dev, s); + cfc_handle_events(dev, s); } /* @@ -1237,20 +1233,6 @@ static struct pci_dev *pci224_find_pci_dev(struct comedi_device *dev, return NULL; } -static void pci224_report_attach(struct comedi_device *dev, unsigned int irq) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - char tmpbuf[30]; - - if (irq) - snprintf(tmpbuf, sizeof(tmpbuf), "irq %u%s", irq, - (dev->irq ? "" : " UNAVAILABLE")); - else - snprintf(tmpbuf, sizeof(tmpbuf), "no irq"); - dev_info(dev->class_dev, "%s (pci %s) (%s) attached\n", - dev->board_name, pci_name(pcidev), tmpbuf); -} - /* * Common part of attach and auto_attach. */ @@ -1399,8 +1381,7 @@ static int pci224_attach_common(struct comedi_device *dev, } } - pci224_report_attach(dev, irq); - return 1; + return 0; } static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index c08dfbbe4062..99e60835dc4a 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -799,19 +799,29 @@ static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct) /* Counter ct, 8254 mode 1, initial count not written. */ } -/* - * COMEDI_SUBD_AI instruction; - */ +static int pci230_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + PCI230_ADCCON); + if ((status & PCI230_ADC_FIFO_EMPTY) == 0) + return 0; + return -EBUSY; +} + static int pci230_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct pci230_private *devpriv = dev->private; - unsigned int n, i; + unsigned int n; unsigned int chan, range, aref; unsigned int gainshift; - unsigned int status; unsigned short adccon, adcen; + int ret; /* Unpack channel and range. */ chan = CR_CHAN(insn->chanspec); @@ -883,18 +893,10 @@ static int pci230_ai_rinsn(struct comedi_device *dev, i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1); -#define TIMEOUT 100 /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = inw(dev->iobase + PCI230_ADCCON); - if (!(status & PCI230_ADC_FIFO_EMPTY)) - break; - udelay(1); - } - if (i == TIMEOUT) { - dev_err(dev->class_dev, "timeout\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, pci230_ai_eoc, 0); + if (ret) + return ret; /* read data */ data[n] = pci230_ai_read(dev); @@ -2762,14 +2764,14 @@ static int pci230_attach_common(struct comedi_device *dev, /* digital i/o subdevice */ if (thisboard->have_dio) { rc = subdev_8255_init(dev, s, NULL, - (devpriv->iobase1 + PCI230_PPI_X_BASE)); - if (rc < 0) + devpriv->iobase1 + PCI230_PPI_X_BASE); + if (rc) return rc; } else { s->type = COMEDI_SUBD_UNUSED; } - dev_info(dev->class_dev, "attached\n"); - return 1; + + return 0; } static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it) diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/staging/comedi/drivers/amplc_pci263.c index be28e6cbea20..93ed03ee416a 100644 --- a/drivers/staging/comedi/drivers/amplc_pci263.c +++ b/drivers/staging/comedi/drivers/amplc_pci263.c @@ -84,8 +84,6 @@ static int pci263_auto_attach(struct comedi_device *dev, /* read initial relay state */ s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8); - dev_info(dev->class_dev, "%s (pci %s) attached\n", dev->board_name, - pci_name(pci_dev)); return 0; } diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c index 5034f663eec9..e03dd6e71415 100644 --- a/drivers/staging/comedi/drivers/c6xdigio.c +++ b/drivers/staging/comedi/drivers/c6xdigio.c @@ -1,34 +1,33 @@ /* - comedi/drivers/c6xdigio.c - - Hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card. - (http://robot0.ge.uiuc.edu/~spong/mecha/) - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999 Dan Block - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * c6xdigio.c + * Hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card. + * http://web.archive.org/web/%2A/http://robot0.ge.uiuc.edu/~spong/mecha/ + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1999 Dan Block + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ + /* -Driver: c6xdigio -Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card -Author: Dan Block -Status: unknown -Devices: [Mechatronic Systems Inc.] C6x_DIGIO DSP daughter card (c6xdigio) -Updated: Sun Nov 20 20:18:34 EST 2005 - -This driver will not work with a 2.4 kernel. -http://robot0.ge.uiuc.edu/~spong/mecha/ - -*/ + * Driver: c6xdigio + * Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card + * Author: Dan Block + * Status: unknown + * Devices: (Mechatronic Systems Inc.) C6x_DIGIO DSP daughter card [c6xdigio] + * Updated: Sun Nov 20 20:18:34 EST 2005 + * + * Configuration Options: + * [0] - base address + */ #include #include @@ -43,309 +42,194 @@ http://robot0.ge.uiuc.edu/~spong/mecha/ #include "../comedidev.h" -static u8 ReadByteFromHwPort(unsigned long addr) -{ - u8 result = inb(addr); - return result; -} - -static void WriteByteToHwPort(unsigned long addr, u8 val) -{ - outb_p(val, addr); -} - -#define C6XDIGIO_SIZE 3 - /* - * port offsets + * Register I/O map */ -#define C6XDIGIO_PARALLEL_DATA 0 -#define C6XDIGIO_PARALLEL_STATUS 1 -#define C6XDIGIO_PARALLEL_CONTROL 2 -struct pwmbitstype { - unsigned sb0:2; - unsigned sb1:2; - unsigned sb2:2; - unsigned sb3:2; - unsigned sb4:2; -}; -union pwmcmdtype { - unsigned cmd; /* assuming here that int is 32bit */ - struct pwmbitstype bits; -}; -struct encbitstype { - unsigned sb0:3; - unsigned sb1:3; - unsigned sb2:3; - unsigned sb3:3; - unsigned sb4:3; - unsigned sb5:3; - unsigned sb6:3; - unsigned sb7:3; -}; -union encvaluetype { - unsigned value; - struct encbitstype bits; -}; +#define C6XDIGIO_DATA_REG 0x00 +#define C6XDIGIO_DATA_CHAN(x) (((x) + 1) << 4) +#define C6XDIGIO_DATA_PWM (1 << 5) +#define C6XDIGIO_DATA_ENCODER (1 << 6) +#define C6XDIGIO_STATUS_REG 0x01 +#define C6XDIGIO_CTRL_REG 0x02 #define C6XDIGIO_TIME_OUT 20 -static void C6X_pwmInit(unsigned long baseAddr) +static int c6xdigio_chk_status(struct comedi_device *dev, unsigned long context) { + unsigned int status; int timeout = 0; - WriteByteToHwPort(baseAddr, 0x70); - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0) - && (timeout < C6XDIGIO_TIME_OUT)) { + do { + status = inb(dev->iobase + C6XDIGIO_STATUS_REG); + if ((status & 0x80) != context) + return 0; timeout++; - } - - WriteByteToHwPort(baseAddr, 0x74); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - - WriteByteToHwPort(baseAddr, 0x70); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } + } while (timeout < C6XDIGIO_TIME_OUT); + return -EBUSY; } -static void C6X_pwmOutput(unsigned long baseAddr, unsigned channel, int value) +static int c6xdigio_write_data(struct comedi_device *dev, + unsigned int val, unsigned int status) { - unsigned ppcmd; - union pwmcmdtype pwm; - int timeout = 0; - unsigned tmp; - - pwm.cmd = value; - if (pwm.cmd > 498) - pwm.cmd = 498; - if (pwm.cmd < 2) - pwm.cmd = 2; - - if (channel == 0) { - ppcmd = 0x28; - } else { /* if channel == 1 */ - ppcmd = 0x30; - } /* endif */ - - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb0); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb1 + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb2); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb3 + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb4); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - + outb_p(val, dev->iobase + C6XDIGIO_DATA_REG); + return c6xdigio_chk_status(dev, status); } -static int C6X_encInput(unsigned long baseAddr, unsigned channel) +static int c6xdigio_get_encoder_bits(struct comedi_device *dev, + unsigned int *bits, + unsigned int cmd, + unsigned int status) { - unsigned ppcmd; - union encvaluetype enc; - int timeout = 0; - int tmp; + unsigned int val; - enc.value = 0; - if (channel == 0) - ppcmd = 0x48; - else - ppcmd = 0x50; + val = inb(dev->iobase + C6XDIGIO_STATUS_REG); + val >>= 3; + val &= 0x07; - WriteByteToHwPort(baseAddr, ppcmd); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + *bits = val; - enc.bits.sb0 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb1 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb2 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb3 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb4 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb5 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb6 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb7 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - - return enc.value ^ 0x800000; + return c6xdigio_write_data(dev, cmd, status); } -static void C6X_encResetAll(unsigned long baseAddr) +static void c6xdigio_pwm_write(struct comedi_device *dev, + unsigned int chan, unsigned int val) { - unsigned timeout = 0; + unsigned int cmd = C6XDIGIO_DATA_PWM | C6XDIGIO_DATA_CHAN(chan); + unsigned int bits; - WriteByteToHwPort(baseAddr, 0x68); - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - WriteByteToHwPort(baseAddr, 0x6C); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - WriteByteToHwPort(baseAddr, 0x68); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } + if (val > 498) + val = 498; + if (val < 2) + val = 2; + + bits = (val >> 0) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00); + bits = (val >> 2) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (1 << 2), 0x80); + bits = (val >> 4) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00); + bits = (val >> 6) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (1 << 2), 0x80); + bits = (val >> 8) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00); + + c6xdigio_write_data(dev, 0x00, 0x80); } -static int c6xdigio_pwmo_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int c6xdigio_encoder_read(struct comedi_device *dev, + unsigned int chan) { + unsigned int cmd = C6XDIGIO_DATA_ENCODER | C6XDIGIO_DATA_CHAN(chan); + unsigned int val = 0; + unsigned int bits; + + c6xdigio_write_data(dev, cmd, 0x00); + + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 0); + + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 3); + + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 6); + + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 9); + + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 12); + + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 15); + + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 18); + + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 21); + + c6xdigio_write_data(dev, 0x00, 0x80); + + return val; +} + +static int c6xdigio_pwm_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = (s->state >> (16 * chan)) & 0xffff; int i; - int chan = CR_CHAN(insn->chanspec); for (i = 0; i < insn->n; i++) { - C6X_pwmOutput(dev->iobase, chan, data[i]); - /* devpriv->ao_readback[chan] = data[i]; */ + val = data[i]; + c6xdigio_pwm_write(dev, chan, val); } - return i; + + /* + * There are only 2 PWM channels and they have a maxdata of 500. + * Instead of allocating private data to save the values in for + * readback this driver just packs the values for the two channels + * in the s->state. + */ + s->state &= (0xffff << (16 * chan)); + s->state |= (val << (16 * chan)); + + return insn->n; } -static int c6xdigio_ei_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int c6xdigio_pwm_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int n; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; - for (n = 0; n < insn->n; n++) - data[n] = (C6X_encInput(dev->iobase, chan) & 0xffffff); + val = (s->state >> (16 * chan)) & 0xffff; - return n; + for (i = 0; i < insn->n; i++) + data[i] = val; + + return insn->n; } -static void board_init(struct comedi_device *dev) +static int c6xdigio_encoder_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - C6X_pwmInit(dev->iobase); - C6X_encResetAll(dev->iobase); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; + + for (i = 0; i < insn->n; i++) { + val = c6xdigio_encoder_read(dev, chan); + + /* munge two's complement value to offset binary */ + data[i] = comedi_offset_munge(s, val); + } + + return insn->n; +} + +static void c6xdigio_init(struct comedi_device *dev) +{ + /* Initialize the PWM */ + c6xdigio_write_data(dev, 0x70, 0x00); + c6xdigio_write_data(dev, 0x74, 0x80); + c6xdigio_write_data(dev, 0x70, 0x00); + c6xdigio_write_data(dev, 0x00, 0x80); + + /* Reset the encoders */ + c6xdigio_write_data(dev, 0x68, 0x00); + c6xdigio_write_data(dev, 0x6c, 0x80); + c6xdigio_write_data(dev, 0x68, 0x00); + c6xdigio_write_data(dev, 0x00, 0x80); } static const struct pnp_device_id c6xdigio_pnp_tbl[] = { @@ -367,7 +251,7 @@ static int c6xdigio_attach(struct comedi_device *dev, struct comedi_subdevice *s; int ret; - ret = comedi_request_region(dev, it->options[0], C6XDIGIO_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x03); if (ret) return ret; @@ -380,27 +264,26 @@ static int c6xdigio_attach(struct comedi_device *dev, s = &dev->subdevices[0]; /* pwm output subdevice */ - s->type = COMEDI_SUBD_AO; /* Not sure what to put here */ - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 2; - /* s->trig[0] = c6xdigio_pwmo; */ - s->insn_write = c6xdigio_pwmo_insn_write; - s->maxdata = 500; - s->range_table = &range_bipolar10; /* A suitable lie */ + s->type = COMEDI_SUBD_PWM; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = 500; + s->range_table = &range_unknown; + s->insn_write = c6xdigio_pwm_insn_write; + s->insn_read = c6xdigio_pwm_insn_read; s = &dev->subdevices[1]; /* encoder (counter) subdevice */ - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_LSAMPL; - s->n_chan = 2; - /* s->trig[0] = c6xdigio_ei; */ - s->insn_read = c6xdigio_ei_insn_read; - s->maxdata = 0xffffff; - s->range_table = &range_unknown; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE | SDF_LSAMPL; + s->n_chan = 2; + s->maxdata = 0xffffff; + s->range_table = &range_unknown; + s->insn_read = c6xdigio_encoder_insn_read; /* I will call this init anyway but more than likely the DSP board */ /* will not be connected when device driver is loaded. */ - board_init(dev); + c6xdigio_init(dev); return 0; } @@ -420,5 +303,5 @@ static struct comedi_driver c6xdigio_driver = { module_comedi_driver(c6xdigio_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for the C6x_DIGIO DSP daughter card"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index 64d5f291553f..645fcb0cf17d 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -95,10 +95,17 @@ static const struct comedi_lrange das16cs_ai_range = { } }; -static irqreturn_t das16cs_interrupt(int irq, void *d) +static int das16cs_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - /* struct comedi_device *dev = d; */ - return IRQ_HANDLED; + unsigned int status; + + status = inw(dev->iobase + DAS16CS_MISC1); + if (status & 0x0080) + return 0; + return -EBUSY; } static int das16cs_ai_rinsn(struct comedi_device *dev, @@ -109,8 +116,8 @@ static int das16cs_ai_rinsn(struct comedi_device *dev, int chan = CR_CHAN(insn->chanspec); int range = CR_RANGE(insn->chanspec); int aref = CR_AREF(insn->chanspec); + int ret; int i; - int to; outw(chan, dev->iobase + DAS16CS_DIO_MUX); @@ -138,132 +145,16 @@ static int das16cs_ai_rinsn(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outw(0, dev->iobase + DAS16CS_ADC_DATA); -#define TIMEOUT 1000 - for (to = 0; to < TIMEOUT; to++) { - if (inw(dev->iobase + DAS16CS_MISC1) & 0x0080) - break; - } - if (to == TIMEOUT) { - dev_dbg(dev->class_dev, "cb_das16_cs: ai timeout\n"); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, das16cs_ai_eoc, 0); + if (ret) + return ret; + data[i] = inw(dev->iobase + DAS16CS_ADC_DATA); } return i; } -static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) -{ - return -EINVAL; -} - -static int das16cs_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - int err = 0; - int tmp; - - /* Step 1 : check if triggers are trivially valid */ - - err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); - err |= cfc_check_trigger_src(&cmd->scan_begin_src, - TRIG_TIMER | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->convert_src, - TRIG_TIMER | TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - - if (err) - return 1; - - /* Step 2a : make sure trigger sources are unique */ - - err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); - err |= cfc_check_trigger_is_unique(cmd->convert_src); - err |= cfc_check_trigger_is_unique(cmd->stop_src); - - /* Step 2b : and mutually compatible */ - - if (err) - return 2; - - /* Step 3: check if arguments are trivially valid */ - - err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - -#define MAX_SPEED 10000 /* in nanoseconds */ -#define MIN_SPEED 1000000000 /* in nanoseconds */ - - if (cmd->scan_begin_src == TRIG_TIMER) { - err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, - MAX_SPEED); - err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, - MIN_SPEED); - } else { - /* external trigger */ - /* should be level/edge, hi/lo specification here */ - /* should specify multiple external triggers */ - err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); - } - if (cmd->convert_src == TRIG_TIMER) { - err |= cfc_check_trigger_arg_min(&cmd->convert_arg, - MAX_SPEED); - err |= cfc_check_trigger_arg_max(&cmd->convert_arg, - MIN_SPEED); - } else { - /* external trigger */ - /* see above */ - err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 9); - } - - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - - if (cmd->stop_src == TRIG_COUNT) - err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff); - else /* TRIG_NONE */ - err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - - if (err) - return 3; - - /* step 4: fix up any arguments */ - - if (cmd->scan_begin_src == TRIG_TIMER) { - unsigned int div1 = 0, div2 = 0; - - tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, - &div1, &div2, - &cmd->scan_begin_arg, cmd->flags); - if (tmp != cmd->scan_begin_arg) - err++; - } - if (cmd->convert_src == TRIG_TIMER) { - unsigned int div1 = 0, div2 = 0; - - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, - &div1, &div2, - &cmd->scan_begin_arg, cmd->flags); - if (tmp != cmd->convert_arg) - err++; - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; - } - } - - if (err) - return 4; - - return 0; -} - static int das16cs_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -401,10 +292,6 @@ static int das16cs_auto_attach(struct comedi_device *dev, dev->iobase = link->resource[0]->start; link->priv = dev; - ret = pcmcia_request_irq(link, das16cs_interrupt); - if (ret) - return ret; - dev->irq = link->irq; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) @@ -415,7 +302,6 @@ static int das16cs_auto_attach(struct comedi_device *dev, return ret; s = &dev->subdevices[0]; - dev->read_subdev = s; /* analog input subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; @@ -424,8 +310,6 @@ static int das16cs_auto_attach(struct comedi_device *dev, s->range_table = &das16cs_ai_range; s->len_chanlist = 16; s->insn_read = das16cs_ai_rinsn; - s->do_cmd = das16cs_ai_cmd; - s->do_cmdtest = das16cs_ai_cmdtest; s = &dev->subdevices[1]; /* analog output subdevice */ @@ -451,10 +335,6 @@ static int das16cs_auto_attach(struct comedi_device *dev, s->insn_bits = das16cs_dio_insn_bits; s->insn_config = das16cs_dio_insn_config; - dev_info(dev->class_dev, "%s: %s, I/O base=0x%04lx, irq=%u\n", - dev->driver->driver_name, dev->board_name, - dev->iobase, dev->irq); - return 0; } diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c index 9819be092f8d..83a265f3408c 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -376,6 +376,20 @@ static inline unsigned int cal_enable_bits(struct comedi_device *dev) return CAL_EN_BIT | CAL_SRC_BITS(devpriv->calibration_source); } +static int cb_pcidas_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct cb_pcidas_private *devpriv = dev->private; + unsigned int status; + + status = inw(devpriv->control_status + ADCMUX_CONT); + if (status & EOC) + return 0; + return -EBUSY; +} + static int cb_pcidas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -385,7 +399,8 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev, unsigned int range = CR_RANGE(insn->chanspec); unsigned int aref = CR_AREF(insn->chanspec); unsigned int bits; - int n, i; + int ret; + int n; /* enable calibration input if appropriate */ if (insn->chanspec & CR_ALT_SOURCE) { @@ -415,13 +430,9 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev, outw(0, devpriv->adc_fifo + ADCDATA); /* wait for conversion to end */ - /* return -ETIMEDOUT if there is a timeout */ - for (i = 0; i < 10000; i++) { - if (inw(devpriv->control_status + ADCMUX_CONT) & EOC) - break; - } - if (i == 10000) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, cb_pcidas_ai_eoc, 0); + if (ret) + return ret; /* read data */ data[n] = inw(devpriv->adc_fifo + ADCDATA); @@ -1006,9 +1017,9 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, /* set start trigger and burst mode */ bits = 0; - if (cmd->start_src == TRIG_NOW) + if (cmd->start_src == TRIG_NOW) { bits |= SW_TRIGGER; - else if (cmd->start_src == TRIG_EXT) { + } else { /* TRIG_EXT */ bits |= EXT_TRIGGER | TGEN | XTRCL; if (thisboard->is_1602) { if (cmd->start_arg & CR_INVERT) @@ -1016,9 +1027,6 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, if (cmd->start_arg & CR_EDGE) bits |= TGSEL; } - } else { - comedi_error(dev, "bug!"); - return -1; } if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) bits |= BURSTE; @@ -1269,8 +1277,6 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) unsigned int num_points; unsigned long flags; - async->events = 0; - if (status & DAEMI) { /* clear dac empty interrupt latch */ spin_lock_irqsave(&dev->spinlock, flags); @@ -1282,7 +1288,6 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) (cmd->stop_src == TRIG_COUNT && devpriv->ao_count)) { comedi_error(dev, "dac fifo underflow"); - cb_pcidas_ao_cancel(dev, s); async->events |= COMEDI_CB_ERROR; } async->events |= COMEDI_CB_EOA; @@ -1312,7 +1317,7 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) spin_unlock_irqrestore(&dev->spinlock, flags); } - comedi_event(dev, s); + cfc_handle_events(dev, s); } static irqreturn_t cb_pcidas_interrupt(int irq, void *d) @@ -1332,7 +1337,6 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) return IRQ_NONE; async = s->async; - async->events = 0; s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR); @@ -1364,10 +1368,8 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) cfc_write_array_to_buffer(s, devpriv->ai_buffer, num_samples * sizeof(short)); devpriv->count -= num_samples; - if (async->cmd.stop_src == TRIG_COUNT && devpriv->count == 0) { + if (async->cmd.stop_src == TRIG_COUNT && devpriv->count == 0) async->events |= COMEDI_CB_EOA; - cb_pcidas_cancel(dev, s); - } /* clear half-full interrupt latch */ spin_lock_irqsave(&dev->spinlock, flags); outw(devpriv->adc_fifo_bits | INT, @@ -1384,7 +1386,6 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) if (async->cmd.stop_src == TRIG_COUNT && --devpriv->count == 0) { /* end of acquisition */ - cb_pcidas_cancel(dev, s); async->events |= COMEDI_CB_EOA; break; } @@ -1411,11 +1412,10 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) outw(devpriv->adc_fifo_bits | LADFUL, devpriv->control_status + INT_ADCFIFO); spin_unlock_irqrestore(&dev->spinlock, flags); - cb_pcidas_cancel(dev, s); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -1576,9 +1576,6 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS, devpriv->s5933_config + AMCC_OP_REG_INTCSR); - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index 4fff1738e3f8..f9afcbe1da54 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1664,15 +1664,36 @@ static void i2c_write(struct comedi_device *dev, unsigned int address, i2c_stop(dev); } +static int cb_pcidas64_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->main_iobase + HW_STATUS_REG); + if (thisboard->layout == LAYOUT_4020) { + status = readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG); + if (status) + return 0; + } else { + if (pipe_full_bits(status)) + return 0; + } + return -EBUSY; +} + static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct pcidas64_board *thisboard = comedi_board(dev); struct pcidas64_private *devpriv = dev->private; - unsigned int bits = 0, n, i; + unsigned int bits = 0, n; unsigned int channel, range, aref; unsigned long flags; - static const int timeout = 100; + int ret; channel = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); @@ -1770,23 +1791,10 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, devpriv->main_iobase + ADC_CONVERT_REG); /* wait for data */ - for (i = 0; i < timeout; i++) { - bits = readw(devpriv->main_iobase + HW_STATUS_REG); - if (thisboard->layout == LAYOUT_4020) { - if (readw(devpriv->main_iobase + - ADC_WRITE_PNTR_REG)) - break; - } else { - if (pipe_full_bits(bits)) - break; - } - udelay(1); - } - if (i == timeout) { - comedi_error(dev, " analog input read insn timed out"); - dev_info(dev->class_dev, "status 0x%x\n", bits); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, cb_pcidas64_ai_eoc, 0); + if (ret) + return ret; + if (thisboard->layout == LAYOUT_4020) data[n] = readl(devpriv->dio_counter_iobase + ADC_FIFO_REG) & 0xffff; @@ -3816,16 +3824,19 @@ static int setup_subdevices(struct comedi_device *dev) if (thisboard->has_8255) { if (thisboard->layout == LAYOUT_4020) { dio_8255_iobase = devpriv->main_iobase + I8255_4020_REG; - subdev_8255_init(dev, s, dio_callback_4020, - (unsigned long)dio_8255_iobase); + ret = subdev_8255_init(dev, s, dio_callback_4020, + (unsigned long)dio_8255_iobase); } else { dio_8255_iobase = devpriv->dio_counter_iobase + DIO_8255_OFFSET; - subdev_8255_init(dev, s, dio_callback, - (unsigned long)dio_8255_iobase); + ret = subdev_8255_init(dev, s, dio_callback, + (unsigned long)dio_8255_iobase); } - } else + if (ret) + return ret; + } else { s->type = COMEDI_SUBD_UNUSED; + } /* 8 channel dio for 60xx */ s = &dev->subdevices[5]; diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c index 8cca0518cfda..901dc5d1bb72 100644 --- a/drivers/staging/comedi/drivers/cb_pcidda.c +++ b/drivers/staging/comedi/drivers/cb_pcidda.c @@ -388,8 +388,6 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev, for (i = 0; i < thisboard->ao_chans; i++) cb_pcidda_calibrate(dev, i, devpriv->ao_range[i]); - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c index 57295d189ff6..d3141c865fe7 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdas.c +++ b/drivers/staging/comedi/drivers/cb_pcimdas.c @@ -85,21 +85,31 @@ struct cb_pcimdas_private { unsigned int ao_readback[2]; }; -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ +static int cb_pcimdas_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct cb_pcimdas_private *devpriv = dev->private; + unsigned int status; + + status = inb(devpriv->BADR3 + 2); + if ((status & 0x80) == 0) + return 0; + return -EBUSY; +} + static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct cb_pcimdas_private *devpriv = dev->private; - int n, i; + int n; unsigned int d; - unsigned int busy; int chan = CR_CHAN(insn->chanspec); unsigned short chanlims; int maxchans; + int ret; /* only support sw initiated reads from a single channel */ @@ -133,17 +143,10 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, /* trigger conversion */ outw(0, dev->iobase + 0); -#define TIMEOUT 1000 /* typically takes 5 loops on a lightly loaded Pentium 100MHz, */ - /* this is likely to be 100 loops on a 2GHz machine, so set 1000 as the limit. */ - /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - busy = inb(devpriv->BADR3 + 2) & 0x80; - if (!busy) - break; - } - if (i == TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, cb_pcimdas_ai_eoc, 0); + if (ret) + return ret; /* read data */ data[n] = inw(dev->iobase + 0); @@ -247,9 +250,9 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev, s = &dev->subdevices[2]; /* digital i/o subdevice */ - subdev_8255_init(dev, s, NULL, iobase_8255); - - dev_info(dev->class_dev, "%s attached\n", dev->board_name); + ret = subdev_8255_init(dev, s, NULL, iobase_8255); + if (ret) + return ret; return 0; } diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c index 43a86630a66e..4a2b200de01b 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdda.c +++ b/drivers/staging/comedi/drivers/cb_pcimdda.c @@ -187,9 +187,7 @@ static int cb_pcimdda_auto_attach(struct comedi_device *dev, if (ret) return ret; - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - - return 1; + return 0; } static struct comedi_driver cb_pcimdda_driver = { diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c index 51a59e5b8ec5..8450c99af8b0 100644 --- a/drivers/staging/comedi/drivers/comedi_bond.c +++ b/drivers/staging/comedi/drivers/comedi_bond.c @@ -211,7 +211,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it) return -EINVAL; } - snprintf(file, sizeof(file), "/dev/comedi%u", minor); + snprintf(file, sizeof(file), "/dev/comedi%d", minor); file[sizeof(file) - 1] = 0; d = comedi_open(file); @@ -254,6 +254,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it) if (!devs) { dev_err(dev->class_dev, "Could not allocate memory. Out of memory?\n"); + kfree(bdev); return -ENOMEM; } devpriv->devs = devs; @@ -263,7 +264,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it) char buf[20]; int left = MAX_BOARD_NAME - strlen(devpriv->name) - 1; - snprintf(buf, sizeof(buf), "%d:%d ", + snprintf(buf, sizeof(buf), "%u:%u ", bdev->minor, bdev->subdev); buf[sizeof(buf) - 1] = 0; strncat(devpriv->name, buf, left); diff --git a/drivers/staging/comedi/drivers/comedi_fc.c b/drivers/staging/comedi/drivers/comedi_fc.c index 26d9dbcf8bd4..9d9b1469e89a 100644 --- a/drivers/staging/comedi/drivers/comedi_fc.c +++ b/drivers/staging/comedi/drivers/comedi_fc.c @@ -1,34 +1,53 @@ /* - comedi/drivers/comedi_fc.c - - This is a place for code driver writers wish to share between - two or more drivers. fc is short - for frank-common. - - Author: Frank Mori Hess - Copyright (C) 2002 Frank Mori Hess - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * comedi_fc.c + * This is a place for code driver writers wish to share between + * two or more drivers. fc is short for frank-common. + * + * Author: Frank Mori Hess + * Copyright (C) 2002 Frank Mori Hess + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ #include #include "../comedidev.h" #include "comedi_fc.h" -static void increment_scan_progress(struct comedi_subdevice *subd, - unsigned int num_bytes) +unsigned int cfc_bytes_per_scan(struct comedi_subdevice *s) { - struct comedi_async *async = subd->async; - unsigned int scan_length = cfc_bytes_per_scan(subd); + unsigned int chanlist_len = s->async->cmd.chanlist_len; + unsigned int num_samples; + unsigned int bits_per_sample; + + switch (s->type) { + case COMEDI_SUBD_DI: + case COMEDI_SUBD_DO: + case COMEDI_SUBD_DIO: + bits_per_sample = 8 * bytes_per_sample(s); + num_samples = (chanlist_len + bits_per_sample - 1) / + bits_per_sample; + break; + default: + num_samples = chanlist_len; + break; + } + return num_samples * bytes_per_sample(s); +} +EXPORT_SYMBOL_GPL(cfc_bytes_per_scan); + +void cfc_inc_scan_progress(struct comedi_subdevice *s, unsigned int num_bytes) +{ + struct comedi_async *async = s->async; + unsigned int scan_length = cfc_bytes_per_scan(s); async->scan_progress += num_bytes; if (async->scan_progress >= scan_length) { @@ -36,12 +55,13 @@ static void increment_scan_progress(struct comedi_subdevice *subd, async->events |= COMEDI_CB_EOS; } } +EXPORT_SYMBOL_GPL(cfc_inc_scan_progress); /* Writes an array of data points to comedi's buffer */ -unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd, +unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *s, void *data, unsigned int num_bytes) { - struct comedi_async *async = subd->async; + struct comedi_async *async = s->async; unsigned int retval; if (num_bytes == 0) @@ -49,24 +69,24 @@ unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd, retval = comedi_buf_write_alloc(async, num_bytes); if (retval != num_bytes) { - dev_warn(subd->device->class_dev, "comedi: buffer overrun\n"); + dev_warn(s->device->class_dev, "buffer overrun\n"); async->events |= COMEDI_CB_OVERFLOW; return 0; } comedi_buf_memcpy_to(async, 0, data, num_bytes); comedi_buf_write_free(async, num_bytes); - increment_scan_progress(subd, num_bytes); + cfc_inc_scan_progress(s, num_bytes); async->events |= COMEDI_CB_BLOCK; return num_bytes; } EXPORT_SYMBOL_GPL(cfc_write_array_to_buffer); -unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd, +unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *s, void *data, unsigned int num_bytes) { - struct comedi_async *async = subd->async; + struct comedi_async *async = s->async; if (num_bytes == 0) return 0; @@ -74,7 +94,7 @@ unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd, num_bytes = comedi_buf_read_alloc(async, num_bytes); comedi_buf_memcpy_from(async, 0, data, num_bytes); comedi_buf_read_free(async, num_bytes); - increment_scan_progress(subd, num_bytes); + cfc_inc_scan_progress(s, num_bytes); async->events |= COMEDI_CB_BLOCK; return num_bytes; @@ -82,34 +102,33 @@ unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd, EXPORT_SYMBOL_GPL(cfc_read_array_from_buffer); unsigned int cfc_handle_events(struct comedi_device *dev, - struct comedi_subdevice *subd) + struct comedi_subdevice *s) { - unsigned int events = subd->async->events; + unsigned int events = s->async->events; if (events == 0) return events; if (events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) - subd->cancel(dev, subd); + s->cancel(dev, s); - comedi_event(dev, subd); + comedi_event(dev, s); return events; } EXPORT_SYMBOL_GPL(cfc_handle_events); -MODULE_AUTHOR("Frank Mori Hess "); -MODULE_DESCRIPTION("Shared functions for Comedi low-level drivers"); -MODULE_LICENSE("GPL"); - static int __init comedi_fc_init_module(void) { return 0; } +module_init(comedi_fc_init_module); static void __exit comedi_fc_cleanup_module(void) { } - -module_init(comedi_fc_init_module); module_exit(comedi_fc_cleanup_module); + +MODULE_AUTHOR("Frank Mori Hess "); +MODULE_DESCRIPTION("Shared functions for Comedi low-level drivers"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/comedi_fc.h b/drivers/staging/comedi/drivers/comedi_fc.h index 8558b07f8df3..541b9371d3da 100644 --- a/drivers/staging/comedi/drivers/comedi_fc.h +++ b/drivers/staging/comedi/drivers/comedi_fc.h @@ -1,72 +1,52 @@ /* - comedi_fc.h - - This is a place for code driver writers wish to share between - two or more drivers. These functions are meant to be used only - by drivers, they are NOT part of the kcomedilib API! - - Author: Frank Mori Hess - Copyright (C) 2002 Frank Mori Hess - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * comedi_fc.h + * This is a place for code driver writers wish to share between + * two or more drivers. These functions are meant to be used only + * by drivers, they are NOT part of the kcomedilib API! + * + * Author: Frank Mori Hess + * Copyright (C) 2002 Frank Mori Hess + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ #ifndef _COMEDI_FC_H #define _COMEDI_FC_H #include "../comedidev.h" -/* Writes an array of data points to comedi's buffer */ -extern unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd, - void *data, - unsigned int num_bytes); +unsigned int cfc_bytes_per_scan(struct comedi_subdevice *); +void cfc_inc_scan_progress(struct comedi_subdevice *, unsigned int num_bytes); -static inline unsigned int cfc_write_to_buffer(struct comedi_subdevice *subd, +/* Writes an array of data points to comedi's buffer */ +unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *, + void *data, unsigned int num_bytes); + +static inline unsigned int cfc_write_to_buffer(struct comedi_subdevice *s, unsigned short data) { - return cfc_write_array_to_buffer(subd, &data, sizeof(data)); + return cfc_write_array_to_buffer(s, &data, sizeof(data)); }; -static inline unsigned int cfc_write_long_to_buffer(struct comedi_subdevice - *subd, unsigned int data) +static inline unsigned int cfc_write_long_to_buffer(struct comedi_subdevice *s, + unsigned int data) { - return cfc_write_array_to_buffer(subd, &data, sizeof(data)); + return cfc_write_array_to_buffer(s, &data, sizeof(data)); }; -extern unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd, - void *data, - unsigned int num_bytes); +unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *, + void *data, unsigned int num_bytes); -extern unsigned int cfc_handle_events(struct comedi_device *dev, - struct comedi_subdevice *subd); - -static inline unsigned int cfc_bytes_per_scan(struct comedi_subdevice *subd) -{ - int num_samples; - int bits_per_sample; - - switch (subd->type) { - case COMEDI_SUBD_DI: - case COMEDI_SUBD_DO: - case COMEDI_SUBD_DIO: - bits_per_sample = 8 * bytes_per_sample(subd); - num_samples = (subd->async->cmd.chanlist_len + - bits_per_sample - 1) / bits_per_sample; - break; - default: - num_samples = subd->async->cmd.chanlist_len; - break; - } - return num_samples * bytes_per_sample(subd); -} +unsigned int cfc_handle_events(struct comedi_device *, + struct comedi_subdevice *); /** * cfc_check_trigger_src() - trivially validate a comedi_cmd trigger source diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index d539eaf53b63..cd9562556d2c 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -185,7 +185,6 @@ static void waveform_ai_interrupt(unsigned long arg) (devpriv->usec_remainder + elapsed_time) / devpriv->scan_period; devpriv->usec_remainder = (devpriv->usec_remainder + elapsed_time) % devpriv->scan_period; - async->events = 0; if (cmd->stop_src == TRIG_COUNT) { unsigned int remaining = cmd->stop_arg - devpriv->ai_count; @@ -318,12 +317,8 @@ static int waveform_ai_cmd(struct comedi_device *dev, if (cmd->convert_src == TRIG_NOW) devpriv->convert_period = 0; - else if (cmd->convert_src == TRIG_TIMER) + else /* TRIG_TIMER */ devpriv->convert_period = cmd->convert_arg / nano_per_micro; - else { - comedi_error(dev, "bug setting conversion period"); - return -1; - } do_gettimeofday(&devpriv->last); devpriv->usec_current = devpriv->last.tv_usec % devpriv->usec_period; diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c index 323a7f39cd97..0a9c32e9db4a 100644 --- a/drivers/staging/comedi/drivers/contec_pci_dio.c +++ b/drivers/staging/comedi/drivers/contec_pci_dio.c @@ -92,8 +92,6 @@ static int contec_auto_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = contec_do_insn_bits; - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/dac02.c b/drivers/staging/comedi/drivers/dac02.c new file mode 100644 index 000000000000..df46e0a5bade --- /dev/null +++ b/drivers/staging/comedi/drivers/dac02.c @@ -0,0 +1,172 @@ +/* + * dac02.c + * Comedi driver for DAC02 compatible boards + * Copyright (C) 2014 H Hartley Sweeten + * + * Based on the poc driver + * Copyright (C) 2000 Frank Mori Hess + * Copyright (C) 2001 David A. Schleef + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Driver: dac02 + * Description: Comedi driver for DAC02 compatible boards + * Devices: (Keithley Metrabyte) DAC-02 [dac02] + * Author: H Hartley Sweeten + * Updated: Tue, 11 Mar 2014 11:27:19 -0700 + * Status: unknown + * + * Configuration options: + * [0] - I/O port base + */ + +#include + +#include "../comedidev.h" + +/* + * The output range is selected by jumpering pins on the I/O connector. + * + * Range Chan # Jumper pins Output + * ------------- ------ ------------- ----------------- + * 0 to 5V 0 21 to 22 24 + * 1 15 to 16 18 + * 0 to 10V 0 20 to 22 24 + * 1 14 to 16 18 + * +/-5V 0 21 to 22 23 + * 1 15 to 16 17 + * +/-10V 0 20 to 22 23 + * 1 14 to 16 17 + * 4 to 20mA 0 21 to 22 25 + * 1 15 to 16 19 + * AC reference 0 In on pin 22 24 (2-quadrant) + * In on pin 22 23 (4-quadrant) + * 1 In on pin 16 18 (2-quadrant) + * In on pin 16 17 (4-quadrant) + */ +static const struct comedi_lrange das02_ao_ranges = { + 6, { + UNI_RANGE(5), + UNI_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(10), + RANGE_mA(4, 20), + RANGE_ext(0, 1) + } +}; + +struct dac02_private { + unsigned int ao_readback[2]; +}; + +/* + * Register I/O map + */ +#define DAC02_AO_LSB(x) (0x00 + ((x) * 2)) +#define DAC02_AO_MSB(x) (0x01 + ((x) * 2)) + +static int dac02_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct dac02_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + int i; + + for (i = 0; i < insn->n; i++) { + val = data[i]; + + devpriv->ao_readback[chan] = val; + + /* + * Unipolar outputs are true binary encoding. + * Bipolar outputs are complementary offset binary + * (that is, 0 = +full scale, maxdata = -full scale). + */ + if (comedi_range_is_bipolar(s, range)) + val = s->maxdata - val; + + /* + * DACs are double-buffered. + * Write LSB then MSB to latch output. + */ + outb((val << 4) & 0xf0, dev->iobase + DAC02_AO_LSB(chan)); + outb((val >> 4) & 0xff, dev->iobase + DAC02_AO_MSB(chan)); + } + + return insn->n; +} + +static int dac02_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct dac02_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return insn->n; +} + +static int dac02_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + struct dac02_private *devpriv; + struct comedi_subdevice *s; + int ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_request_region(dev, it->options[0], 0x08); + if (ret) + return ret; + + ret = comedi_alloc_subdevices(dev, 1); + if (ret) + return ret; + + /* Analog Output subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = &das02_ao_ranges; + s->insn_write = dac02_ao_insn_write; + s->insn_read = dac02_ao_insn_read; + + return 0; +} + +static struct comedi_driver dac02_driver = { + .driver_name = "dac02", + .module = THIS_MODULE, + .attach = dac02_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(dac02_driver); + +MODULE_AUTHOR("H Hartley Sweeten "); +MODULE_DESCRIPTION("Comedi driver for DAC02 compatible boards"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index ce153fcb8b2a..a8f6036ad82b 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -333,14 +333,28 @@ static void setup_sampling(struct comedi_device *dev, int chan, int gain) writeAcqScanListEntry(dev, word3); } +static int daqboard2000_ai_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct daqboard2000_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->daq + acqControl); + if (status & context) + return 0; + return -EBUSY; +} + static int daqboard2000_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct daqboard2000_private *devpriv = dev->private; - unsigned int val; - int gain, chan, timeout; + int gain, chan; + int ret; int i; writew(DAQBOARD2000_AcqResetScanListFifo | @@ -367,25 +381,24 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, /* Enable reading from the scanlist FIFO */ writew(DAQBOARD2000_SeqStartScanList, devpriv->daq + acqControl); - for (timeout = 0; timeout < 20; timeout++) { - val = readw(devpriv->daq + acqControl); - if (val & DAQBOARD2000_AcqConfigPipeFull) - break; - /* udelay(2); */ - } + + ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, + DAQBOARD2000_AcqConfigPipeFull); + if (ret) + return ret; + writew(DAQBOARD2000_AdcPacerEnable, devpriv->daq + acqControl); - for (timeout = 0; timeout < 20; timeout++) { - val = readw(devpriv->daq + acqControl); - if (val & DAQBOARD2000_AcqLogicScanning) - break; - /* udelay(2); */ - } - for (timeout = 0; timeout < 20; timeout++) { - val = readw(devpriv->daq + acqControl); - if (val & DAQBOARD2000_AcqResultsFIFOHasValidData) - break; - /* udelay(2); */ - } + + ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, + DAQBOARD2000_AcqLogicScanning); + if (ret) + return ret; + + ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, + DAQBOARD2000_AcqResultsFIFOHasValidData); + if (ret) + return ret; + data[i] = readw(devpriv->daq + acqResultsFIFO); writew(DAQBOARD2000_AdcPacerDisable, devpriv->daq + acqControl); writew(DAQBOARD2000_SeqStopScanList, devpriv->daq + acqControl); @@ -409,6 +422,21 @@ static int daqboard2000_ao_insn_read(struct comedi_device *dev, return i; } +static int daqboard2000_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct daqboard2000_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int status; + + status = readw(devpriv->daq + dacControl); + if ((status & ((chan + 1) * 0x0010)) == 0) + return 0; + return -EBUSY; +} + static int daqboard2000_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -416,8 +444,7 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev, { struct daqboard2000_private *devpriv = dev->private; int chan = CR_CHAN(insn->chanspec); - unsigned int val; - int timeout; + int ret; int i; for (i = 0; i < insn->n; i++) { @@ -431,12 +458,11 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev, udelay(1000); #endif writew(data[i], devpriv->daq + dacSetting(chan)); - for (timeout = 0; timeout < 20; timeout++) { - val = readw(devpriv->daq + dacControl); - if ((val & ((chan + 1) * 0x0010)) == 0) - break; - /* udelay(2); */ - } + + ret = comedi_timeout(dev, s, insn, daqboard2000_ao_eoc, 0); + if (ret) + return ret; + devpriv->ao_readback[chan] = data[i]; #if 0 /* @@ -737,9 +763,6 @@ static int daqboard2000_auto_attach(struct comedi_device *dev, if (result) return result; - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index e5c0ee9a09c2..c5e352fb5555 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c @@ -201,17 +201,29 @@ static const int *const das08_gainlists[] = { das08_pgm_gainlist, }; -#define TIMEOUT 100000 +static int das08_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DAS08_STATUS); + if ((status & DAS08_EOC) == 0) + return 0; + return -EBUSY; +} static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct das08_board_struct *thisboard = comedi_board(dev); struct das08_private_struct *devpriv = dev->private; - int i, n; + int n; int chan; int range; int lsb, msb; + int ret; chan = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); @@ -244,14 +256,10 @@ static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* trigger conversion */ outb_p(0, dev->iobase + DAS08_TRIG_12BIT); - for (i = 0; i < TIMEOUT; i++) { - if (!(inb(dev->iobase + DAS08_STATUS) & DAS08_EOC)) - break; - } - if (i == TIMEOUT) { - dev_err(dev->class_dev, "timeout\n"); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, das08_ai_eoc, 0); + if (ret) + return ret; + msb = inb(dev->iobase + DAS08_MSB); lsb = inb(dev->iobase + DAS08_LSB); if (thisboard->ai_encoding == das08_encode12) { @@ -529,9 +537,10 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) s = &dev->subdevices[4]; /* 8255 */ if (thisboard->i8255_offset != 0) { - subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase + - thisboard-> - i8255_offset)); + ret = subdev_8255_init(dev, s, NULL, + dev->iobase + thisboard->i8255_offset); + if (ret) + return ret; } else { s->type = COMEDI_SUBD_UNUSED; } diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index a8446ca04110..6a7d652ff564 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -856,18 +856,17 @@ static void das16_ai_munge(struct comedi_device *dev, } } -static int das16_ai_wait_for_conv(struct comedi_device *dev, - unsigned int timeout) +static int das16_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned int status; - int i; - for (i = 0; i < timeout; i++) { - status = inb(dev->iobase + DAS16_STATUS_REG); - if (!(status & DAS16_STATUS_BUSY)) - return 0; - } - return -ETIME; + status = inb(dev->iobase + DAS16_STATUS_REG); + if ((status & DAS16_STATUS_BUSY) == 0) + return 0; + return -EBUSY; } static int das16_ai_insn_read(struct comedi_device *dev, @@ -897,7 +896,7 @@ static int das16_ai_insn_read(struct comedi_device *dev, /* trigger conversion */ outb_p(0, dev->iobase + DAS16_TRIG_REG); - ret = das16_ai_wait_for_conv(dev, 1000); + ret = comedi_timeout(dev, s, insn, das16_ai_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index fee5facff8dd..779225831dc0 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -331,14 +331,27 @@ static int das16m1_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } +static int das16m1_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DAS16M1_CS); + if (status & IRQDATA) + return 0; + return -EBUSY; +} + static int das16m1_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct das16m1_private_struct *devpriv = dev->private; - int i, n; + int ret; + int n; int byte; - const int timeout = 1000; /* disable interrupts and internal pacer */ devpriv->control_state &= ~INTE & ~PACER_MASK; @@ -356,14 +369,10 @@ static int das16m1_ai_rinsn(struct comedi_device *dev, /* trigger conversion */ outb(0, dev->iobase); - for (i = 0; i < timeout; i++) { - if (inb(dev->iobase + DAS16M1_CS) & IRQDATA) - break; - } - if (i == timeout) { - comedi_error(dev, "timeout"); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, das16m1_ai_eoc, 0); + if (ret) + return ret; + data[n] = munge_sample(inw(dev->iobase)); } @@ -407,7 +416,6 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) s = dev->read_subdev; async = s->async; - async->events = 0; cmd = &async->cmd; /* figure out how many samples are in fifo */ @@ -440,8 +448,8 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) devpriv->adc_count += num_samples; if (cmd->stop_src == TRIG_COUNT) { - if (devpriv->adc_count >= cmd->stop_arg * cmd->chanlist_len) { /* end of acquisition */ - das16m1_cancel(dev, s); + if (devpriv->adc_count >= cmd->stop_arg * cmd->chanlist_len) { + /* end of acquisition */ async->events |= COMEDI_CB_EOA; } } @@ -449,13 +457,11 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) /* this probably won't catch overruns since the card doesn't generate * overrun interrupts, but we might as well try */ if (status & OVRUN) { - das16m1_cancel(dev, s); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; comedi_error(dev, "fifo overflow"); } - comedi_event(dev, s); - + cfc_handle_events(dev, s); } static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s) diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c index 320d95a5f47b..8e975d6b06db 100644 --- a/drivers/staging/comedi/drivers/das1800.c +++ b/drivers/staging/comedi/drivers/das1800.c @@ -646,7 +646,6 @@ static void das1800_ai_handler(struct comedi_device *dev) struct comedi_cmd *cmd = &async->cmd; unsigned int status = inb(dev->iobase + DAS1800_STATUS); - async->events = 0; /* select adc for base address + 0 */ outb(ADC, dev->iobase + DAS1800_SELECT); /* dma buffer full */ @@ -665,9 +664,8 @@ static void das1800_ai_handler(struct comedi_device *dev) /* clear OVF interrupt bit */ outb(CLEAR_INTR_MASK & ~OVF, dev->iobase + DAS1800_STATUS); comedi_error(dev, "DAS1800 FIFO overflow"); - das1800_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } /* stop taking data if appropriate */ @@ -680,16 +678,12 @@ static void das1800_ai_handler(struct comedi_device *dev) das1800_flush_dma(dev, s); else das1800_handle_fifo_not_empty(dev, s); - das1800_cancel(dev, s); /* disable hardware conversions */ async->events |= COMEDI_CB_EOA; } else if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) { /* stop_src TRIG_COUNT */ - das1800_cancel(dev, s); /* disable hardware conversions */ async->events |= COMEDI_CB_EOA; } - comedi_event(dev, s); - - return; + cfc_handle_events(dev, s); } static int das1800_ai_poll(struct comedi_device *dev, diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c index 43027ee500e3..e0cfb6cb547b 100644 --- a/drivers/staging/comedi/drivers/das6402.c +++ b/drivers/staging/comedi/drivers/das6402.c @@ -1,309 +1,532 @@ /* - Some comments on the code.. - - - it shouldn't be necessary to use outb_p(). - - - ignoreirq creates a race condition. It needs to be fixed. - + * das6402.c + * Comedi driver for DAS6402 compatible boards + * Copyright(c) 2014 H Hartley Sweeten + * + * Rewrite of an experimental driver by: + * Copyright (C) 1999 Oystein Svendsen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ /* - comedi/drivers/das6402.c - An experimental driver for Computerboards' DAS6402 I/O card - - Copyright (C) 1999 Oystein Svendsen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * Driver: das6402 + * Description: Keithley Metrabyte DAS6402 (& compatibles) + * Devices: (Keithley Metrabyte) DAS6402-12 (das6402-12) + * (Keithley Metrabyte) DAS6402-16 (das6402-16) + * Author: H Hartley Sweeten + * Updated: Fri, 14 Mar 2014 10:18:43 -0700 + * Status: unknown + * + * Configuration Options: + * [0] - I/O base address + * [1] - IRQ (optional, needed for async command support) */ -/* -Driver: das6402 -Description: Keithley Metrabyte DAS6402 (& compatibles) -Author: Oystein Svendsen -Status: bitrotten -Devices: [Keithley Metrabyte] DAS6402 (das6402) - -This driver has suffered bitrot. -*/ #include #include + #include "../comedidev.h" +#include "8253.h" -#define DAS6402_SIZE 16 +/* + * Register I/O map + */ +#define DAS6402_AI_DATA_REG 0x00 +#define DAS6402_AI_MUX_REG 0x02 +#define DAS6402_AI_MUX_LO(x) (((x) & 0x3f) << 0) +#define DAS6402_AI_MUX_HI(x) (((x) & 0x3f) << 8) +#define DAS6402_DI_DO_REG 0x03 +#define DAS6402_AO_DATA_REG(x) (0x04 + ((x) * 2)) +#define DAS6402_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define DAS6402_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define DAS6402_STATUS_REG 0x08 +#define DAS6402_STATUS_FFNE (1 << 0) +#define DAS6402_STATUS_FHALF (1 << 1) +#define DAS6402_STATUS_FFULL (1 << 2) +#define DAS6402_STATUS_XINT (1 << 3) +#define DAS6402_STATUS_INT (1 << 4) +#define DAS6402_STATUS_XTRIG (1 << 5) +#define DAS6402_STATUS_INDGT (1 << 6) +#define DAS6402_STATUS_10MHZ (1 << 7) +#define DAS6402_STATUS_W_CLRINT (1 << 0) +#define DAS6402_STATUS_W_CLRXTR (1 << 1) +#define DAS6402_STATUS_W_CLRXIN (1 << 2) +#define DAS6402_STATUS_W_EXTEND (1 << 4) +#define DAS6402_STATUS_W_ARMED (1 << 5) +#define DAS6402_STATUS_W_POSTMODE (1 << 6) +#define DAS6402_STATUS_W_10MHZ (1 << 7) +#define DAS6402_CTRL_REG 0x09 +#define DAS6402_CTRL_SOFT_TRIG (0 << 0) +#define DAS6402_CTRL_EXT_FALL_TRIG (1 << 0) +#define DAS6402_CTRL_EXT_RISE_TRIG (2 << 0) +#define DAS6402_CTRL_PACER_TRIG (3 << 0) +#define DAS6402_CTRL_BURSTEN (1 << 2) +#define DAS6402_CTRL_XINTE (1 << 3) +#define DAS6402_CTRL_IRQ(x) ((x) << 4) +#define DAS6402_CTRL_INTE (1 << 7) +#define DAS6402_TRIG_REG 0x0a +#define DAS6402_TRIG_TGEN (1 << 0) +#define DAS6402_TRIG_TGSEL (1 << 1) +#define DAS6402_TRIG_TGPOL (1 << 2) +#define DAS6402_TRIG_PRETRIG (1 << 3) +#define DAS6402_AO_RANGE(_chan, _range) ((_range) << ((_chan) ? 6 : 4)) +#define DAS6402_AO_RANGE_MASK(_chan) (3 << ((_chan) ? 6 : 4)) +#define DAS6402_MODE_REG 0x0b +#define DAS6402_MODE_RANGE(x) ((x) << 0) +#define DAS6402_MODE_POLLED (0 << 2) +#define DAS6402_MODE_FIFONEPTY (1 << 2) +#define DAS6402_MODE_FIFOHFULL (2 << 2) +#define DAS6402_MODE_EOB (3 << 2) +#define DAS6402_MODE_ENHANCED (1 << 4) +#define DAS6402_MODE_SE (1 << 5) +#define DAS6402_MODE_UNI (1 << 6) +#define DAS6402_MODE_DMA1 (0 << 7) +#define DAS6402_MODE_DMA3 (1 << 7) +#define DAS6402_TIMER_BASE 0x0c -#define N_WORDS (3000*64) - -#define STOP 0 -#define START 1 - -#define SCANL 0x3f00 -#define BYTE unsigned char -#define WORD unsigned short - -/*----- register 8 ----*/ -#define CLRINT 0x01 -#define CLRXTR 0x02 -#define CLRXIN 0x04 -#define EXTEND 0x10 -#define ARMED 0x20 /* enable conting of post sample conv */ -#define POSTMODE 0x40 -#define MHZ 0x80 /* 10 MHz clock */ -/*---------------------*/ - -/*----- register 9 ----*/ -#define IRQ (0x04 << 4) /* these two are */ -#define IRQV 10 /* dependent on each other */ - -#define CONVSRC 0x03 /* trig src is Intarnal pacer */ -#define BURSTEN 0x04 /* enable burst */ -#define XINTE 0x08 /* use external int. trig */ -#define INTE 0x80 /* enable analog interrupts */ -/*---------------------*/ - -/*----- register 10 ---*/ -#define TGEN 0x01 /* Use pin DI1 for externl trigging? */ -#define TGSEL 0x02 /* Use edge triggering */ -#define TGPOL 0x04 /* active edge is falling */ -#define PRETRIG 0x08 /* pretrig */ -/*---------------------*/ - -/*----- register 11 ---*/ -#define EOB 0x0c -#define FIFOHFULL 0x08 -#define GAIN 0x01 -#define FIFONEPTY 0x04 -#define MODE 0x10 -#define SEM 0x20 -#define BIP 0x40 -/*---------------------*/ - -#define M0 0x00 -#define M2 0x04 - -#define C0 0x00 -#define C1 0x40 -#define C2 0x80 -#define RWLH 0x30 - -struct das6402_private { - int ai_bytes_to_read; - - int das6402_ignoreirq; +static const struct comedi_lrange das6402_ai_ranges = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; -static void das6402_ai_fifo_dregs(struct comedi_device *dev, - struct comedi_subdevice *s) +/* + * Analog output ranges are programmable on the DAS6402/12. + * For the DAS6402/16 the range bits have no function, the + * DAC ranges are selected by switches on the board. + */ +static const struct comedi_lrange das6402_ao_ranges = { + 4, { + BIP_RANGE(5), + BIP_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(10) + } +}; + +struct das6402_boardinfo { + const char *name; + unsigned int maxdata; +}; + +struct das6402_boardinfo das6402_boards[] = { + { + .name = "das6402-12", + .maxdata = 0x0fff, + }, { + .name = "das6402-16", + .maxdata = 0xffff, + }, +}; + +struct das6402_private { + unsigned int irq; + + unsigned int count; + unsigned int divider1; + unsigned int divider2; + + unsigned int ao_range; + unsigned int ao_readback[2]; +}; + +static void das6402_set_mode(struct comedi_device *dev, + unsigned int mode) { - while (1) { - if (!(inb(dev->iobase + 8) & 0x01)) - return; - comedi_buf_put(s->async, inw(dev->iobase)); + outb(DAS6402_MODE_ENHANCED | mode, dev->iobase + DAS6402_MODE_REG); +} + +static void das6402_set_extended(struct comedi_device *dev, + unsigned int val) +{ + outb(DAS6402_STATUS_W_EXTEND, dev->iobase + DAS6402_STATUS_REG); + outb(DAS6402_STATUS_W_EXTEND | val, dev->iobase + DAS6402_STATUS_REG); + outb(val, dev->iobase + DAS6402_STATUS_REG); +} + +static void das6402_clear_all_interrupts(struct comedi_device *dev) +{ + outb(DAS6402_STATUS_W_CLRINT | + DAS6402_STATUS_W_CLRXTR | + DAS6402_STATUS_W_CLRXIN, dev->iobase + DAS6402_STATUS_REG); +} + +static void das6402_ai_clear_eoc(struct comedi_device *dev) +{ + outb(DAS6402_STATUS_W_CLRINT, dev->iobase + DAS6402_STATUS_REG); +} + +static void das6402_enable_counter(struct comedi_device *dev, bool load) +{ + struct das6402_private *devpriv = dev->private; + unsigned long timer_iobase = dev->iobase + DAS6402_TIMER_BASE; + + if (load) { + i8254_set_mode(timer_iobase, 0, 0, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 2, I8254_MODE2 | I8254_BINARY); + + i8254_write(timer_iobase, 0, 0, devpriv->count); + i8254_write(timer_iobase, 0, 1, devpriv->divider1); + i8254_write(timer_iobase, 0, 2, devpriv->divider2); + + } else { + i8254_set_mode(timer_iobase, 0, 0, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 1, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 2, I8254_MODE0 | I8254_BINARY); } } -static void das6402_setcounter(struct comedi_device *dev) -{ - BYTE p; - unsigned short ctrlwrd; - - /* set up counter0 first, mode 0 */ - p = M0 | C0 | RWLH; - outb_p(p, dev->iobase + 15); - ctrlwrd = 2000; - p = (BYTE) (0xff & ctrlwrd); - outb_p(p, dev->iobase + 12); - p = (BYTE) (0xff & (ctrlwrd >> 8)); - outb_p(p, dev->iobase + 12); - - /* set up counter1, mode 2 */ - p = M2 | C1 | RWLH; - outb_p(p, dev->iobase + 15); - ctrlwrd = 10; - p = (BYTE) (0xff & ctrlwrd); - outb_p(p, dev->iobase + 13); - p = (BYTE) (0xff & (ctrlwrd >> 8)); - outb_p(p, dev->iobase + 13); - - /* set up counter1, mode 2 */ - p = M2 | C2 | RWLH; - outb_p(p, dev->iobase + 15); - ctrlwrd = 1000; - p = (BYTE) (0xff & ctrlwrd); - outb_p(p, dev->iobase + 14); - p = (BYTE) (0xff & (ctrlwrd >> 8)); - outb_p(p, dev->iobase + 14); -} - -static irqreturn_t intr_handler(int irq, void *d) +static irqreturn_t das6402_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct das6402_private *devpriv = dev->private; - struct comedi_subdevice *s = &dev->subdevices[0]; - if (!dev->attached || devpriv->das6402_ignoreirq) { - dev_warn(dev->class_dev, "BUG: spurious interrupt\n"); - return IRQ_HANDLED; - } + das6402_clear_all_interrupts(dev); - das6402_ai_fifo_dregs(dev, s); - - if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) { - outw_p(SCANL, dev->iobase + 2); /* clears the fifo */ - outb(0x07, dev->iobase + 8); /* clears all flip-flops */ - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - } - - outb(0x01, dev->iobase + 8); /* clear only the interrupt flip-flop */ - - comedi_event(dev, s); return IRQ_HANDLED; } -#if 0 -static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n) +static int das6402_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { - int i; - - for (i = 0; i < n; i++) - data[i] = inw(dev->iobase); + return -EINVAL; +} + +static int das6402_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + return -EINVAL; } -#endif static int das6402_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) +{ + outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG); + + return 0; +} + +static void das6402_ai_soft_trig(struct comedi_device *dev) +{ + outw(0, dev->iobase + DAS6402_AI_DATA_REG); +} + +static int das6402_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DAS6402_STATUS_REG); + if (status & DAS6402_STATUS_FFNE) + return 0; + return -EBUSY; +} + +static int das6402_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int aref = CR_AREF(insn->chanspec); + unsigned int val; + int ret; + int i; + + val = DAS6402_MODE_RANGE(range) | DAS6402_MODE_POLLED; + if (aref == AREF_DIFF) { + if (chan > s->n_chan / 2) + return -EINVAL; + } else { + val |= DAS6402_MODE_SE; + } + if (comedi_range_is_unipolar(s, range)) + val |= DAS6402_MODE_UNI; + + /* enable software conversion trigger */ + outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG); + + das6402_set_mode(dev, val); + + /* load the mux for single channel conversion */ + outw(DAS6402_AI_MUX_HI(chan) | DAS6402_AI_MUX_LO(chan), + dev->iobase + DAS6402_AI_MUX_REG); + + for (i = 0; i < insn->n; i++) { + das6402_ai_clear_eoc(dev); + das6402_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, das6402_ai_eoc, 0); + if (ret) + break; + + val = inw(dev->iobase + DAS6402_AI_DATA_REG); + + if (s->maxdata == 0x0fff) + val >>= 4; + + data[i] = val; + } + + das6402_ai_clear_eoc(dev); + + return insn->n; +} + +static int das6402_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct das6402_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + int i; + + /* set the range for this channel */ + val = devpriv->ao_range; + val &= ~DAS6402_AO_RANGE_MASK(chan); + val |= DAS6402_AO_RANGE(chan, range); + if (val != devpriv->ao_range) { + devpriv->ao_range = val; + outb(val, dev->iobase + DAS6402_TRIG_REG); + } /* - * This function should reset the board from whatever condition it - * is in (i.e., acquiring data), to a non-active state. + * The DAS6402/16 has a jumper to select either individual + * update (UPDATE) or simultaneous updating (XFER) of both + * DAC's. In UPDATE mode, when the MSB is written, that DAC + * is updated. In XFER mode, after both DAC's are loaded, + * a read cycle of any DAC register will update both DAC's + * simultaneously. + * + * If you have XFER mode enabled a (*insn_read) will need + * to be performed in order to update the DAC's with the + * last value written. */ + for (i = 0; i < insn->n; i++) { + val = data[i]; - devpriv->das6402_ignoreirq = 1; - dev_dbg(dev->class_dev, "Stopping acquisition\n"); - devpriv->das6402_ignoreirq = 1; - outb_p(0x02, dev->iobase + 10); /* disable external trigging */ - outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */ - outb_p(0, dev->iobase + 9); /* disables interrupts */ + devpriv->ao_readback[chan] = val; - outw_p(SCANL, dev->iobase + 2); + if (s->maxdata == 0x0fff) { + /* + * DAS6402/12 has the two 8-bit DAC registers, left + * justified (the 4 LSB bits are don't care). Data + * can be written as one word. + */ + val <<= 4; + outw(val, dev->iobase + DAS6402_AO_DATA_REG(chan)); + } else { + /* + * DAS6402/16 uses both 8-bit DAC registers and needs + * to be written LSB then MSB. + */ + outb(val & 0xff, + dev->iobase + DAS6402_AO_LSB_REG(chan)); + outb((val >> 8) & 0xff, + dev->iobase + DAS6402_AO_LSB_REG(chan)); + } + } - return 0; + return insn->n; } -#ifdef unused -static int das6402_ai_mode2(struct comedi_device *dev, - struct comedi_subdevice *s, comedi_trig *it) +static int das6402_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct das6402_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + /* + * If XFER mode is enabled, reading any DAC register + * will update both DAC's simultaneously. + */ + inw(dev->iobase + DAS6402_AO_LSB_REG(chan)); + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return insn->n; +} + +static int das6402_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + DAS6402_DI_DO_REG); + + return insn->n; +} + +static int das6402_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAS6402_DI_DO_REG); + + data[1] = s->state; + + return insn->n; +} + +static void das6402_reset(struct comedi_device *dev) { struct das6402_private *devpriv = dev->private; - devpriv->das6402_ignoreirq = 1; - dev_dbg(dev->class_dev, "Starting acquisition\n"); - outb_p(0x03, dev->iobase + 10); /* enable external trigging */ - outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */ - outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9); + /* enable "Enhanced" mode */ + outb(DAS6402_MODE_ENHANCED, dev->iobase + DAS6402_MODE_REG); - devpriv->ai_bytes_to_read = it->n * sizeof(short); + /* enable 10MHz pacer clock */ + das6402_set_extended(dev, DAS6402_STATUS_W_10MHZ); - /* um... ignoreirq is a nasty race condition */ - devpriv->das6402_ignoreirq = 0; + /* enable software conversion trigger */ + outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG); - outw_p(SCANL, dev->iobase + 2); + /* default ADC to single-ended unipolar 10V inputs */ + das6402_set_mode(dev, DAS6402_MODE_RANGE(0) | + DAS6402_MODE_POLLED | + DAS6402_MODE_SE | + DAS6402_MODE_UNI); - return 0; -} -#endif + /* default mux for single channel conversion (channel 0) */ + outw(DAS6402_AI_MUX_HI(0) | DAS6402_AI_MUX_LO(0), + dev->iobase + DAS6402_AI_MUX_REG); -static int board_init(struct comedi_device *dev) -{ - struct das6402_private *devpriv = dev->private; - BYTE b; + /* set both DAC's for unipolar 5V output range */ + devpriv->ao_range = DAS6402_AO_RANGE(0, 2) | DAS6402_AO_RANGE(1, 2); + outb(devpriv->ao_range, dev->iobase + DAS6402_TRIG_REG); - devpriv->das6402_ignoreirq = 1; + /* set both DAC's to 0V */ + outw(0, dev->iobase + DAS6402_AO_DATA_REG(0)); + outw(0, dev->iobase + DAS6402_AO_DATA_REG(0)); + inw(dev->iobase + DAS6402_AO_LSB_REG(0)); - outb(0x07, dev->iobase + 8); + das6402_enable_counter(dev, false); - /* register 11 */ - outb_p(MODE, dev->iobase + 11); - b = BIP | SEM | MODE | GAIN | FIFOHFULL; - outb_p(b, dev->iobase + 11); + /* set all digital outputs low */ + outb(0, dev->iobase + DAS6402_DI_DO_REG); - /* register 8 */ - outb_p(EXTEND, dev->iobase + 8); - b = EXTEND | MHZ; - outb_p(b, dev->iobase + 8); - b = MHZ | CLRINT | CLRXTR | CLRXIN; - outb_p(b, dev->iobase + 8); - - /* register 9 */ - b = IRQ | CONVSRC | BURSTEN | INTE; - outb_p(b, dev->iobase + 9); - - /* register 10 */ - b = TGSEL | TGEN; - outb_p(b, dev->iobase + 10); - - b = 0x07; - outb_p(b, dev->iobase + 8); - - das6402_setcounter(dev); - - outw_p(SCANL, dev->iobase + 2); /* reset card fifo */ - - devpriv->das6402_ignoreirq = 0; - - return 0; + das6402_clear_all_interrupts(dev); } static int das6402_attach(struct comedi_device *dev, struct comedi_devconfig *it) { + const struct das6402_boardinfo *board = comedi_board(dev); struct das6402_private *devpriv; - unsigned int irq; - int ret; struct comedi_subdevice *s; - - ret = comedi_request_region(dev, it->options[0], DAS6402_SIZE); - if (ret) - return ret; - - irq = it->options[0]; - dev_dbg(dev->class_dev, "( irq = %u )\n", irq); - ret = request_irq(irq, intr_handler, 0, "das6402", dev); - if (ret < 0) - return ret; - - dev->irq = irq; + int ret; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - ret = comedi_alloc_subdevices(dev, 1); + ret = comedi_request_region(dev, it->options[0], 0x10); if (ret) return ret; - /* ai subdevice */ - s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = 8; - /* s->trig[2]=das6402_ai_mode2; */ - s->cancel = das6402_ai_cancel; - s->maxdata = (1 << 12) - 1; - s->len_chanlist = 16; /* ? */ - s->range_table = &range_unknown; + das6402_reset(dev); - board_init(dev); + /* IRQs 2,3,5,6,7, 10,11,15 are valid for "enhanced" mode */ + if ((1 << it->options[1]) & 0x8cec) { + ret = request_irq(it->options[1], das6402_interrupt, 0, + dev->board_name, dev); + if (ret == 0) { + dev->irq = it->options[1]; + + switch (dev->irq) { + case 10: + devpriv->irq = 4; + break; + case 11: + devpriv->irq = 1; + break; + case 15: + devpriv->irq = 6; + break; + default: + devpriv->irq = dev->irq; + break; + } + } + } + + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; + + /* Analog Input subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; + s->n_chan = 64; + s->maxdata = board->maxdata; + s->range_table = &das6402_ai_ranges; + s->insn_read = das6402_ai_insn_read; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmdtest = das6402_ai_cmdtest; + s->do_cmd = das6402_ai_cmd; + s->cancel = das6402_ai_cancel; + } + + /* Analog Output subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = board->maxdata; + s->range_table = &das6402_ao_ranges; + s->insn_write = das6402_ao_insn_write; + s->insn_read = das6402_ao_insn_read; + + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das6402_di_insn_bits; + + /* Digital Input subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das6402_do_insn_bits; return 0; } @@ -313,9 +536,12 @@ static struct comedi_driver das6402_driver = { .module = THIS_MODULE, .attach = das6402_attach, .detach = comedi_legacy_detach, + .board_name = &das6402_boards[0].name, + .num_names = ARRAY_SIZE(das6402_boards), + .offset = sizeof(struct das6402_boardinfo), }; module_comedi_driver(das6402_driver) -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_AUTHOR("H Hartley Sweeten "); +MODULE_DESCRIPTION("Comedi driver for DAS6402 compatible boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index 5af0a5764a8c..3e408370dcf3 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -420,17 +420,12 @@ static int das800_ai_do_cmd(struct comedi_device *dev, gain &= 0xf; outb(gain, dev->iobase + DAS800_GAIN); - switch (async->cmd.stop_src) { - case TRIG_COUNT: + if (async->cmd.stop_src == TRIG_COUNT) { devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len; devpriv->forever = false; - break; - case TRIG_NONE: + } else { /* TRIG_NONE */ devpriv->forever = true; devpriv->count = 0; - break; - default: - break; } /* enable auto channel scan, send interrupts on end of conversion @@ -440,26 +435,19 @@ static int das800_ai_do_cmd(struct comedi_device *dev, conv_bits |= EACS | IEOC; if (async->cmd.start_src == TRIG_EXT) conv_bits |= DTEN; - switch (async->cmd.convert_src) { - case TRIG_TIMER: + if (async->cmd.convert_src == TRIG_TIMER) { conv_bits |= CASC | ITE; /* set conversion frequency */ if (das800_set_frequency(dev) < 0) { comedi_error(dev, "Error setting up counters"); return -1; } - break; - case TRIG_EXT: - break; - default: - break; } spin_lock_irqsave(&dev->spinlock, irq_flags); das800_ind_write(dev, conv_bits, CONV_CONTROL); spin_unlock_irqrestore(&dev->spinlock, irq_flags); - async->events = 0; das800_enable(dev); return 0; } @@ -532,10 +520,8 @@ static irqreturn_t das800_interrupt(int irq, void *d) if (fifo_overflow) { spin_unlock_irqrestore(&dev->spinlock, irq_flags); - das800_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); - async->events = 0; + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -551,20 +537,21 @@ static irqreturn_t das800_interrupt(int irq, void *d) das800_disable(dev); async->events |= COMEDI_CB_EOA; } - comedi_event(dev, s); - async->events = 0; + cfc_handle_events(dev, s); return IRQ_HANDLED; } -static int das800_wait_for_conv(struct comedi_device *dev, int timeout) +static int das800_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - int i; + unsigned int status; - for (i = 0; i < timeout; i++) { - if (!(inb(dev->iobase + DAS800_STATUS) & BUSY)) - return 0; - } - return -ETIME; + status = inb(dev->iobase + DAS800_STATUS); + if ((status & BUSY) == 0) + return 0; + return -EBUSY; } static int das800_ai_insn_read(struct comedi_device *dev, @@ -599,7 +586,7 @@ static int das800_ai_insn_read(struct comedi_device *dev, /* trigger conversion */ outb_p(0, dev->iobase + DAS800_MSB); - ret = das800_wait_for_conv(dev, 1000); + ret = comedi_timeout(dev, s, insn, das800_ai_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c index 78a19629ff56..c8a36eb5f015 100644 --- a/drivers/staging/comedi/drivers/dmm32at.c +++ b/drivers/staging/comedi/drivers/dmm32at.c @@ -164,16 +164,29 @@ struct dmm32at_private { }; +static int dmm32at_ai_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned char status; + + status = inb(dev->iobase + context); + if ((status & DMM32AT_STATUS) == 0) + return 0; + return -EBUSY; +} + static int dmm32at_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i; + int n; unsigned int d; - unsigned char status; unsigned short msb, lsb; unsigned char chan; int range; + int ret; /* get the channel and range number */ @@ -190,26 +203,20 @@ static int dmm32at_ai_rinsn(struct comedi_device *dev, outb(dmm32at_rangebits[range], dev->iobase + DMM32AT_AICONF); /* wait for circuit to settle */ - for (i = 0; i < 40000; i++) { - status = inb(dev->iobase + DMM32AT_AIRBACK); - if ((status & DMM32AT_STATUS) == 0) - break; - } - if (i == 40000) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, dmm32at_ai_status, DMM32AT_AIRBACK); + if (ret) + return ret; /* convert n samples */ for (n = 0; n < insn->n; n++) { /* trigger conversion */ outb(0xff, dev->iobase + DMM32AT_CONV); + /* wait for conversion to end */ - for (i = 0; i < 40000; i++) { - status = inb(dev->iobase + DMM32AT_AISTAT); - if ((status & DMM32AT_STATUS) == 0) - break; - } - if (i == 40000) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, dmm32at_ai_status, + DMM32AT_AISTAT); + if (ret) + return ret; /* read data */ lsb = inb(dev->iobase + DMM32AT_AILSB); @@ -403,8 +410,9 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { struct dmm32at_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - int i, range; - unsigned char chanlo, chanhi, status; + int range; + unsigned char chanlo, chanhi; + int ret; if (!cmd->chanlist) return -EINVAL; @@ -439,14 +447,13 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * isr */ } - /* wait for circuit to settle */ - for (i = 0; i < 40000; i++) { - status = inb(dev->iobase + DMM32AT_AIRBACK); - if ((status & DMM32AT_STATUS) == 0) - break; - } - if (i == 40000) - return -ETIMEDOUT; + /* + * wait for circuit to settle + * we don't have the 'insn' here but it's not needed + */ + ret = comedi_timeout(dev, s, NULL, dmm32at_ai_status, DMM32AT_AIRBACK); + if (ret) + return ret; if (devpriv->ai_scans_left > 1) { /* start the clock and enable the interrupts */ @@ -525,6 +532,19 @@ static irqreturn_t dmm32at_isr(int irq, void *d) return IRQ_HANDLED; } +static int dmm32at_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned char status; + + status = inb(dev->iobase + DMM32AT_DACSTAT); + if ((status & DMM32AT_DACBUSY) == 0) + return 0; + return -EBUSY; +} + static int dmm32at_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -533,6 +553,7 @@ static int dmm32at_ao_winsn(struct comedi_device *dev, int i; int chan = CR_CHAN(insn->chanspec); unsigned char hi, lo, status; + int ret; /* Writing a list of values to an AO channel is probably not * very useful, but that's how the interface is defined. */ @@ -549,13 +570,9 @@ static int dmm32at_ao_winsn(struct comedi_device *dev, outb(hi, dev->iobase + DMM32AT_DACMSB); /* wait for circuit to settle */ - for (i = 0; i < 40000; i++) { - status = inb(dev->iobase + DMM32AT_DACSTAT); - if ((status & DMM32AT_DACBUSY) == 0) - break; - } - if (i == 40000) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, dmm32at_ao_eoc, 0); + if (ret) + return ret; /* dummy read to update trigger the output */ status = inb(dev->iobase + DMM32AT_DACMSB); diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 4271903facd7..ba7c2ba618e6 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -224,23 +224,32 @@ static const struct comedi_lrange *dac_range_types[] = { &range_unipolar5 }; -#define DT2811_TIMEOUT 5 +static int dt2811_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DT2811_ADCSR); + if ((status & DT2811_ADBUSY) == 0) + return 0; + return -EBUSY; +} static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { int chan = CR_CHAN(insn->chanspec); - int timeout = DT2811_TIMEOUT; + int ret; int i; for (i = 0; i < insn->n; i++) { outb(chan, dev->iobase + DT2811_ADGCR); - while (timeout - && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY) - timeout--; - if (!timeout) - return -ETIME; + ret = comedi_timeout(dev, s, insn, dt2811_ai_eoc, 0); + if (ret) + return ret; data[i] = inb(dev->iobase + DT2811_ADDATLO); data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8; diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c index abad6e49c1c1..3794b7e52091 100644 --- a/drivers/staging/comedi/drivers/dt2814.c +++ b/drivers/staging/comedi/drivers/dt2814.c @@ -66,26 +66,35 @@ struct dt2814_private { #define DT2814_TIMEOUT 10 #define DT2814_MAX_SPEED 100000 /* Arbitrary 10 khz limit */ +static int dt2814_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DT2814_CSR); + if (status & DT2814_FINISH) + return 0; + return -EBUSY; +} + static int dt2814_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i, hi, lo; + int n, hi, lo; int chan; - int status = 0; + int ret; for (n = 0; n < insn->n; n++) { chan = CR_CHAN(insn->chanspec); outb(chan, dev->iobase + DT2814_CSR); - for (i = 0; i < DT2814_TIMEOUT; i++) { - status = inb(dev->iobase + DT2814_CSR); - udelay(10); - if (status & DT2814_FINISH) - break; - } - if (i >= DT2814_TIMEOUT) - return -ETIMEDOUT; + + ret = comedi_timeout(dev, s, insn, dt2814_ai_eoc, 0); + if (ret) + return ret; hi = inb(dev->iobase + DT2814_DATA); lo = inb(dev->iobase + DT2814_DATA); diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c index ee24717821e1..b9ac4ed8babb 100644 --- a/drivers/staging/comedi/drivers/dt2815.c +++ b/drivers/staging/comedi/drivers/dt2815.c @@ -67,15 +67,17 @@ struct dt2815_private { unsigned int ao_readback[8]; }; -static int dt2815_wait_for_status(struct comedi_device *dev, int status) +static int dt2815_ao_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - int i; + unsigned int status; - for (i = 0; i < 100; i++) { - if (inb(dev->iobase + DT2815_STATUS) == status) - break; - } - return status; + status = inb(dev->iobase + DT2815_STATUS); + if (status == context) + return 0; + return -EBUSY; } static int dt2815_ao_insn_read(struct comedi_device *dev, @@ -98,30 +100,23 @@ static int dt2815_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct dt2815_private *devpriv = dev->private; int i; int chan = CR_CHAN(insn->chanspec); - unsigned int status; unsigned int lo, hi; + int ret; for (i = 0; i < insn->n; i++) { lo = ((data[i] & 0x0f) << 4) | (chan << 1) | 0x01; hi = (data[i] & 0xff0) >> 4; - status = dt2815_wait_for_status(dev, 0x00); - if (status != 0) { - dev_dbg(dev->class_dev, - "failed to write low byte on %d reason %x\n", - chan, status); - return -EBUSY; - } + ret = comedi_timeout(dev, s, insn, dt2815_ao_status, 0x00); + if (ret) + return ret; outb(lo, dev->iobase + DT2815_DATA); - status = dt2815_wait_for_status(dev, 0x10); - if (status != 0x10) { - dev_dbg(dev->class_dev, - "failed to write high byte on %d reason %x\n", - chan, status); - return -EBUSY; - } + ret = comedi_timeout(dev, s, insn, dt2815_ao_status, 0x10); + if (ret) + return ret; + devpriv->ao_readback[chan] = data[i]; } return i; diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c index 895f73a19023..16cc100531e5 100644 --- a/drivers/staging/comedi/drivers/dt282x.c +++ b/drivers/staging/comedi/drivers/dt282x.c @@ -63,7 +63,6 @@ Notes: #include "comedi_fc.h" -#define DT2821_TIMEOUT 100 /* 500 us */ #define DT2821_SIZE 0x10 /* @@ -248,27 +247,6 @@ struct dt282x_private { * Some useless abstractions */ #define chan_to_DAC(a) ((a)&1) -#define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY) -#define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE) - -/* - * danger! macro abuse... a is the expression to wait on, and b is - * the statement(s) to execute if it doesn't happen. - */ -#define wait_for(a, b) \ - do { \ - int _i; \ - for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \ - if (a) { \ - _i = 0; \ - break; \ - } \ - udelay(5); \ - } \ - if (_i) { \ - b \ - } \ - } while (0) static int prep_ai_dma(struct comedi_device *dev, int chan, int size); static int prep_ao_dma(struct comedi_device *dev, int chan, int size); @@ -328,7 +306,6 @@ static void dt282x_ao_dma_interrupt(struct comedi_device *dev) size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize); if (size == 0) { dev_err(dev->class_dev, "AO underrun\n"); - dt282x_ao_cancel(dev, s); s->async->events |= COMEDI_CB_OVERFLOW; return; } @@ -363,7 +340,7 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev) dt282x_munge(dev, ptr, size); ret = cfc_write_array_to_buffer(s, ptr, size); if (ret != size) { - dt282x_ai_cancel(dev, s); + s->async->events |= COMEDI_CB_OVERFLOW; return; } devpriv->nread -= size / 2; @@ -373,7 +350,6 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev) devpriv->nread = 0; } if (!devpriv->nread) { - dt282x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; return; } @@ -471,15 +447,13 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) if (adcsr & DT2821_ADERR) { if (devpriv->nread != 0) { comedi_error(dev, "A/D error"); - dt282x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_ERROR; } handled = 1; } if (dacsr & DT2821_DAERR) { comedi_error(dev, "D/A error"); - dt282x_ao_cancel(dev, s_ao); - s->async->events |= COMEDI_CB_ERROR; + s_ao->async->events |= COMEDI_CB_ERROR; handled = 1; } #if 0 @@ -508,7 +482,8 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) handled = 1; } #endif - comedi_event(dev, s); + cfc_handle_events(dev, s); + cfc_handle_events(dev, s_ao); return IRQ_RETVAL(handled); } @@ -530,6 +505,29 @@ static void dt282x_load_changain(struct comedi_device *dev, int n, outw(n - 1, dev->iobase + DT2821_CHANCSR); } +static int dt282x_ai_timeout(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + DT2821_ADCSR); + switch (context) { + case DT2821_MUXBUSY: + if ((status & DT2821_MUXBUSY) == 0) + return 0; + break; + case DT2821_ADDONE: + if (status & DT2821_ADDONE) + return 0; + break; + default: + return -EINVAL; + } + return -EBUSY; +} + /* * Performs a single A/D conversion. * - Put channel/gain into channel-gain list @@ -542,6 +540,7 @@ static int dt282x_ai_insn_read(struct comedi_device *dev, { const struct dt282x_board *board = comedi_board(dev); struct dt282x_private *devpriv = dev->private; + int ret; int i; /* XXX should we really be enabling the ad clock here? */ @@ -551,13 +550,18 @@ static int dt282x_ai_insn_read(struct comedi_device *dev, dt282x_load_changain(dev, 1, &insn->chanspec); outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR); - wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;); + ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout, DT2821_MUXBUSY); + if (ret) + return ret; for (i = 0; i < insn->n; i++) { outw(devpriv->supcsr | DT2821_STRIG, dev->iobase + DT2821_SUPCSR); - wait_for(ad_done(), comedi_error(dev, "timeout\n"); - return -ETIME;); + + ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout, + DT2821_ADDONE); + if (ret) + return ret; data[i] = inw(dev->iobase + @@ -646,6 +650,7 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) struct dt282x_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; int timer; + int ret; if (devpriv->usedma == 0) { comedi_error(dev, @@ -691,7 +696,9 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR); outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR); - wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;); + ret = comedi_timeout(dev, s, NULL, dt282x_ai_timeout, DT2821_MUXBUSY); + if (ret) + return ret; if (cmd->scan_begin_src == TRIG_FOLLOW) { outw(devpriv->supcsr | DT2821_STRIG, diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c index f52a4476cb73..436e451cadf5 100644 --- a/drivers/staging/comedi/drivers/dt3000.c +++ b/drivers/staging/comedi/drivers/dt3000.c @@ -369,12 +369,10 @@ static irqreturn_t dt3k_interrupt(int irq, void *d) s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; debug_n_ints++; - if (debug_n_ints >= 10) { - dt3k_ai_cancel(dev, s); + if (debug_n_ints >= 10) s->async->events |= COMEDI_CB_EOA; - } - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -767,8 +765,6 @@ static int dt3000_auto_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_PROC; #endif - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c index f224825830ba..e5593f8c7406 100644 --- a/drivers/staging/comedi/drivers/dyna_pci10xx.c +++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c @@ -57,18 +57,27 @@ struct dyna_pci10xx_private { unsigned long BADR3; }; -/******************************************************************************/ -/************************** READ WRITE FUNCTIONS ******************************/ -/******************************************************************************/ +static int dyna_pci10xx_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw_p(dev->iobase); + if (status & (1 << 15)) + return 0; + return -EBUSY; +} -/* analog input callback */ static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct dyna_pci10xx_private *devpriv = dev->private; - int n, counter; + int n; u16 d = 0; + int ret = 0; unsigned int chan, range; /* get the channel number and range */ @@ -82,18 +91,13 @@ static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev, smp_mb(); outw_p(0x0000 + range + chan, dev->iobase + 2); udelay(10); - /* read data */ - for (counter = 0; counter < READ_TIMEOUT; counter++) { - d = inw_p(dev->iobase); - /* check if read is successful if the EOC bit is set */ - if (d & (1 << 15)) - goto conv_finish; - } - data[n] = 0; - dev_dbg(dev->class_dev, "timeout reading analog input\n"); - continue; -conv_finish: + ret = comedi_timeout(dev, s, insn, dyna_pci10xx_ai_eoc, 0); + if (ret) + break; + + /* read data */ + d = inw_p(dev->iobase); /* mask the first 4 bits - EOC bits */ d &= 0x0FFF; data[n] = d; @@ -101,7 +105,7 @@ conv_finish: mutex_unlock(&devpriv->mutex); /* return the number of samples read/written */ - return n; + return ret ? ret : n; } /* analog output callback */ @@ -232,8 +236,6 @@ static int dyna_pci10xx_auto_attach(struct comedi_device *dev, s->state = 0; s->insn_bits = dyna_pci10xx_do_insn_bits; - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c index a99ddf00ddc4..4e410f3b0e24 100644 --- a/drivers/staging/comedi/drivers/fl512.c +++ b/drivers/staging/comedi/drivers/fl512.c @@ -1,27 +1,49 @@ /* - comedi/drivers/fl512.c - Anders Gnistrup -*/ + * fl512.c + * Anders Gnistrup + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* -Driver: fl512 -Description: unknown -Author: Anders Gnistrup -Devices: [unknown] FL512 (fl512) -Status: unknown - -Digital I/O is not supported. - -Configuration options: - [0] - I/O port base address -*/ + * Driver: fl512 + * Description: unknown + * Author: Anders Gnistrup + * Devices: [unknown] FL512 (fl512) + * Status: unknown + * + * Digital I/O is not supported. + * + * Configuration options: + * [0] - I/O port base address + */ #include #include "../comedidev.h" #include -#define FL512_SIZE 16 /* the size of the used memory */ +/* + * Register I/O map + */ +#define FL512_AI_LSB_REG 0x02 +#define FL512_AI_MSB_REG 0x03 +#define FL512_AI_MUX_REG 0x02 +#define FL512_AI_START_CONV_REG 0x03 +#define FL512_AO_DATA_REG(x) (0x04 + ((x) * 2)) +#define FL512_AO_TRIG_REG(x) (0x04 + ((x) * 2)) + struct fl512_private { unsigned short ao_readback[2]; }; @@ -38,72 +60,69 @@ static const struct comedi_lrange range_fl512 = { } }; -/* - * fl512_ai_insn : this is the analog input function - */ -static int fl512_ai_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int fl512_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int n; - unsigned int lo_byte, hi_byte; - char chan = CR_CHAN(insn->chanspec); - unsigned long iobase = dev->iobase; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; + + outb(chan, dev->iobase + FL512_AI_MUX_REG); + + for (i = 0; i < insn->n; i++) { + outb(0, dev->iobase + FL512_AI_START_CONV_REG); - for (n = 0; n < insn->n; n++) { /* sample n times on selected channel */ - /* XXX probably can move next step out of for() loop -- will - * make AI a little bit faster. */ - outb(chan, iobase + 2); /* select chan */ - outb(0, iobase + 3); /* start conversion */ /* XXX should test "done" flag instead of delay */ - udelay(30); /* sleep 30 usec */ - lo_byte = inb(iobase + 2); /* low 8 byte */ - hi_byte = inb(iobase + 3) & 0xf; /* high 4 bit and mask */ - data[n] = lo_byte + (hi_byte << 8); + udelay(30); + + val = inb(dev->iobase + FL512_AI_LSB_REG); + val |= (inb(dev->iobase + FL512_AI_MSB_REG) << 8); + val &= s->maxdata; + + data[i] = val; } - return n; + + return insn->n; } -/* - * fl512_ao_insn : used to write to a DA port n times - */ -static int fl512_ao_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int fl512_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct fl512_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); /* get chan to write */ - unsigned long iobase = dev->iobase; /* get base address */ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = devpriv->ao_readback[chan]; + int i; - for (n = 0; n < insn->n; n++) { /* write n data set */ - /* write low byte */ - outb(data[n] & 0x0ff, iobase + 4 + 2 * chan); - /* write high byte */ - outb((data[n] & 0xf00) >> 8, iobase + 4 + 2 * chan); - inb(iobase + 4 + 2 * chan); /* trig */ + for (i = 0; i < insn->n; i++) { + val = data[i]; - devpriv->ao_readback[chan] = data[n]; + /* write LSB, MSB then trigger conversion */ + outb(val & 0x0ff, dev->iobase + FL512_AO_DATA_REG(chan)); + outb((val >> 8) & 0xf, dev->iobase + FL512_AO_DATA_REG(chan)); + inb(dev->iobase + FL512_AO_TRIG_REG(chan)); } - return n; + devpriv->ao_readback[chan] = val; + + return insn->n; } -/* - * fl512_ao_insn_readback : used to read previous values written to - * DA port - */ -static int fl512_ao_insn_readback(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int fl512_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { struct fl512_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_readback[chan]; + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; - return n; + return insn->n; } static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -112,7 +131,7 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) struct comedi_subdevice *s; int ret; - ret = comedi_request_region(dev, it->options[0], FL512_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x10); if (ret) return ret; @@ -124,42 +143,26 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - /* - * this if the definitions of the supdevices, 2 have been defined - */ - /* Analog indput */ + /* Analog Input subdevice */ s = &dev->subdevices[0]; - /* define subdevice as Analog In */ - s->type = COMEDI_SUBD_AI; - /* you can read it from userspace */ - s->subdev_flags = SDF_READABLE | SDF_GROUND; - /* Number of Analog input channels */ - s->n_chan = 16; - /* accept only 12 bits of data */ - s->maxdata = 0x0fff; - /* device use one of the ranges */ - s->range_table = &range_fl512; - /* function to call when read AD */ - s->insn_read = fl512_ai_insn; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 16; + s->maxdata = 0x0fff; + s->range_table = &range_fl512; + s->insn_read = fl512_ai_insn_read; - /* Analog output */ + /* Analog Output subdevice */ s = &dev->subdevices[1]; - /* define subdevice as Analog OUT */ - s->type = COMEDI_SUBD_AO; - /* you can write it from userspace */ - s->subdev_flags = SDF_WRITABLE; - /* Number of Analog output channels */ - s->n_chan = 2; - /* accept only 12 bits of data */ - s->maxdata = 0x0fff; - /* device use one of the ranges */ - s->range_table = &range_fl512; - /* function to call when write DA */ - s->insn_write = fl512_ao_insn; - /* function to call when reading DA */ - s->insn_read = fl512_ao_insn_readback; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = &range_fl512; + s->insn_write = fl512_ao_insn_write; + s->insn_read = fl512_ao_insn_read; - return 1; + return 0; } static struct comedi_driver fl512_driver = { diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index de60a2871d70..08d7655e24e7 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -1,24 +1,24 @@ /* - comedi/drivers/gsc_hpdi.c - This is a driver for the General Standards Corporation High - Speed Parallel Digital Interface rs485 boards. - - Author: Frank Mori Hess - Copyright (C) 2003 Coherent Imaging Systems - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1997-8 David A. Schleef - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * gsc_hpdi.c + * Comedi driver the General Standards Corporation + * High Speed Parallel Digital Interface rs485 boards. + * + * Author: Frank Mori Hess + * Copyright (C) 2003 Coherent Imaging Systems + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-8 David A. Schleef + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* * Driver: gsc_hpdi @@ -40,8 +40,6 @@ * support could be added to this driver. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include @@ -52,149 +50,105 @@ #include "plx9080.h" #include "comedi_fc.h" -static void abort_dma(struct comedi_device *dev, unsigned int channel); -static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static irqreturn_t handle_interrupt(int irq, void *d); -static int dio_config_block_size(struct comedi_device *dev, unsigned int *data); +/* + * PCI BAR2 Register map (devpriv->mmio) + */ +#define FIRMWARE_REV_REG 0x00 +#define FEATURES_REG_PRESENT_BIT (1 << 15) +#define BOARD_CONTROL_REG 0x04 +#define BOARD_RESET_BIT (1 << 0) +#define TX_FIFO_RESET_BIT (1 << 1) +#define RX_FIFO_RESET_BIT (1 << 2) +#define TX_ENABLE_BIT (1 << 4) +#define RX_ENABLE_BIT (1 << 5) +#define DEMAND_DMA_DIRECTION_TX_BIT (1 << 6) /* ch 0 only */ +#define LINE_VALID_ON_STATUS_VALID_BIT (1 << 7) +#define START_TX_BIT (1 << 8) +#define CABLE_THROTTLE_ENABLE_BIT (1 << 9) +#define TEST_MODE_ENABLE_BIT (1 << 31) +#define BOARD_STATUS_REG 0x08 +#define COMMAND_LINE_STATUS_MASK (0x7f << 0) +#define TX_IN_PROGRESS_BIT (1 << 7) +#define TX_NOT_EMPTY_BIT (1 << 8) +#define TX_NOT_ALMOST_EMPTY_BIT (1 << 9) +#define TX_NOT_ALMOST_FULL_BIT (1 << 10) +#define TX_NOT_FULL_BIT (1 << 11) +#define RX_NOT_EMPTY_BIT (1 << 12) +#define RX_NOT_ALMOST_EMPTY_BIT (1 << 13) +#define RX_NOT_ALMOST_FULL_BIT (1 << 14) +#define RX_NOT_FULL_BIT (1 << 15) +#define BOARD_JUMPER0_INSTALLED_BIT (1 << 16) +#define BOARD_JUMPER1_INSTALLED_BIT (1 << 17) +#define TX_OVERRUN_BIT (1 << 21) +#define RX_UNDERRUN_BIT (1 << 22) +#define RX_OVERRUN_BIT (1 << 23) +#define TX_PROG_ALMOST_REG 0x0c +#define RX_PROG_ALMOST_REG 0x10 +#define ALMOST_EMPTY_BITS(x) (((x) & 0xffff) << 0) +#define ALMOST_FULL_BITS(x) (((x) & 0xff) << 16) +#define FEATURES_REG 0x14 +#define FIFO_SIZE_PRESENT_BIT (1 << 0) +#define FIFO_WORDS_PRESENT_BIT (1 << 1) +#define LEVEL_EDGE_INTERRUPTS_PRESENT_BIT (1 << 2) +#define GPIO_SUPPORTED_BIT (1 << 3) +#define PLX_DMA_CH1_SUPPORTED_BIT (1 << 4) +#define OVERRUN_UNDERRUN_SUPPORTED_BIT (1 << 5) +#define FIFO_REG 0x18 +#define TX_STATUS_COUNT_REG 0x1c +#define TX_LINE_VALID_COUNT_REG 0x20, +#define TX_LINE_INVALID_COUNT_REG 0x24 +#define RX_STATUS_COUNT_REG 0x28 +#define RX_LINE_COUNT_REG 0x2c +#define INTERRUPT_CONTROL_REG 0x30 +#define FRAME_VALID_START_INTR (1 << 0) +#define FRAME_VALID_END_INTR (1 << 1) +#define TX_FIFO_EMPTY_INTR (1 << 8) +#define TX_FIFO_ALMOST_EMPTY_INTR (1 << 9) +#define TX_FIFO_ALMOST_FULL_INTR (1 << 10) +#define TX_FIFO_FULL_INTR (1 << 11) +#define RX_EMPTY_INTR (1 << 12) +#define RX_ALMOST_EMPTY_INTR (1 << 13) +#define RX_ALMOST_FULL_INTR (1 << 14) +#define RX_FULL_INTR (1 << 15) +#define INTERRUPT_STATUS_REG 0x34 +#define TX_CLOCK_DIVIDER_REG 0x38 +#define TX_FIFO_SIZE_REG 0x40 +#define RX_FIFO_SIZE_REG 0x44 +#define FIFO_SIZE_MASK (0xfffff << 0) +#define TX_FIFO_WORDS_REG 0x48 +#define RX_FIFO_WORDS_REG 0x4c +#define INTERRUPT_EDGE_LEVEL_REG 0x50 +#define INTERRUPT_POLARITY_REG 0x54 -#define TIMER_BASE 50 /* 20MHz master clock */ -#define DMA_BUFFER_SIZE 0x10000 -#define NUM_DMA_BUFFERS 4 -#define NUM_DMA_DESCRIPTORS 256 - -enum hpdi_registers { - FIRMWARE_REV_REG = 0x0, - BOARD_CONTROL_REG = 0x4, - BOARD_STATUS_REG = 0x8, - TX_PROG_ALMOST_REG = 0xc, - RX_PROG_ALMOST_REG = 0x10, - FEATURES_REG = 0x14, - FIFO_REG = 0x18, - TX_STATUS_COUNT_REG = 0x1c, - TX_LINE_VALID_COUNT_REG = 0x20, - TX_LINE_INVALID_COUNT_REG = 0x24, - RX_STATUS_COUNT_REG = 0x28, - RX_LINE_COUNT_REG = 0x2c, - INTERRUPT_CONTROL_REG = 0x30, - INTERRUPT_STATUS_REG = 0x34, - TX_CLOCK_DIVIDER_REG = 0x38, - TX_FIFO_SIZE_REG = 0x40, - RX_FIFO_SIZE_REG = 0x44, - TX_FIFO_WORDS_REG = 0x48, - RX_FIFO_WORDS_REG = 0x4c, - INTERRUPT_EDGE_LEVEL_REG = 0x50, - INTERRUPT_POLARITY_REG = 0x54, -}; - -/* bit definitions */ - -enum firmware_revision_bits { - FEATURES_REG_PRESENT_BIT = 0x8000, -}; - -enum board_control_bits { - BOARD_RESET_BIT = 0x1, /* wait 10usec before accessing fifos */ - TX_FIFO_RESET_BIT = 0x2, - RX_FIFO_RESET_BIT = 0x4, - TX_ENABLE_BIT = 0x10, - RX_ENABLE_BIT = 0x20, - DEMAND_DMA_DIRECTION_TX_BIT = 0x40, - /* for ch 0, ch 1 can only transmit (when present) */ - LINE_VALID_ON_STATUS_VALID_BIT = 0x80, - START_TX_BIT = 0x10, - CABLE_THROTTLE_ENABLE_BIT = 0x20, - TEST_MODE_ENABLE_BIT = 0x80000000, -}; - -enum board_status_bits { - COMMAND_LINE_STATUS_MASK = 0x7f, - TX_IN_PROGRESS_BIT = 0x80, - TX_NOT_EMPTY_BIT = 0x100, - TX_NOT_ALMOST_EMPTY_BIT = 0x200, - TX_NOT_ALMOST_FULL_BIT = 0x400, - TX_NOT_FULL_BIT = 0x800, - RX_NOT_EMPTY_BIT = 0x1000, - RX_NOT_ALMOST_EMPTY_BIT = 0x2000, - RX_NOT_ALMOST_FULL_BIT = 0x4000, - RX_NOT_FULL_BIT = 0x8000, - BOARD_JUMPER0_INSTALLED_BIT = 0x10000, - BOARD_JUMPER1_INSTALLED_BIT = 0x20000, - TX_OVERRUN_BIT = 0x200000, - RX_UNDERRUN_BIT = 0x400000, - RX_OVERRUN_BIT = 0x800000, -}; - -static uint32_t almost_full_bits(unsigned int num_words) -{ - /* XXX need to add or subtract one? */ - return (num_words << 16) & 0xff0000; -} - -static uint32_t almost_empty_bits(unsigned int num_words) -{ - return num_words & 0xffff; -} - -enum features_bits { - FIFO_SIZE_PRESENT_BIT = 0x1, - FIFO_WORDS_PRESENT_BIT = 0x2, - LEVEL_EDGE_INTERRUPTS_PRESENT_BIT = 0x4, - GPIO_SUPPORTED_BIT = 0x8, - PLX_DMA_CH1_SUPPORTED_BIT = 0x10, - OVERRUN_UNDERRUN_SUPPORTED_BIT = 0x20, -}; - -enum interrupt_sources { - FRAME_VALID_START_INTR = 0, - FRAME_VALID_END_INTR = 1, - TX_FIFO_EMPTY_INTR = 8, - TX_FIFO_ALMOST_EMPTY_INTR = 9, - TX_FIFO_ALMOST_FULL_INTR = 10, - TX_FIFO_FULL_INTR = 11, - RX_EMPTY_INTR = 12, - RX_ALMOST_EMPTY_INTR = 13, - RX_ALMOST_FULL_INTR = 14, - RX_FULL_INTR = 15, -}; - -static uint32_t intr_bit(int interrupt_source) -{ - return 0x1 << interrupt_source; -} - -static unsigned int fifo_size(uint32_t fifo_size_bits) -{ - return fifo_size_bits & 0xfffff; -} +#define TIMER_BASE 50 /* 20MHz master clock */ +#define DMA_BUFFER_SIZE 0x10000 +#define NUM_DMA_BUFFERS 4 +#define NUM_DMA_DESCRIPTORS 256 struct hpdi_board { - const char *name; /* board name */ - int device_id; /* pci device id */ - int subdevice_id; /* pci subdevice id */ + const char *name; + int device_id; + int subdevice_id; }; static const struct hpdi_board hpdi_boards[] = { { - .name = "pci-hpdi32", - .device_id = PCI_DEVICE_ID_PLX_9080, - .subdevice_id = 0x2400, + .name = "pci-hpdi32", + .device_id = PCI_DEVICE_ID_PLX_9080, + .subdevice_id = 0x2400, }, #if 0 { - .name = "pxi-hpdi32", - .device_id = 0x9656, - .subdevice_id = 0x2705, + .name = "pxi-hpdi32", + .device_id = 0x9656, + .subdevice_id = 0x2705, }, #endif }; struct hpdi_private { - /* base addresses (ioremapped) */ - void __iomem *plx9080_iobase; - void __iomem *hpdi_iobase; + void __iomem *plx9080_mmio; + void __iomem *mmio; uint32_t *dio_buffer[NUM_DMA_BUFFERS]; /* dma buffers */ /* physical addresses of dma buffers */ dma_addr_t dio_buffer_phys_addr[NUM_DMA_BUFFERS]; @@ -207,26 +161,334 @@ struct hpdi_private { /* pointer to start of buffers indexed by descriptor */ uint32_t *desc_dio_buffer[NUM_DMA_DESCRIPTORS]; /* index of the dma descriptor that is currently being used */ - volatile unsigned int dma_desc_index; + unsigned int dma_desc_index; unsigned int tx_fifo_size; unsigned int rx_fifo_size; - volatile unsigned long dio_count; - /* software copies of values written to hpdi registers */ - volatile uint32_t bits[24]; + unsigned long dio_count; /* number of bytes at which to generate COMEDI_CB_BLOCK events */ - volatile unsigned int block_size; + unsigned int block_size; }; -static int dio_config_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static void gsc_hpdi_drain_dma(struct comedi_device *dev, unsigned int channel) +{ + struct hpdi_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int idx; + unsigned int start; + unsigned int desc; + unsigned int size; + unsigned int next; + + if (channel) + next = readl(devpriv->plx9080_mmio + PLX_DMA1_PCI_ADDRESS_REG); + else + next = readl(devpriv->plx9080_mmio + PLX_DMA0_PCI_ADDRESS_REG); + + idx = devpriv->dma_desc_index; + start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr); + /* loop until we have read all the full buffers */ + for (desc = 0; (next < start || next >= start + devpriv->block_size) && + desc < devpriv->num_dma_descriptors; desc++) { + /* transfer data from dma buffer to comedi buffer */ + size = devpriv->block_size / sizeof(uint32_t); + if (cmd->stop_src == TRIG_COUNT) { + if (size > devpriv->dio_count) + size = devpriv->dio_count; + devpriv->dio_count -= size; + } + cfc_write_array_to_buffer(s, devpriv->desc_dio_buffer[idx], + size * sizeof(uint32_t)); + idx++; + idx %= devpriv->num_dma_descriptors; + start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr); + + devpriv->dma_desc_index = idx; + } + /* XXX check for buffer overrun somehow */ +} + +static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct hpdi_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + uint32_t hpdi_intr_status, hpdi_board_status; + uint32_t plx_status; + uint32_t plx_bits; + uint8_t dma0_status, dma1_status; + unsigned long flags; + + if (!dev->attached) + return IRQ_NONE; + + plx_status = readl(devpriv->plx9080_mmio + PLX_INTRCS_REG); + if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0) + return IRQ_NONE; + + hpdi_intr_status = readl(devpriv->mmio + INTERRUPT_STATUS_REG); + hpdi_board_status = readl(devpriv->mmio + BOARD_STATUS_REG); + + if (hpdi_intr_status) + writel(hpdi_intr_status, devpriv->mmio + INTERRUPT_STATUS_REG); + + /* spin lock makes sure no one else changes plx dma control reg */ + spin_lock_irqsave(&dev->spinlock, flags); + dma0_status = readb(devpriv->plx9080_mmio + PLX_DMA0_CS_REG); + if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ + writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, + devpriv->plx9080_mmio + PLX_DMA0_CS_REG); + + if (dma0_status & PLX_DMA_EN_BIT) + gsc_hpdi_drain_dma(dev, 0); + } + spin_unlock_irqrestore(&dev->spinlock, flags); + + /* spin lock makes sure no one else changes plx dma control reg */ + spin_lock_irqsave(&dev->spinlock, flags); + dma1_status = readb(devpriv->plx9080_mmio + PLX_DMA1_CS_REG); + if (plx_status & ICS_DMA1_A) { /* XXX *//* dma chan 1 interrupt */ + writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, + devpriv->plx9080_mmio + PLX_DMA1_CS_REG); + } + spin_unlock_irqrestore(&dev->spinlock, flags); + + /* clear possible plx9080 interrupt sources */ + if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ + plx_bits = readl(devpriv->plx9080_mmio + PLX_DBR_OUT_REG); + writel(plx_bits, devpriv->plx9080_mmio + PLX_DBR_OUT_REG); + } + + if (hpdi_board_status & RX_OVERRUN_BIT) { + dev_err(dev->class_dev, "rx fifo overrun\n"); + async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + } + + if (hpdi_board_status & RX_UNDERRUN_BIT) { + dev_err(dev->class_dev, "rx fifo underrun\n"); + async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + } + + if (devpriv->dio_count == 0) + async->events |= COMEDI_CB_EOA; + + cfc_handle_events(dev, s); + + return IRQ_HANDLED; +} + +static void gsc_hpdi_abort_dma(struct comedi_device *dev, unsigned int channel) +{ + struct hpdi_private *devpriv = dev->private; + unsigned long flags; + + /* spinlock for plx dma control/status reg */ + spin_lock_irqsave(&dev->spinlock, flags); + + plx9080_abort_dma(devpriv->plx9080_mmio, channel); + + spin_unlock_irqrestore(&dev->spinlock, flags); +} + +static int gsc_hpdi_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct hpdi_private *devpriv = dev->private; + + writel(0, devpriv->mmio + BOARD_CONTROL_REG); + writel(0, devpriv->mmio + INTERRUPT_CONTROL_REG); + + gsc_hpdi_abort_dma(dev, 0); + + return 0; +} + +static int gsc_hpdi_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct hpdi_private *devpriv = dev->private; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned long flags; + uint32_t bits; + + if (s->io_bits) + return -EINVAL; + + writel(RX_FIFO_RESET_BIT, devpriv->mmio + BOARD_CONTROL_REG); + + gsc_hpdi_abort_dma(dev, 0); + + devpriv->dma_desc_index = 0; + + /* + * These register are supposedly unused during chained dma, + * but I have found that left over values from last operation + * occasionally cause problems with transfer of first dma + * block. Initializing them to zero seems to fix the problem. + */ + writel(0, devpriv->plx9080_mmio + PLX_DMA0_TRANSFER_SIZE_REG); + writel(0, devpriv->plx9080_mmio + PLX_DMA0_PCI_ADDRESS_REG); + writel(0, devpriv->plx9080_mmio + PLX_DMA0_LOCAL_ADDRESS_REG); + + /* give location of first dma descriptor */ + bits = devpriv->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT | + PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI; + writel(bits, devpriv->plx9080_mmio + PLX_DMA0_DESCRIPTOR_REG); + + /* enable dma transfer */ + spin_lock_irqsave(&dev->spinlock, flags); + writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, + devpriv->plx9080_mmio + PLX_DMA0_CS_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); + + if (cmd->stop_src == TRIG_COUNT) + devpriv->dio_count = cmd->stop_arg; + else + devpriv->dio_count = 1; + + /* clear over/under run status flags */ + writel(RX_UNDERRUN_BIT | RX_OVERRUN_BIT, + devpriv->mmio + BOARD_STATUS_REG); + + /* enable interrupts */ + writel(RX_FULL_INTR, devpriv->mmio + INTERRUPT_CONTROL_REG); + + writel(RX_ENABLE_BIT, devpriv->mmio + BOARD_CONTROL_REG); + + return 0; +} + +static int gsc_hpdi_cmd_test(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + int err = 0; + int i; + + if (s->io_bits) + return -EINVAL; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ + + if (err) + return 2; + + /* Step 3: check if arguments are trivially valid */ + + if (!cmd->chanlist_len || !cmd->chanlist) { + cmd->chanlist_len = 32; + err |= -EINVAL; + } + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + + if (err) + return 3; + + /* step 4: fix up any arguments */ + + if (err) + return 4; + + /* step 5: complain about special chanlist considerations */ + + for (i = 0; i < cmd->chanlist_len; i++) { + if (CR_CHAN(cmd->chanlist[i]) != i) { + /* XXX could support 8 or 16 channels */ + dev_err(dev->class_dev, + "chanlist must be ch 0 to 31 in order"); + err |= -EINVAL; + break; + } + } + + if (err) + return 5; + + return 0; + +} + +/* setup dma descriptors so a link completes every 'len' bytes */ +static int gsc_hpdi_setup_dma_descriptors(struct comedi_device *dev, + unsigned int len) +{ + struct hpdi_private *devpriv = dev->private; + dma_addr_t phys_addr = devpriv->dma_desc_phys_addr; + uint32_t next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | + PLX_XFER_LOCAL_TO_PCI; + unsigned int offset = 0; + unsigned int idx = 0; + unsigned int i; + + if (len > DMA_BUFFER_SIZE) + len = DMA_BUFFER_SIZE; + len -= len % sizeof(uint32_t); + if (len == 0) + return -EINVAL; + + for (i = 0; i < NUM_DMA_DESCRIPTORS && idx < NUM_DMA_BUFFERS; i++) { + devpriv->dma_desc[i].pci_start_addr = + cpu_to_le32(devpriv->dio_buffer_phys_addr[idx] + offset); + devpriv->dma_desc[i].local_start_addr = cpu_to_le32(FIFO_REG); + devpriv->dma_desc[i].transfer_size = cpu_to_le32(len); + devpriv->dma_desc[i].next = cpu_to_le32((phys_addr + + (i + 1) * sizeof(devpriv->dma_desc[0])) | next_bits); + + devpriv->desc_dio_buffer[i] = devpriv->dio_buffer[idx] + + (offset / sizeof(uint32_t)); + + offset += len; + if (len + offset > DMA_BUFFER_SIZE) { + offset = 0; + idx++; + } + } + devpriv->num_dma_descriptors = i; + /* fix last descriptor to point back to first */ + devpriv->dma_desc[i - 1].next = cpu_to_le32(phys_addr | next_bits); + + devpriv->block_size = len; + + return len; +} + +static int gsc_hpdi_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { int ret; switch (data[0]) { case INSN_CONFIG_BLOCK_SIZE: - return dio_config_block_size(dev, data); + ret = gsc_hpdi_setup_dma_descriptors(dev, data[1]); + if (ret) + return ret; + + data[1] = ret; + break; default: ret = comedi_dio_insn_config(dev, s, insn, data, 0xffffffff); if (ret) @@ -237,31 +499,53 @@ static int dio_config_insn(struct comedi_device *dev, return insn->n; } -static void disable_plx_interrupts(struct comedi_device *dev) +static int gsc_hpdi_init(struct comedi_device *dev) { struct hpdi_private *devpriv = dev->private; + uint32_t plx_intcsr_bits; - writel(0, devpriv->plx9080_iobase + PLX_INTRCS_REG); + /* wait 10usec after reset before accessing fifos */ + writel(BOARD_RESET_BIT, devpriv->mmio + BOARD_CONTROL_REG); + udelay(10); + + writel(ALMOST_EMPTY_BITS(32) | ALMOST_FULL_BITS(32), + devpriv->mmio + RX_PROG_ALMOST_REG); + writel(ALMOST_EMPTY_BITS(32) | ALMOST_FULL_BITS(32), + devpriv->mmio + TX_PROG_ALMOST_REG); + + devpriv->tx_fifo_size = readl(devpriv->mmio + TX_FIFO_SIZE_REG) & + FIFO_SIZE_MASK; + devpriv->rx_fifo_size = readl(devpriv->mmio + RX_FIFO_SIZE_REG) & + FIFO_SIZE_MASK; + + writel(0, devpriv->mmio + INTERRUPT_CONTROL_REG); + + /* enable interrupts */ + plx_intcsr_bits = + ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | + ICS_DMA0_E; + writel(plx_intcsr_bits, devpriv->plx9080_mmio + PLX_INTRCS_REG); + + return 0; } -/* initialize plx9080 chip */ -static void init_plx9080(struct comedi_device *dev) +static void gsc_hpdi_init_plx9080(struct comedi_device *dev) { struct hpdi_private *devpriv = dev->private; uint32_t bits; - void __iomem *plx_iobase = devpriv->plx9080_iobase; + void __iomem *plx_iobase = devpriv->plx9080_mmio; #ifdef __BIG_ENDIAN bits = BIGEND_DMA0 | BIGEND_DMA1; #else bits = 0; #endif - writel(bits, devpriv->plx9080_iobase + PLX_BIGEND_REG); + writel(bits, devpriv->plx9080_mmio + PLX_BIGEND_REG); - disable_plx_interrupts(dev); + writel(0, devpriv->plx9080_mmio + PLX_INTRCS_REG); - abort_dma(dev, 0); - abort_dma(dev, 1); + gsc_hpdi_abort_dma(dev, 0); + gsc_hpdi_abort_dma(dev, 1); /* configure dma0 mode */ bits = 0; @@ -285,117 +569,7 @@ static void init_plx9080(struct comedi_device *dev) writel(bits, plx_iobase + PLX_DMA0_MODE_REG); } -/* Allocate and initialize the subdevice structures. - */ -static int setup_subdevices(struct comedi_device *dev) -{ - struct comedi_subdevice *s; - int ret; - - ret = comedi_alloc_subdevices(dev, 1); - if (ret) - return ret; - - s = &dev->subdevices[0]; - /* analog input subdevice */ - dev->read_subdev = s; -/* dev->write_subdev = s; */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = - SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL | SDF_CMD_READ; - s->n_chan = 32; - s->len_chanlist = 32; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_config = dio_config_insn; - s->do_cmd = hpdi_cmd; - s->do_cmdtest = hpdi_cmd_test; - s->cancel = hpdi_cancel; - - return 0; -} - -static int init_hpdi(struct comedi_device *dev) -{ - struct hpdi_private *devpriv = dev->private; - uint32_t plx_intcsr_bits; - - writel(BOARD_RESET_BIT, devpriv->hpdi_iobase + BOARD_CONTROL_REG); - udelay(10); - - writel(almost_empty_bits(32) | almost_full_bits(32), - devpriv->hpdi_iobase + RX_PROG_ALMOST_REG); - writel(almost_empty_bits(32) | almost_full_bits(32), - devpriv->hpdi_iobase + TX_PROG_ALMOST_REG); - - devpriv->tx_fifo_size = fifo_size(readl(devpriv->hpdi_iobase + - TX_FIFO_SIZE_REG)); - devpriv->rx_fifo_size = fifo_size(readl(devpriv->hpdi_iobase + - RX_FIFO_SIZE_REG)); - - writel(0, devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG); - - /* enable interrupts */ - plx_intcsr_bits = - ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | - ICS_DMA0_E; - writel(plx_intcsr_bits, devpriv->plx9080_iobase + PLX_INTRCS_REG); - - return 0; -} - -/* setup dma descriptors so a link completes every 'transfer_size' bytes */ -static int setup_dma_descriptors(struct comedi_device *dev, - unsigned int transfer_size) -{ - struct hpdi_private *devpriv = dev->private; - unsigned int buffer_index, buffer_offset; - uint32_t next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | - PLX_XFER_LOCAL_TO_PCI; - unsigned int i; - - if (transfer_size > DMA_BUFFER_SIZE) - transfer_size = DMA_BUFFER_SIZE; - transfer_size -= transfer_size % sizeof(uint32_t); - if (transfer_size == 0) - return -1; - - buffer_offset = 0; - buffer_index = 0; - for (i = 0; i < NUM_DMA_DESCRIPTORS && - buffer_index < NUM_DMA_BUFFERS; i++) { - devpriv->dma_desc[i].pci_start_addr = - cpu_to_le32(devpriv->dio_buffer_phys_addr[buffer_index] + - buffer_offset); - devpriv->dma_desc[i].local_start_addr = cpu_to_le32(FIFO_REG); - devpriv->dma_desc[i].transfer_size = - cpu_to_le32(transfer_size); - devpriv->dma_desc[i].next = - cpu_to_le32((devpriv->dma_desc_phys_addr + (i + - 1) * - sizeof(devpriv->dma_desc[0])) | next_bits); - - devpriv->desc_dio_buffer[i] = - devpriv->dio_buffer[buffer_index] + - (buffer_offset / sizeof(uint32_t)); - - buffer_offset += transfer_size; - if (transfer_size + buffer_offset > DMA_BUFFER_SIZE) { - buffer_offset = 0; - buffer_index++; - } - } - devpriv->num_dma_descriptors = i; - /* fix last descriptor to point back to first */ - devpriv->dma_desc[i - 1].next = - cpu_to_le32(devpriv->dma_desc_phys_addr | next_bits); - - devpriv->block_size = transfer_size; - - return transfer_size; -} - -static const struct hpdi_board *hpdi_find_board(struct pci_dev *pcidev) +static const struct hpdi_board *gsc_hpdi_find_board(struct pci_dev *pcidev) { unsigned int i; @@ -406,16 +580,17 @@ static const struct hpdi_board *hpdi_find_board(struct pci_dev *pcidev) return NULL; } -static int hpdi_auto_attach(struct comedi_device *dev, - unsigned long context_unused) +static int gsc_hpdi_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); const struct hpdi_board *thisboard; struct hpdi_private *devpriv; + struct comedi_subdevice *s; int i; int retval; - thisboard = hpdi_find_board(pcidev); + thisboard = gsc_hpdi_find_board(pcidev); if (!thisboard) { dev_err(dev->class_dev, "gsc_hpdi: pci %s not supported\n", pci_name(pcidev)); @@ -433,17 +608,17 @@ static int hpdi_auto_attach(struct comedi_device *dev, return retval; pci_set_master(pcidev); - devpriv->plx9080_iobase = pci_ioremap_bar(pcidev, 0); - devpriv->hpdi_iobase = pci_ioremap_bar(pcidev, 2); - if (!devpriv->plx9080_iobase || !devpriv->hpdi_iobase) { + devpriv->plx9080_mmio = pci_ioremap_bar(pcidev, 0); + devpriv->mmio = pci_ioremap_bar(pcidev, 2); + if (!devpriv->plx9080_mmio || !devpriv->mmio) { dev_warn(dev->class_dev, "failed to remap io memory\n"); return -ENOMEM; } - init_plx9080(dev); + gsc_hpdi_init_plx9080(dev); /* get irq */ - if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED, + if (request_irq(pcidev->irq, gsc_hpdi_interrupt, IRQF_SHARED, dev->board_name, dev)) { dev_warn(dev->class_dev, "unable to allocate irq %u\n", pcidev->irq); @@ -470,18 +645,33 @@ static int hpdi_auto_attach(struct comedi_device *dev, return -EIO; } - retval = setup_dma_descriptors(dev, 0x1000); + retval = gsc_hpdi_setup_dma_descriptors(dev, 0x1000); if (retval < 0) return retval; - retval = setup_subdevices(dev); - if (retval < 0) + retval = comedi_alloc_subdevices(dev, 1); + if (retval) return retval; - return init_hpdi(dev); + /* Digital I/O subdevice */ + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL | + SDF_CMD_READ; + s->n_chan = 32; + s->len_chanlist = 32; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_config = gsc_hpdi_dio_insn_config; + s->do_cmd = gsc_hpdi_cmd; + s->do_cmdtest = gsc_hpdi_cmd_test; + s->cancel = gsc_hpdi_cancel; + + return gsc_hpdi_init(dev); } -static void hpdi_detach(struct comedi_device *dev) +static void gsc_hpdi_detach(struct comedi_device *dev) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct hpdi_private *devpriv = dev->private; @@ -490,12 +680,12 @@ static void hpdi_detach(struct comedi_device *dev) if (dev->irq) free_irq(dev->irq, dev); if (devpriv) { - if (devpriv->plx9080_iobase) { - disable_plx_interrupts(dev); - iounmap(devpriv->plx9080_iobase); + if (devpriv->plx9080_mmio) { + writel(0, devpriv->plx9080_mmio + PLX_INTRCS_REG); + iounmap(devpriv->plx9080_mmio); } - if (devpriv->hpdi_iobase) - iounmap(devpriv->hpdi_iobase); + if (devpriv->mmio) + iounmap(devpriv->mmio); /* free pci dma buffers */ for (i = 0; i < NUM_DMA_BUFFERS; i++) { if (devpriv->dio_buffer[i]) @@ -516,318 +706,11 @@ static void hpdi_detach(struct comedi_device *dev) comedi_pci_disable(dev); } -static int dio_config_block_size(struct comedi_device *dev, unsigned int *data) -{ - unsigned int requested_block_size; - int retval; - - requested_block_size = data[1]; - - retval = setup_dma_descriptors(dev, requested_block_size); - if (retval < 0) - return retval; - - data[1] = retval; - - return 2; -} - -static int di_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - int err = 0; - int i; - - /* Step 1 : check if triggers are trivially valid */ - - err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); - err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); - err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); - err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - - if (err) - return 1; - - /* Step 2a : make sure trigger sources are unique */ - - err |= cfc_check_trigger_is_unique(cmd->stop_src); - - /* Step 2b : and mutually compatible */ - - if (err) - return 2; - - /* Step 3: check if arguments are trivially valid */ - - if (!cmd->chanlist_len) { - cmd->chanlist_len = 32; - err |= -EINVAL; - } - err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - - switch (cmd->stop_src) { - case TRIG_COUNT: - err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); - break; - case TRIG_NONE: - err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - break; - default: - break; - } - - if (err) - return 3; - - /* step 4: fix up any arguments */ - - if (err) - return 4; - - if (!cmd->chanlist) - return 0; - - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != i) { - /* XXX could support 8 or 16 channels */ - comedi_error(dev, - "chanlist must be ch 0 to 31 in order"); - err++; - break; - } - } - - if (err) - return 5; - - return 0; -} - -static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - if (s->io_bits) - return -EINVAL; - else - return di_cmd_test(dev, s, cmd); -} - -static inline void hpdi_writel(struct comedi_device *dev, uint32_t bits, - unsigned int offset) -{ - struct hpdi_private *devpriv = dev->private; - - writel(bits | devpriv->bits[offset / sizeof(uint32_t)], - devpriv->hpdi_iobase + offset); -} - -static int di_cmd(struct comedi_device *dev, struct comedi_subdevice *s) -{ - struct hpdi_private *devpriv = dev->private; - uint32_t bits; - unsigned long flags; - struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &async->cmd; - - hpdi_writel(dev, RX_FIFO_RESET_BIT, BOARD_CONTROL_REG); - - abort_dma(dev, 0); - - devpriv->dma_desc_index = 0; - - /* These register are supposedly unused during chained dma, - * but I have found that left over values from last operation - * occasionally cause problems with transfer of first dma - * block. Initializing them to zero seems to fix the problem. */ - writel(0, devpriv->plx9080_iobase + PLX_DMA0_TRANSFER_SIZE_REG); - writel(0, devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG); - writel(0, devpriv->plx9080_iobase + PLX_DMA0_LOCAL_ADDRESS_REG); - /* give location of first dma descriptor */ - bits = - devpriv->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT | - PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI; - writel(bits, devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG); - - /* spinlock for plx dma control/status reg */ - spin_lock_irqsave(&dev->spinlock, flags); - /* enable dma transfer */ - writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA0_CS_REG); - spin_unlock_irqrestore(&dev->spinlock, flags); - - if (cmd->stop_src == TRIG_COUNT) - devpriv->dio_count = cmd->stop_arg; - else - devpriv->dio_count = 1; - - /* clear over/under run status flags */ - writel(RX_UNDERRUN_BIT | RX_OVERRUN_BIT, - devpriv->hpdi_iobase + BOARD_STATUS_REG); - /* enable interrupts */ - writel(intr_bit(RX_FULL_INTR), - devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG); - - hpdi_writel(dev, RX_ENABLE_BIT, BOARD_CONTROL_REG); - - return 0; -} - -static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s) -{ - if (s->io_bits) - return -EINVAL; - else - return di_cmd(dev, s); -} - -static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel) -{ - struct hpdi_private *devpriv = dev->private; - struct comedi_async *async = dev->read_subdev->async; - uint32_t next_transfer_addr; - int j; - int num_samples = 0; - void __iomem *pci_addr_reg; - - if (channel) - pci_addr_reg = - devpriv->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG; - else - pci_addr_reg = - devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG; - - /* loop until we have read all the full buffers */ - j = 0; - for (next_transfer_addr = readl(pci_addr_reg); - (next_transfer_addr < - le32_to_cpu(devpriv->dma_desc[devpriv->dma_desc_index]. - pci_start_addr) - || next_transfer_addr >= - le32_to_cpu(devpriv->dma_desc[devpriv->dma_desc_index]. - pci_start_addr) + devpriv->block_size) - && j < devpriv->num_dma_descriptors; j++) { - /* transfer data from dma buffer to comedi buffer */ - num_samples = devpriv->block_size / sizeof(uint32_t); - if (async->cmd.stop_src == TRIG_COUNT) { - if (num_samples > devpriv->dio_count) - num_samples = devpriv->dio_count; - devpriv->dio_count -= num_samples; - } - cfc_write_array_to_buffer(dev->read_subdev, - devpriv->desc_dio_buffer[devpriv-> - dma_desc_index], - num_samples * sizeof(uint32_t)); - devpriv->dma_desc_index++; - devpriv->dma_desc_index %= devpriv->num_dma_descriptors; - } - /* XXX check for buffer overrun somehow */ -} - -static irqreturn_t handle_interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - struct hpdi_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - struct comedi_async *async = s->async; - uint32_t hpdi_intr_status, hpdi_board_status; - uint32_t plx_status; - uint32_t plx_bits; - uint8_t dma0_status, dma1_status; - unsigned long flags; - - if (!dev->attached) - return IRQ_NONE; - - plx_status = readl(devpriv->plx9080_iobase + PLX_INTRCS_REG); - if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0) - return IRQ_NONE; - - hpdi_intr_status = readl(devpriv->hpdi_iobase + INTERRUPT_STATUS_REG); - hpdi_board_status = readl(devpriv->hpdi_iobase + BOARD_STATUS_REG); - - async->events = 0; - - if (hpdi_intr_status) { - writel(hpdi_intr_status, - devpriv->hpdi_iobase + INTERRUPT_STATUS_REG); - } - /* spin lock makes sure no one else changes plx dma control reg */ - spin_lock_irqsave(&dev->spinlock, flags); - dma0_status = readb(devpriv->plx9080_iobase + PLX_DMA0_CS_REG); - if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ - writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA0_CS_REG); - - if (dma0_status & PLX_DMA_EN_BIT) - drain_dma_buffers(dev, 0); - } - spin_unlock_irqrestore(&dev->spinlock, flags); - - /* spin lock makes sure no one else changes plx dma control reg */ - spin_lock_irqsave(&dev->spinlock, flags); - dma1_status = readb(devpriv->plx9080_iobase + PLX_DMA1_CS_REG); - if (plx_status & ICS_DMA1_A) { /* XXX *//* dma chan 1 interrupt */ - writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, - devpriv->plx9080_iobase + PLX_DMA1_CS_REG); - } - spin_unlock_irqrestore(&dev->spinlock, flags); - - /* clear possible plx9080 interrupt sources */ - if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ - plx_bits = readl(devpriv->plx9080_iobase + PLX_DBR_OUT_REG); - writel(plx_bits, devpriv->plx9080_iobase + PLX_DBR_OUT_REG); - } - - if (hpdi_board_status & RX_OVERRUN_BIT) { - comedi_error(dev, "rx fifo overrun"); - async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - } - - if (hpdi_board_status & RX_UNDERRUN_BIT) { - comedi_error(dev, "rx fifo underrun"); - async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - } - - if (devpriv->dio_count == 0) - async->events |= COMEDI_CB_EOA; - - cfc_handle_events(dev, s); - - return IRQ_HANDLED; -} - -static void abort_dma(struct comedi_device *dev, unsigned int channel) -{ - struct hpdi_private *devpriv = dev->private; - unsigned long flags; - - /* spinlock for plx dma control/status reg */ - spin_lock_irqsave(&dev->spinlock, flags); - - plx9080_abort_dma(devpriv->plx9080_iobase, channel); - - spin_unlock_irqrestore(&dev->spinlock, flags); -} - -static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s) -{ - struct hpdi_private *devpriv = dev->private; - - hpdi_writel(dev, 0, BOARD_CONTROL_REG); - - writel(0, devpriv->hpdi_iobase + INTERRUPT_CONTROL_REG); - - abort_dma(dev, 0); - - return 0; -} - static struct comedi_driver gsc_hpdi_driver = { .driver_name = "gsc_hpdi", .module = THIS_MODULE, - .auto_attach = hpdi_auto_attach, - .detach = hpdi_detach, + .auto_attach = gsc_hpdi_auto_attach, + .detach = gsc_hpdi_detach, }; static int gsc_hpdi_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c index 80539b2bea1a..0b8b2162b76b 100644 --- a/drivers/staging/comedi/drivers/icp_multi.c +++ b/drivers/staging/comedi/drivers/icp_multi.c @@ -171,12 +171,27 @@ static void setup_channel_list(struct comedi_device *dev, } } +static int icp_multi_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct icp_multi_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->io_addr + ICP_MULTI_ADC_CSR); + if ((status & ADC_BSY) == 0) + return 0; + return -EBUSY; +} + static int icp_multi_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct icp_multi_private *devpriv = dev->private; - int n, timeout; + int ret = 0; + int n; /* Disable A/D conversion ready interrupt */ devpriv->IntEnable &= ~ADC_READY; @@ -199,33 +214,10 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev, udelay(1); /* Wait for conversion to complete, or get fed up waiting */ - timeout = 100; - while (timeout--) { - if (!(readw(devpriv->io_addr + - ICP_MULTI_ADC_CSR) & ADC_BSY)) - goto conv_finish; + ret = comedi_timeout(dev, s, insn, icp_multi_ai_eoc, 0); + if (ret) + break; - udelay(1); - } - - /* If we reach here, a timeout has occurred */ - comedi_error(dev, "A/D insn timeout"); - - /* Disable interrupt */ - devpriv->IntEnable &= ~ADC_READY; - writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= ADC_READY; - writew(devpriv->IntStatus, - devpriv->io_addr + ICP_MULTI_INT_STAT); - - /* Clear data received */ - data[n] = 0; - - return -ETIME; - -conv_finish: data[n] = (readw(devpriv->io_addr + ICP_MULTI_AI) >> 4) & 0x0fff; } @@ -238,7 +230,21 @@ conv_finish: devpriv->IntStatus |= ADC_READY; writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT); - return n; + return ret ? ret : n; +} + +static int icp_multi_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct icp_multi_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->io_addr + ICP_MULTI_DAC_CSR); + if ((status & DAC_BSY) == 0) + return 0; + return -EBUSY; } static int icp_multi_insn_write_ao(struct comedi_device *dev, @@ -246,7 +252,8 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { struct icp_multi_private *devpriv = dev->private; - int n, chan, range, timeout; + int n, chan, range; + int ret; /* Disable D/A conversion ready interrupt */ devpriv->IntEnable &= ~DAC_READY; @@ -274,33 +281,24 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { /* Wait for analogue output data register to be * ready for new data, or get fed up waiting */ - timeout = 100; - while (timeout--) { - if (!(readw(devpriv->io_addr + - ICP_MULTI_DAC_CSR) & DAC_BSY)) - goto dac_ready; + ret = comedi_timeout(dev, s, insn, icp_multi_ao_eoc, 0); + if (ret) { + /* Disable interrupt */ + devpriv->IntEnable &= ~DAC_READY; + writew(devpriv->IntEnable, + devpriv->io_addr + ICP_MULTI_INT_EN); - udelay(1); + /* Clear interrupt status */ + devpriv->IntStatus |= DAC_READY; + writew(devpriv->IntStatus, + devpriv->io_addr + ICP_MULTI_INT_STAT); + + /* Clear data received */ + devpriv->ao_data[chan] = 0; + + return ret; } - /* If we reach here, a timeout has occurred */ - comedi_error(dev, "D/A insn timeout"); - - /* Disable interrupt */ - devpriv->IntEnable &= ~DAC_READY; - writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= DAC_READY; - writew(devpriv->IntStatus, - devpriv->io_addr + ICP_MULTI_INT_STAT); - - /* Clear data received */ - devpriv->ao_data[chan] = 0; - - return -ETIME; - -dac_ready: /* Write data to analogue output data register */ writew(data[n], devpriv->io_addr + ICP_MULTI_AO); @@ -565,9 +563,6 @@ static int icp_multi_auto_attach(struct comedi_device *dev, devpriv->valid = 1; - dev_info(dev->class_dev, "%s attached, irq %sabled\n", - dev->board_name, dev->irq ? "en" : "dis"); - return 0; } diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c index 8577778441fa..3558ab3b6e1f 100644 --- a/drivers/staging/comedi/drivers/ii_pci20kc.c +++ b/drivers/staging/comedi/drivers/ii_pci20kc.c @@ -190,20 +190,18 @@ static int ii20k_ao_insn_write(struct comedi_device *dev, return insn->n; } -static int ii20k_ai_wait_eoc(struct comedi_device *dev, - struct comedi_subdevice *s, - int timeout) +static int ii20k_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { void __iomem *iobase = ii20k_module_iobase(dev, s); unsigned char status; - do { - status = readb(iobase + II20K_AI_STATUS_REG); - if ((status & II20K_AI_STATUS_INT) == 0) - return 0; - } while (timeout--); - - return -ETIME; + status = readb(iobase + II20K_AI_STATUS_REG); + if ((status & II20K_AI_STATUS_INT) == 0) + return 0; + return -EBUSY; } static void ii20k_ai_setup(struct comedi_device *dev, @@ -263,7 +261,7 @@ static int ii20k_ai_insn_read(struct comedi_device *dev, /* generate a software start convert signal */ readb(iobase + II20K_AI_PACER_RESET_REG); - ret = ii20k_ai_wait_eoc(dev, s, 100); + ret = comedi_timeout(dev, s, insn, ii20k_ai_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index 6100c12c164f..a8db9d86aadc 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -51,23 +51,55 @@ #include "jr3_pci.h" #define PCI_VENDOR_ID_JR3 0x1762 -#define PCI_DEVICE_ID_JR3_1_CHANNEL 0x3111 -#define PCI_DEVICE_ID_JR3_1_CHANNEL_NEW 0x1111 -#define PCI_DEVICE_ID_JR3_2_CHANNEL 0x3112 -#define PCI_DEVICE_ID_JR3_3_CHANNEL 0x3113 -#define PCI_DEVICE_ID_JR3_4_CHANNEL 0x3114 + +enum jr3_pci_boardid { + BOARD_JR3_1, + BOARD_JR3_2, + BOARD_JR3_3, + BOARD_JR3_4, +}; + +struct jr3_pci_board { + const char *name; + int n_subdevs; +}; + +static const struct jr3_pci_board jr3_pci_boards[] = { + [BOARD_JR3_1] = { + .name = "jr3_pci_1", + .n_subdevs = 1, + }, + [BOARD_JR3_2] = { + .name = "jr3_pci_2", + .n_subdevs = 2, + }, + [BOARD_JR3_3] = { + .name = "jr3_pci_3", + .n_subdevs = 3, + }, + [BOARD_JR3_4] = { + .name = "jr3_pci_4", + .n_subdevs = 4, + }, +}; + +struct jr3_pci_transform { + struct { + u16 link_type; + s16 link_amount; + } link[8]; +}; + +struct jr3_pci_poll_delay { + int min; + int max; +}; struct jr3_pci_dev_private { struct jr3_t __iomem *iobase; - int n_channels; struct timer_list timer; }; -struct poll_delay_t { - int min; - int max; -}; - struct jr3_pci_subdev_private { struct jr3_channel __iomem *channel; unsigned long next_time_min; @@ -79,7 +111,6 @@ struct jr3_pci_subdev_private { state_jr3_init_use_offset_complete, state_jr3_done } state; - int channel_no; int serial_no; int model_no; struct { @@ -92,9 +123,9 @@ struct jr3_pci_subdev_private { int retries; }; -static struct poll_delay_t poll_delay_min_max(int min, int max) +static struct jr3_pci_poll_delay poll_delay_min_max(int min, int max) { - struct poll_delay_t result; + struct jr3_pci_poll_delay result; result.min = min; result.max = max; @@ -106,15 +137,8 @@ static int is_complete(struct jr3_channel __iomem *channel) return get_s16(&channel->command_word0) == 0; } -struct transform_t { - struct { - u16 link_type; - s16 link_amount; - } link[8]; -}; - static void set_transforms(struct jr3_channel __iomem *channel, - struct transform_t transf, short num) + struct jr3_pci_transform transf, short num) { int i; @@ -194,110 +218,99 @@ static struct six_axis_t get_max_full_scales(struct jr3_channel __iomem return result; } +static unsigned int jr3_pci_ai_read_chan(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan) +{ + struct jr3_pci_subdev_private *spriv = s->private; + unsigned int val = 0; + + if (spriv->state != state_jr3_done) + return 0; + + if (chan < 56) { + unsigned int axis = chan % 8; + unsigned filter = chan / 8; + + switch (axis) { + case 0: + val = get_s16(&spriv->channel->filter[filter].fx); + break; + case 1: + val = get_s16(&spriv->channel->filter[filter].fy); + break; + case 2: + val = get_s16(&spriv->channel->filter[filter].fz); + break; + case 3: + val = get_s16(&spriv->channel->filter[filter].mx); + break; + case 4: + val = get_s16(&spriv->channel->filter[filter].my); + break; + case 5: + val = get_s16(&spriv->channel->filter[filter].mz); + break; + case 6: + val = get_s16(&spriv->channel->filter[filter].v1); + break; + case 7: + val = get_s16(&spriv->channel->filter[filter].v2); + break; + } + val += 0x4000; + } else if (chan == 56) { + val = get_u16(&spriv->channel->model_no); + } else if (chan == 57) { + val = get_u16(&spriv->channel->serial_no); + } + + return val; +} + static int jr3_pci_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int result; - struct jr3_pci_subdev_private *p; - int channel; + struct jr3_pci_subdev_private *spriv = s->private; + unsigned int chan = CR_CHAN(insn->chanspec); + u16 errors; + int i; - p = s->private; - channel = CR_CHAN(insn->chanspec); - if (p == NULL || channel > 57) { - result = -EINVAL; - } else { - int i; + if (!spriv) + return -EINVAL; - result = insn->n; - if (p->state != state_jr3_done || - (get_u16(&p->channel->errors) & (watch_dog | watch_dog2 | - sensor_change))) { - /* No sensor or sensor changed */ - if (p->state == state_jr3_done) { - /* Restart polling */ - p->state = state_jr3_poll; - } - result = -EAGAIN; - } - for (i = 0; i < insn->n; i++) { - if (channel < 56) { - int axis, filter; - - axis = channel % 8; - filter = channel / 8; - if (p->state != state_jr3_done) { - data[i] = 0; - } else { - int F = 0; - switch (axis) { - case 0: - F = get_s16(&p->channel-> - filter[filter].fx); - break; - case 1: - F = get_s16(&p->channel-> - filter[filter].fy); - break; - case 2: - F = get_s16(&p->channel-> - filter[filter].fz); - break; - case 3: - F = get_s16(&p->channel-> - filter[filter].mx); - break; - case 4: - F = get_s16(&p->channel-> - filter[filter].my); - break; - case 5: - F = get_s16(&p->channel-> - filter[filter].mz); - break; - case 6: - F = get_s16(&p->channel-> - filter[filter].v1); - break; - case 7: - F = get_s16(&p->channel-> - filter[filter].v2); - break; - } - data[i] = F + 0x4000; - } - } else if (channel == 56) { - if (p->state != state_jr3_done) - data[i] = 0; - else - data[i] = - get_u16(&p->channel->model_no); - } else if (channel == 57) { - if (p->state != state_jr3_done) - data[i] = 0; - else - data[i] = - get_u16(&p->channel->serial_no); - } + errors = get_u16(&spriv->channel->errors); + if (spriv->state != state_jr3_done || + (errors & (watch_dog | watch_dog2 | sensor_change))) { + /* No sensor or sensor changed */ + if (spriv->state == state_jr3_done) { + /* Restart polling */ + spriv->state = state_jr3_poll; } + return -EAGAIN; } - return result; + + for (i = 0; i < insn->n; i++) + data[i] = jr3_pci_ai_read_chan(dev, s, chan); + + return insn->n; } static int jr3_pci_open(struct comedi_device *dev) { + struct jr3_pci_subdev_private *spriv; + struct comedi_subdevice *s; int i; - struct jr3_pci_dev_private *devpriv = dev->private; dev_dbg(dev->class_dev, "jr3_pci_open\n"); - for (i = 0; i < devpriv->n_channels; i++) { - struct jr3_pci_subdev_private *p; - - p = dev->subdevices[i].private; - if (p) { - dev_dbg(dev->class_dev, "serial: %p %d (%d)\n", p, - p->serial_no, p->channel_no); - } + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + spriv = s->private; + if (spriv) + dev_dbg(dev->class_dev, "serial: %p %d (%d)\n", + spriv, spriv->serial_no, s->index); } return 0; } @@ -326,271 +339,262 @@ static int read_idm_word(const u8 *data, size_t size, int *pos, return result; } -static int jr3_download_firmware(struct comedi_device *dev, - const u8 *data, size_t size, - unsigned long context) +static int jr3_check_firmware(struct comedi_device *dev, + const u8 *data, size_t size) { + int more = 1; + int pos = 0; + /* * IDM file format is: * { count, address, data } * * ffff */ - int result, more, pos, OK; - - result = 0; - more = 1; - pos = 0; - OK = 0; while (more) { - unsigned int count, addr; + unsigned int count = 0; + unsigned int addr = 0; more = more && read_idm_word(data, size, &pos, &count); - if (more && count == 0xffff) { - OK = 1; - break; - } + if (more && count == 0xffff) + return 0; + more = more && read_idm_word(data, size, &pos, &addr); while (more && count > 0) { - unsigned int dummy; + unsigned int dummy = 0; + more = more && read_idm_word(data, size, &pos, &dummy); count--; } } - if (!OK) { - result = -ENODATA; - } else { - int i; - struct jr3_pci_dev_private *p = dev->private; - - for (i = 0; i < p->n_channels; i++) { - struct jr3_pci_subdev_private *sp; - - sp = dev->subdevices[i].private; - more = 1; - pos = 0; - while (more) { - unsigned int count, addr; - more = more && - read_idm_word(data, size, &pos, &count); - if (more && count == 0xffff) - break; - more = more && - read_idm_word(data, size, &pos, &addr); - dev_dbg(dev->class_dev, - "Loading#%d %4.4x bytes at %4.4x\n", - i, count, addr); - while (more && count > 0) { - if (addr & 0x4000) { - /* 16 bit data, never seen - * in real life!! */ - unsigned int data1; - - more = more && - read_idm_word(data, - size, &pos, - &data1); - count--; - /* jr3[addr + 0x20000 * pnum] = - data1; */ - } else { - /* Download 24 bit program */ - unsigned int data1, data2; - - more = more && - read_idm_word(data, - size, &pos, - &data1); - more = more && - read_idm_word(data, size, - &pos, - &data2); - count -= 2; - if (more) { - set_u16(&p-> - iobase->channel - [i].program_low - [addr], data1); - udelay(1); - set_u16(&p-> - iobase->channel - [i].program_high - [addr], data2); - udelay(1); - } - } - addr++; - } - } - } - } - return result; + return -ENODATA; } -static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice *s) +static void jr3_write_firmware(struct comedi_device *dev, + int subdev, const u8 *data, size_t size) { - struct poll_delay_t result = poll_delay_min_max(1000, 2000); - struct jr3_pci_subdev_private *p = s->private; - int i; + struct jr3_pci_dev_private *devpriv = dev->private; + struct jr3_t __iomem *iobase = devpriv->iobase; + u32 __iomem *lo; + u32 __iomem *hi; + int more = 1; + int pos = 0; - if (p) { - struct jr3_channel __iomem *channel = p->channel; - int errors = get_u16(&channel->errors); + while (more) { + unsigned int count = 0; + unsigned int addr = 0; - if (errors != p->errors) - p->errors = errors; + more = more && read_idm_word(data, size, &pos, &count); + if (more && count == 0xffff) + return; - if (errors & (watch_dog | watch_dog2 | sensor_change)) - /* Sensor communication lost, force poll mode */ - p->state = state_jr3_poll; + more = more && read_idm_word(data, size, &pos, &addr); - switch (p->state) { - case state_jr3_poll: { - u16 model_no = get_u16(&channel->model_no); - u16 serial_no = get_u16(&channel->serial_no); - if ((errors & (watch_dog | watch_dog2)) || - model_no == 0 || serial_no == 0) { - /* - * Still no sensor, keep on polling. - * Since it takes up to 10 seconds - * for offsets to stabilize, polling - * each second should suffice. - */ - result = poll_delay_min_max(1000, 2000); - } else { - p->retries = 0; - p->state = - state_jr3_init_wait_for_offset; - result = poll_delay_min_max(1000, 2000); + dev_dbg(dev->class_dev, "Loading#%d %4.4x bytes at %4.4x\n", + subdev, count, addr); + + while (more && count > 0) { + if (addr & 0x4000) { + /* 16 bit data, never seen in real life!! */ + unsigned int data1 = 0; + + more = more && + read_idm_word(data, size, &pos, &data1); + count--; + /* jr3[addr + 0x20000 * pnum] = data1; */ + } else { + /* Download 24 bit program */ + unsigned int data1 = 0; + unsigned int data2 = 0; + + lo = &iobase->channel[subdev].program_lo[addr]; + hi = &iobase->channel[subdev].program_hi[addr]; + + more = more && + read_idm_word(data, size, &pos, &data1); + more = more && + read_idm_word(data, size, &pos, &data2); + count -= 2; + if (more) { + set_u16(lo, data1); + udelay(1); + set_u16(hi, data2); + udelay(1); } } - break; - case state_jr3_init_wait_for_offset: - p->retries++; - if (p->retries < 10) { - /* Wait for offeset to stabilize - * (< 10 s according to manual) */ - result = poll_delay_min_max(1000, 2000); - } else { - struct transform_t transf; - - p->model_no = get_u16(&channel->model_no); - p->serial_no = get_u16(&channel->serial_no); - - /* Transformation all zeros */ - for (i = 0; i < ARRAY_SIZE(transf.link); i++) { - transf.link[i].link_type = - (enum link_types)0; - transf.link[i].link_amount = 0; - } - - set_transforms(channel, transf, 0); - use_transform(channel, 0); - p->state = state_jr3_init_transform_complete; - /* Allow 20 ms for completion */ - result = poll_delay_min_max(20, 100); - } - break; - case state_jr3_init_transform_complete: - if (!is_complete(channel)) { - result = poll_delay_min_max(20, 100); - } else { - /* Set full scale */ - struct six_axis_t min_full_scale; - struct six_axis_t max_full_scale; - - min_full_scale = get_min_full_scales(channel); - max_full_scale = get_max_full_scales(channel); - set_full_scales(channel, max_full_scale); - - p->state = - state_jr3_init_set_full_scale_complete; - /* Allow 20 ms for completion */ - result = poll_delay_min_max(20, 100); - } - break; - case state_jr3_init_set_full_scale_complete: - if (!is_complete(channel)) { - result = poll_delay_min_max(20, 100); - } else { - struct force_array __iomem *full_scale; - - /* Use ranges in kN or we will - * overflow around 2000N! */ - full_scale = &channel->full_scale; - p->range[0].range.min = - -get_s16(&full_scale->fx) * 1000; - p->range[0].range.max = - get_s16(&full_scale->fx) * 1000; - p->range[1].range.min = - -get_s16(&full_scale->fy) * 1000; - p->range[1].range.max = - get_s16(&full_scale->fy) * 1000; - p->range[2].range.min = - -get_s16(&full_scale->fz) * 1000; - p->range[2].range.max = - get_s16(&full_scale->fz) * 1000; - p->range[3].range.min = - -get_s16(&full_scale->mx) * 100; - p->range[3].range.max = - get_s16(&full_scale->mx) * 100; - p->range[4].range.min = - -get_s16(&full_scale->my) * 100; - p->range[4].range.max = - get_s16(&full_scale->my) * 100; - p->range[5].range.min = - -get_s16(&full_scale->mz) * 100; - p->range[5].range.max = - get_s16(&full_scale->mz) * 100; /* ?? */ - p->range[6].range.min = - -get_s16(&full_scale->v1) * 100;/* ?? */ - p->range[6].range.max = - get_s16(&full_scale->v1) * 100; /* ?? */ - p->range[7].range.min = - -get_s16(&full_scale->v2) * 100;/* ?? */ - p->range[7].range.max = - get_s16(&full_scale->v2) * 100; /* ?? */ - p->range[8].range.min = 0; - p->range[8].range.max = 65535; - - use_offset(channel, 0); - p->state = state_jr3_init_use_offset_complete; - /* Allow 40 ms for completion */ - result = poll_delay_min_max(40, 100); - } - break; - case state_jr3_init_use_offset_complete: - if (!is_complete(channel)) { - result = poll_delay_min_max(20, 100); - } else { - set_s16(&channel->offsets.fx, 0); - set_s16(&channel->offsets.fy, 0); - set_s16(&channel->offsets.fz, 0); - set_s16(&channel->offsets.mx, 0); - set_s16(&channel->offsets.my, 0); - set_s16(&channel->offsets.mz, 0); - - set_offset(channel); - - p->state = state_jr3_done; - } - break; - case state_jr3_done: - poll_delay_min_max(10000, 20000); - break; - default: - poll_delay_min_max(1000, 2000); - break; + addr++; } } +} + +static int jr3_download_firmware(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context) +{ + int subdev; + int ret; + + /* verify IDM file format */ + ret = jr3_check_firmware(dev, data, size); + if (ret) + return ret; + + /* write firmware to each subdevice */ + for (subdev = 0; subdev < dev->n_subdevices; subdev++) + jr3_write_firmware(dev, subdev, data, size); + + return 0; +} + +static struct jr3_pci_poll_delay jr3_pci_poll_subdevice(struct comedi_subdevice *s) +{ + struct jr3_pci_subdev_private *spriv = s->private; + struct jr3_pci_poll_delay result = poll_delay_min_max(1000, 2000); + struct jr3_channel __iomem *channel; + u16 model_no; + u16 serial_no; + int errors; + int i; + + if (!spriv) + return result; + + channel = spriv->channel; + errors = get_u16(&channel->errors); + + if (errors != spriv->errors) + spriv->errors = errors; + + /* Sensor communication lost? force poll mode */ + if (errors & (watch_dog | watch_dog2 | sensor_change)) + spriv->state = state_jr3_poll; + + switch (spriv->state) { + case state_jr3_poll: + model_no = get_u16(&channel->model_no); + serial_no = get_u16(&channel->serial_no); + + if ((errors & (watch_dog | watch_dog2)) || + model_no == 0 || serial_no == 0) { + /* + * Still no sensor, keep on polling. + * Since it takes up to 10 seconds for offsets to + * stabilize, polling each second should suffice. + */ + } else { + spriv->retries = 0; + spriv->state = state_jr3_init_wait_for_offset; + } + break; + case state_jr3_init_wait_for_offset: + spriv->retries++; + if (spriv->retries < 10) { + /* + * Wait for offeset to stabilize + * (< 10 s according to manual) + */ + } else { + struct jr3_pci_transform transf; + + spriv->model_no = get_u16(&channel->model_no); + spriv->serial_no = get_u16(&channel->serial_no); + + /* Transformation all zeros */ + for (i = 0; i < ARRAY_SIZE(transf.link); i++) { + transf.link[i].link_type = (enum link_types)0; + transf.link[i].link_amount = 0; + } + + set_transforms(channel, transf, 0); + use_transform(channel, 0); + spriv->state = state_jr3_init_transform_complete; + /* Allow 20 ms for completion */ + result = poll_delay_min_max(20, 100); + } + break; + case state_jr3_init_transform_complete: + if (!is_complete(channel)) { + result = poll_delay_min_max(20, 100); + } else { + /* Set full scale */ + struct six_axis_t min_full_scale; + struct six_axis_t max_full_scale; + + min_full_scale = get_min_full_scales(channel); + max_full_scale = get_max_full_scales(channel); + set_full_scales(channel, max_full_scale); + + spriv->state = state_jr3_init_set_full_scale_complete; + /* Allow 20 ms for completion */ + result = poll_delay_min_max(20, 100); + } + break; + case state_jr3_init_set_full_scale_complete: + if (!is_complete(channel)) { + result = poll_delay_min_max(20, 100); + } else { + struct force_array __iomem *fs = &channel->full_scale; + + /* Use ranges in kN or we will overflow around 2000N! */ + spriv->range[0].range.min = -get_s16(&fs->fx) * 1000; + spriv->range[0].range.max = get_s16(&fs->fx) * 1000; + spriv->range[1].range.min = -get_s16(&fs->fy) * 1000; + spriv->range[1].range.max = get_s16(&fs->fy) * 1000; + spriv->range[2].range.min = -get_s16(&fs->fz) * 1000; + spriv->range[2].range.max = get_s16(&fs->fz) * 1000; + spriv->range[3].range.min = -get_s16(&fs->mx) * 100; + spriv->range[3].range.max = get_s16(&fs->mx) * 100; + spriv->range[4].range.min = -get_s16(&fs->my) * 100; + spriv->range[4].range.max = get_s16(&fs->my) * 100; + spriv->range[5].range.min = -get_s16(&fs->mz) * 100; + /* the next five are questionable */ + spriv->range[5].range.max = get_s16(&fs->mz) * 100; + spriv->range[6].range.min = -get_s16(&fs->v1) * 100; + spriv->range[6].range.max = get_s16(&fs->v1) * 100; + spriv->range[7].range.min = -get_s16(&fs->v2) * 100; + spriv->range[7].range.max = get_s16(&fs->v2) * 100; + spriv->range[8].range.min = 0; + spriv->range[8].range.max = 65535; + + use_offset(channel, 0); + spriv->state = state_jr3_init_use_offset_complete; + /* Allow 40 ms for completion */ + result = poll_delay_min_max(40, 100); + } + break; + case state_jr3_init_use_offset_complete: + if (!is_complete(channel)) { + result = poll_delay_min_max(20, 100); + } else { + set_s16(&channel->offsets.fx, 0); + set_s16(&channel->offsets.fy, 0); + set_s16(&channel->offsets.fz, 0); + set_s16(&channel->offsets.mx, 0); + set_s16(&channel->offsets.my, 0); + set_s16(&channel->offsets.mz, 0); + + set_offset(channel); + + spriv->state = state_jr3_done; + } + break; + case state_jr3_done: + result = poll_delay_min_max(10000, 20000); + break; + default: + break; + } + return result; } static void jr3_pci_poll_dev(unsigned long data) { - unsigned long flags; struct comedi_device *dev = (struct comedi_device *)data; struct jr3_pci_dev_private *devpriv = dev->private; + struct jr3_pci_subdev_private *spriv; + struct comedi_subdevice *s; + unsigned long flags; unsigned long now; int delay; int i; @@ -598,18 +602,22 @@ static void jr3_pci_poll_dev(unsigned long data) spin_lock_irqsave(&dev->spinlock, flags); delay = 1000; now = jiffies; - /* Poll all channels that are ready to be polled */ - for (i = 0; i < devpriv->n_channels; i++) { - struct jr3_pci_subdev_private *subdevpriv = - dev->subdevices[i].private; - if (now > subdevpriv->next_time_min) { - struct poll_delay_t sub_delay; - sub_delay = jr3_pci_poll_subdevice(&dev->subdevices[i]); - subdevpriv->next_time_min = - jiffies + msecs_to_jiffies(sub_delay.min); - subdevpriv->next_time_max = - jiffies + msecs_to_jiffies(sub_delay.max); + /* Poll all channels that are ready to be polled */ + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + spriv = s->private; + + if (now > spriv->next_time_min) { + struct jr3_pci_poll_delay sub_delay; + + sub_delay = jr3_pci_poll_subdevice(s); + + spriv->next_time_min = jiffies + + msecs_to_jiffies(sub_delay.min); + spriv->next_time_max = jiffies + + msecs_to_jiffies(sub_delay.max); + if (sub_delay.max && sub_delay.max < delay) /* * Wake up as late as possible -> @@ -624,13 +632,58 @@ static void jr3_pci_poll_dev(unsigned long data) add_timer(&devpriv->timer); } -static int jr3_pci_auto_attach(struct comedi_device *dev, - unsigned long context_unused) +static struct jr3_pci_subdev_private * +jr3_pci_alloc_spriv(struct comedi_device *dev, struct comedi_subdevice *s) +{ + struct jr3_pci_dev_private *devpriv = dev->private; + struct jr3_pci_subdev_private *spriv; + int j; + int k; + + spriv = comedi_alloc_spriv(s, sizeof(*spriv)); + if (!spriv) + return NULL; + + spriv->channel = &devpriv->iobase->channel[s->index].data; + + for (j = 0; j < 8; j++) { + spriv->range[j].length = 1; + spriv->range[j].range.min = -1000000; + spriv->range[j].range.max = 1000000; + + for (k = 0; k < 7; k++) { + spriv->range_table_list[j + k * 8] = + (struct comedi_lrange *)&spriv->range[j]; + spriv->maxdata_list[j + k * 8] = 0x7fff; + } + } + spriv->range[8].length = 1; + spriv->range[8].range.min = 0; + spriv->range[8].range.max = 65536; + + spriv->range_table_list[56] = (struct comedi_lrange *)&spriv->range[8]; + spriv->range_table_list[57] = (struct comedi_lrange *)&spriv->range[8]; + spriv->maxdata_list[56] = 0xffff; + spriv->maxdata_list[57] = 0xffff; + + dev_dbg(dev->class_dev, "p->channel %p %p (%tx)\n", + spriv->channel, devpriv->iobase, + ((char __iomem *)spriv->channel - + (char __iomem *)devpriv->iobase)); + + return spriv; +} + +static int jr3_pci_auto_attach(struct comedi_device *dev, + unsigned long context) { - int result; struct pci_dev *pcidev = comedi_to_pci_dev(dev); - int i; + static const struct jr3_pci_board *board = NULL; struct jr3_pci_dev_private *devpriv; + struct jr3_pci_subdev_private *spriv; + struct comedi_subdevice *s; + int ret; + int i; if (sizeof(struct jr3_channel) != 0xc00) { dev_err(dev->class_dev, @@ -639,106 +692,56 @@ static int jr3_pci_auto_attach(struct comedi_device *dev, return -EINVAL; } + if (context < ARRAY_SIZE(jr3_pci_boards)) + board = &jr3_pci_boards[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; init_timer(&devpriv->timer); - switch (pcidev->device) { - case PCI_DEVICE_ID_JR3_1_CHANNEL: - case PCI_DEVICE_ID_JR3_1_CHANNEL_NEW: - devpriv->n_channels = 1; - break; - case PCI_DEVICE_ID_JR3_2_CHANNEL: - devpriv->n_channels = 2; - break; - case PCI_DEVICE_ID_JR3_3_CHANNEL: - devpriv->n_channels = 3; - break; - case PCI_DEVICE_ID_JR3_4_CHANNEL: - devpriv->n_channels = 4; - break; - default: - dev_err(dev->class_dev, "jr3_pci: pci %s not supported\n", - pci_name(pcidev)); - return -EINVAL; - break; - } - result = comedi_pci_enable(dev); - if (result) - return result; + ret = comedi_pci_enable(dev); + if (ret) + return ret; devpriv->iobase = pci_ioremap_bar(pcidev, 0); if (!devpriv->iobase) return -ENOMEM; - result = comedi_alloc_subdevices(dev, devpriv->n_channels); - if (result) - return result; + ret = comedi_alloc_subdevices(dev, board->n_subdevs); + if (ret) + return ret; dev->open = jr3_pci_open; - for (i = 0; i < devpriv->n_channels; i++) { - dev->subdevices[i].type = COMEDI_SUBD_AI; - dev->subdevices[i].subdev_flags = SDF_READABLE | SDF_GROUND; - dev->subdevices[i].n_chan = 8 * 7 + 2; - dev->subdevices[i].insn_read = jr3_pci_ai_insn_read; - dev->subdevices[i].private = - kzalloc(sizeof(struct jr3_pci_subdev_private), - GFP_KERNEL); - if (dev->subdevices[i].private) { - struct jr3_pci_subdev_private *p; - int j; + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 8 * 7 + 2; + s->insn_read = jr3_pci_ai_insn_read; - p = dev->subdevices[i].private; - p->channel = &devpriv->iobase->channel[i].data; - dev_dbg(dev->class_dev, "p->channel %p %p (%tx)\n", - p->channel, devpriv->iobase, - ((char __iomem *)p->channel - - (char __iomem *)devpriv->iobase)); - p->channel_no = i; - for (j = 0; j < 8; j++) { - int k; - - p->range[j].length = 1; - p->range[j].range.min = -1000000; - p->range[j].range.max = 1000000; - for (k = 0; k < 7; k++) { - p->range_table_list[j + k * 8] = - (struct comedi_lrange *)&p-> - range[j]; - p->maxdata_list[j + k * 8] = 0x7fff; - } - } - p->range[8].length = 1; - p->range[8].range.min = 0; - p->range[8].range.max = 65536; - - p->range_table_list[56] = - (struct comedi_lrange *)&p->range[8]; - p->range_table_list[57] = - (struct comedi_lrange *)&p->range[8]; - p->maxdata_list[56] = 0xffff; - p->maxdata_list[57] = 0xffff; - /* Channel specific range and maxdata */ - dev->subdevices[i].range_table = NULL; - dev->subdevices[i].range_table_list = - p->range_table_list; - dev->subdevices[i].maxdata = 0; - dev->subdevices[i].maxdata_list = p->maxdata_list; + spriv = jr3_pci_alloc_spriv(dev, s); + if (spriv) { + /* Channel specific range and maxdata */ + s->range_table_list = spriv->range_table_list; + s->maxdata_list = spriv->maxdata_list; } } /* Reset DSP card */ writel(0, &devpriv->iobase->channel[0].reset); - result = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, - "comedi/jr3pci.idm", - jr3_download_firmware, 0); - dev_dbg(dev->class_dev, "Firmare load %d\n", result); - - if (result < 0) - return result; + ret = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, + "comedi/jr3pci.idm", + jr3_download_firmware, 0); + dev_dbg(dev->class_dev, "Firmare load %d\n", ret); + if (ret < 0) + return ret; /* * TODO: use firmware to load preferred offset tables. Suggested * format: @@ -761,11 +764,12 @@ static int jr3_pci_auto_attach(struct comedi_device *dev, } /* Start card timer */ - for (i = 0; i < devpriv->n_channels; i++) { - struct jr3_pci_subdev_private *p = dev->subdevices[i].private; + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + spriv = s->private; - p->next_time_min = jiffies + msecs_to_jiffies(500); - p->next_time_max = jiffies + msecs_to_jiffies(2000); + spriv->next_time_min = jiffies + msecs_to_jiffies(500); + spriv->next_time_max = jiffies + msecs_to_jiffies(2000); } devpriv->timer.data = (unsigned long)dev; @@ -773,21 +777,16 @@ static int jr3_pci_auto_attach(struct comedi_device *dev, devpriv->timer.expires = jiffies + msecs_to_jiffies(1000); add_timer(&devpriv->timer); - return result; + return 0; } static void jr3_pci_detach(struct comedi_device *dev) { - int i; struct jr3_pci_dev_private *devpriv = dev->private; if (devpriv) { del_timer_sync(&devpriv->timer); - if (dev->subdevices) { - for (i = 0; i < devpriv->n_channels; i++) - kfree(dev->subdevices[i].private); - } if (devpriv->iobase) iounmap(devpriv->iobase); } @@ -808,11 +807,11 @@ static int jr3_pci_pci_probe(struct pci_dev *dev, } static const struct pci_device_id jr3_pci_pci_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL) }, - { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL) }, + { PCI_VDEVICE(JR3, 0x1111), BOARD_JR3_1 }, + { PCI_VDEVICE(JR3, 0x3111), BOARD_JR3_1 }, + { PCI_VDEVICE(JR3, 0x3112), BOARD_JR3_2 }, + { PCI_VDEVICE(JR3, 0x3113), BOARD_JR3_3 }, + { PCI_VDEVICE(JR3, 0x3114), BOARD_JR3_4 }, { 0 } }; MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table); diff --git a/drivers/staging/comedi/drivers/jr3_pci.h b/drivers/staging/comedi/drivers/jr3_pci.h index 3317f7a04c48..20478ae8fad6 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.h +++ b/drivers/staging/comedi/drivers/jr3_pci.h @@ -671,11 +671,11 @@ struct jr3_channel { struct jr3_t { struct { - u32 program_low[0x4000]; /* 0x00000 - 0x10000 */ + u32 program_lo[0x4000]; /* 0x00000 - 0x10000 */ struct jr3_channel data; /* 0x10000 - 0x10c00 */ char pad2[0x30000 - 0x00c00]; /* 0x10c00 - 0x40000 */ - u32 program_high[0x8000]; /* 0x40000 - 0x60000 */ - u32 reset; /* 0x60000 - 0x60004 */ + u32 program_hi[0x8000]; /* 0x40000 - 0x60000 */ + u32 reset; /* 0x60000 - 0x60004 */ char pad3[0x20000 - 0x00004]; /* 0x60004 - 0x80000 */ } channel[4]; }; diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c index 6b9846fd8c48..ec43c38958de 100644 --- a/drivers/staging/comedi/drivers/ke_counter.c +++ b/drivers/staging/comedi/drivers/ke_counter.c @@ -1,92 +1,113 @@ /* - comedi/drivers/ke_counter.c - Comedi driver for Kolter-Electronic PCI Counter 1 Card + * ke_counter.c + * Comedi driver for Kolter-Electronic PCI Counter 1 Card + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ /* -Driver: ke_counter -Description: Driver for Kolter Electronic Counter Card -Devices: [Kolter Electronic] PCI Counter Card (ke_counter) -Author: Michael Hillmann -Updated: Mon, 14 Apr 2008 15:42:42 +0100 -Status: tested - -Configuration Options: not applicable, uses PCI auto config - -This driver is a simple driver to read the counter values from -Kolter Electronic PCI Counter Card. -*/ + * Driver: ke_counter + * Description: Driver for Kolter Electronic Counter Card + * Devices: (Kolter Electronic) PCI Counter Card [ke_counter] + * Author: Michael Hillmann + * Updated: Mon, 14 Apr 2008 15:42:42 +0100 + * Status: tested + * + * Configuration Options: not applicable, uses PCI auto config + */ #include #include #include "../comedidev.h" -#define CNT_CARD_DEVICE_ID 0x0014 +/* + * PCI BAR 0 Register I/O map + */ +#define KE_RESET_REG(x) (0x00 + ((x) * 0x20)) +#define KE_LATCH_REG(x) (0x00 + ((x) * 0x20)) +#define KE_LSB_REG(x) (0x04 + ((x) * 0x20)) +#define KE_MID_REG(x) (0x08 + ((x) * 0x20)) +#define KE_MSB_REG(x) (0x0c + ((x) * 0x20)) +#define KE_SIGN_REG(x) (0x10 + ((x) * 0x20)) +#define KE_OSC_SEL_REG 0xf8 +#define KE_OSC_SEL_EXT (1 << 0) +#define KE_OSC_SEL_4MHZ (2 << 0) +#define KE_OSC_SEL_20MHZ (3 << 0) +#define KE_DO_REG 0xfc -/*-- counter write ----------------------------------------------------------*/ - -/* This should be used only for resetting the counters; maybe it is better - to make a special command 'reset'. */ -static int cnt_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int ke_counter_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; - outb((unsigned char)((data[0] >> 24) & 0xff), - dev->iobase + chan * 0x20 + 0x10); - outb((unsigned char)((data[0] >> 16) & 0xff), - dev->iobase + chan * 0x20 + 0x0c); - outb((unsigned char)((data[0] >> 8) & 0xff), - dev->iobase + chan * 0x20 + 0x08); - outb((unsigned char)((data[0] >> 0) & 0xff), - dev->iobase + chan * 0x20 + 0x04); + for (i = 0; i < insn->n; i++) { + val = data[0]; - /* return the number of samples written */ - return 1; + /* Order matters */ + outb((val >> 24) & 0xff, dev->iobase + KE_SIGN_REG(chan)); + outb((val >> 16) & 0xff, dev->iobase + KE_MSB_REG(chan)); + outb((val >> 8) & 0xff, dev->iobase + KE_MID_REG(chan)); + outb((val >> 0) & 0xff, dev->iobase + KE_LSB_REG(chan)); + } + + return insn->n; } -/*-- counter read -----------------------------------------------------------*/ - -static int cnt_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int ke_counter_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned char a0, a1, a2, a3, a4; - int chan = CR_CHAN(insn->chanspec); - int result; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; - a0 = inb(dev->iobase + chan * 0x20); - a1 = inb(dev->iobase + chan * 0x20 + 0x04); - a2 = inb(dev->iobase + chan * 0x20 + 0x08); - a3 = inb(dev->iobase + chan * 0x20 + 0x0c); - a4 = inb(dev->iobase + chan * 0x20 + 0x10); + for (i = 0; i < insn->n; i++) { + /* Order matters */ + inb(dev->iobase + KE_LATCH_REG(chan)); - result = (a1 + (a2 * 256) + (a3 * 65536)); - if (a4 > 0) - result = result - s->maxdata; + val = inb(dev->iobase + KE_LSB_REG(chan)); + val |= (inb(dev->iobase + KE_MID_REG(chan)) << 8); + val |= (inb(dev->iobase + KE_MSB_REG(chan)) << 16); + val |= (inb(dev->iobase + KE_SIGN_REG(chan)) << 24); - *data = (unsigned int)result; + data[i] = val; + } - /* return the number of samples read */ - return 1; + return insn->n; } -static int cnt_auto_attach(struct comedi_device *dev, - unsigned long context_unused) +static int ke_counter_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + KE_DO_REG); + + data[1] = s->state; + + return insn->n; +} + +static int ke_counter_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct comedi_subdevice *s; @@ -97,30 +118,32 @@ static int cnt_auto_attach(struct comedi_device *dev, return ret; dev->iobase = pci_resource_start(pcidev, 0); - ret = comedi_alloc_subdevices(dev, 1); + ret = comedi_alloc_subdevices(dev, 2); if (ret) return ret; s = &dev->subdevices[0]; - dev->read_subdev = s; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE; + s->n_chan = 3; + s->maxdata = 0x01ffffff; + s->range_table = &range_unknown; + s->insn_read = ke_counter_insn_read; + s->insn_write = ke_counter_insn_write; - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE /* | SDF_COMMON */ ; - s->n_chan = 3; - s->maxdata = 0x00ffffff; - s->insn_read = cnt_rinsn; - s->insn_write = cnt_winsn; + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 3; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = ke_counter_do_insn_bits; - /* select 20MHz clock */ - outb(3, dev->iobase + 248); + outb(KE_OSC_SEL_20MHZ, dev->iobase + KE_OSC_SEL_REG); - /* reset all counters */ - outb(0, dev->iobase); - outb(0, dev->iobase + 0x20); - outb(0, dev->iobase + 0x40); - - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); + outb(0, dev->iobase + KE_RESET_REG(0)); + outb(0, dev->iobase + KE_RESET_REG(1)); + outb(0, dev->iobase + KE_RESET_REG(2)); return 0; } @@ -128,7 +151,7 @@ static int cnt_auto_attach(struct comedi_device *dev, static struct comedi_driver ke_counter_driver = { .driver_name = "ke_counter", .module = THIS_MODULE, - .auto_attach = cnt_auto_attach, + .auto_attach = ke_counter_auto_attach, .detach = comedi_pci_disable, }; @@ -140,7 +163,7 @@ static int ke_counter_pci_probe(struct pci_dev *dev, } static const struct pci_device_id ke_counter_pci_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) }, + { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, 0x0014) }, { 0 } }; MODULE_DEVICE_TABLE(pci, ke_counter_pci_table); @@ -154,5 +177,5 @@ static struct pci_driver ke_counter_pci_driver = { module_comedi_pci_driver(ke_counter_driver, ke_counter_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Kolter Electronic Counter Card"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index e739bcd66a04..f02b31b317ec 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -1112,9 +1112,6 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) if (!dev->attached) return IRQ_NONE; - /* Reset all events */ - s->async->events = 0; - if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) & ME4000_IRQ_STATUS_BIT_AI_HF) { /* Read status register to find out what happened */ diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index 7f6687896401..0ff126b1fdfd 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -248,6 +248,20 @@ static int me_dio_insn_bits(struct comedi_device *dev, return insn->n; } +static int me_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct me_private_data *dev_private = dev->private; + unsigned int status; + + status = readw(dev_private->me_regbase + ME_STATUS); + if ((status & 0x0004) == 0) + return 0; + return -EBUSY; +} + static int me_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -258,7 +272,7 @@ static int me_ai_insn_read(struct comedi_device *dev, unsigned int rang = CR_RANGE(insn->chanspec); unsigned int aref = CR_AREF(insn->chanspec); unsigned short val; - int i; + int ret; /* stop any running conversion */ dev_private->control_1 &= 0xFFFC; @@ -290,19 +304,14 @@ static int me_ai_insn_read(struct comedi_device *dev, readw(dev_private->me_regbase + ME_ADC_START); /* wait for ADC fifo not empty flag */ - for (i = 100000; i > 0; i--) - if (!(readw(dev_private->me_regbase + ME_STATUS) & 0x0004)) - break; + ret = comedi_timeout(dev, s, insn, me_ai_eoc, 0); + if (ret) + return ret; /* get value from ADC fifo */ - if (i) { - val = readw(dev_private->me_regbase + ME_READ_AD_FIFO); - val = (val ^ 0x800) & 0x0fff; - data[0] = val; - } else { - dev_err(dev->class_dev, "Cannot get single value\n"); - return -EIO; - } + val = readw(dev_private->me_regbase + ME_READ_AD_FIFO); + val = (val ^ 0x800) & 0x0fff; + data[0] = val; /* stop any running conversion */ dev_private->control_1 &= 0xFFFC; @@ -542,9 +551,6 @@ static int me_auto_attach(struct comedi_device *dev, s->insn_bits = me_dio_insn_bits; s->insn_config = me_dio_insn_config; - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/mf6x4.c b/drivers/staging/comedi/drivers/mf6x4.c index 81b78e053f4e..a4f7d6f138df 100644 --- a/drivers/staging/comedi/drivers/mf6x4.c +++ b/drivers/staging/comedi/drivers/mf6x4.c @@ -133,21 +133,18 @@ static int mf6x4_do_insn_bits(struct comedi_device *dev, return insn->n; } -static int mf6x4_ai_wait_for_eoc(struct comedi_device *dev, - unsigned int timeout) +static int mf6x4_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { struct mf6x4_private *devpriv = dev->private; - unsigned int eolc; + unsigned int status; - while (timeout--) { - eolc = ioread32(devpriv->gpioc_R) & MF6X4_GPIOC_EOLC; - if (eolc) - return 0; - - udelay(1); - } - - return -ETIME; + status = ioread32(devpriv->gpioc_R); + if (status & MF6X4_GPIOC_EOLC) + return 0; + return -EBUSY; } static int mf6x4_ai_insn_read(struct comedi_device *dev, @@ -168,7 +165,7 @@ static int mf6x4_ai_insn_read(struct comedi_device *dev, /* Trigger ADC conversion by reading ADSTART */ ioread16(devpriv->bar1_mem + MF6X4_ADSTART_R); - ret = mf6x4_ai_wait_for_eoc(dev, 100); + ret = comedi_timeout(dev, s, insn, mf6x4_ai_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c index 9c9a0ee432cf..1a572c83f996 100644 --- a/drivers/staging/comedi/drivers/mite.c +++ b/drivers/staging/comedi/drivers/mite.c @@ -527,9 +527,9 @@ EXPORT_SYMBOL_GPL(mite_dma_disarm); int mite_sync_input_dma(struct mite_channel *mite_chan, struct comedi_async *async) { + struct comedi_subdevice *s = async->subdevice; int count; unsigned int nbytes, old_alloc_count; - const unsigned bytes_per_scan = cfc_bytes_per_scan(async->subdevice); old_alloc_count = async->buf_write_alloc_count; /* write alloc as much as we can */ @@ -538,7 +538,7 @@ int mite_sync_input_dma(struct mite_channel *mite_chan, nbytes = mite_bytes_written_to_memory_lb(mite_chan); if ((int)(mite_bytes_written_to_memory_ub(mite_chan) - old_alloc_count) > 0) { - dev_warn(async->subdevice->device->class_dev, + dev_warn(s->device->class_dev, "mite: DMA overwrite of free area\n"); async->events |= COMEDI_CB_OVERFLOW; return -1; @@ -551,12 +551,7 @@ int mite_sync_input_dma(struct mite_channel *mite_chan, return 0; comedi_buf_write_free(async, count); - - async->scan_progress += count; - if (async->scan_progress >= bytes_per_scan) { - async->scan_progress %= bytes_per_scan; - async->events |= COMEDI_CB_EOS; - } + cfc_inc_scan_progress(s, count); async->events |= COMEDI_CB_BLOCK; return 0; } diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h index bcf2f972376e..78f235747991 100644 --- a/drivers/staging/comedi/drivers/mite.h +++ b/drivers/staging/comedi/drivers/mite.h @@ -29,9 +29,9 @@ #define MAX_MITE_DMA_CHANNELS 8 struct mite_dma_descriptor { - u32 count; - u32 addr; - u32 next; + __le32 count; + __le32 addr; + __le32 next; u32 dar; }; diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c index fe4621ea65c3..f770400a0e81 100644 --- a/drivers/staging/comedi/drivers/mpc624.c +++ b/drivers/staging/comedi/drivers/mpc624.c @@ -142,8 +142,18 @@ static const struct comedi_lrange range_mpc624_bipolar10 = { } }; -/* Timeout 200ms */ -#define TIMEOUT 200 +static int mpc624_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned char status; + + status = inb(dev->iobase + MPC624_ADC); + if ((status & MPC624_ADBUSY) == 0) + return 0; + return -EBUSY; +} static int mpc624_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -152,7 +162,7 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, struct mpc624_private *devpriv = dev->private; int n, i; unsigned long int data_in, data_out; - unsigned char ucPort; + int ret; /* * WARNING: @@ -170,15 +180,9 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, udelay(1); /* Wait for the conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - ucPort = inb(dev->iobase + MPC624_ADC); - if (ucPort & MPC624_ADBUSY) - udelay(1000); - else - break; - } - if (i == TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, mpc624_ai_eoc, 0); + if (ret) + return ret; /* Start reading data */ data_in = 0; @@ -341,7 +345,7 @@ static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->len_chanlist = 1; s->insn_read = mpc624_ai_rinsn; - return 1; + return 0; } static struct comedi_driver mpc624_driver = { diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c index 3ca755eca285..b74b9e9bfd4a 100644 --- a/drivers/staging/comedi/drivers/multiq3.c +++ b/drivers/staging/comedi/drivers/multiq3.c @@ -81,34 +81,44 @@ struct multiq3_private { unsigned int ao_readback[2]; }; +static int multiq3_ai_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + MULTIQ3_STATUS); + if (status & context) + return 0; + return -EBUSY; +} + static int multiq3_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int i, n; + int n; int chan; unsigned int hi, lo; + int ret; chan = CR_CHAN(insn->chanspec); outw(MULTIQ3_CONTROL_MUST | MULTIQ3_AD_MUX_EN | (chan << 3), dev->iobase + MULTIQ3_CONTROL); - for (i = 0; i < MULTIQ3_TIMEOUT; i++) { - if (inw(dev->iobase + MULTIQ3_STATUS) & MULTIQ3_STATUS_EOC) - break; - } - if (i == MULTIQ3_TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, multiq3_ai_status, + MULTIQ3_STATUS_EOC); + if (ret) + return ret; for (n = 0; n < insn->n; n++) { outw(0, dev->iobase + MULTIQ3_AD_CS); - for (i = 0; i < MULTIQ3_TIMEOUT; i++) { - if (inw(dev->iobase + - MULTIQ3_STATUS) & MULTIQ3_STATUS_EOC_I) - break; - } - if (i == MULTIQ3_TIMEOUT) - return -ETIMEDOUT; + + ret = comedi_timeout(dev, s, insn, multiq3_ai_status, + MULTIQ3_STATUS_EOC_I); + if (ret) + return ret; hi = inb(dev->iobase + MULTIQ3_AD_CS); lo = inb(dev->iobase + MULTIQ3_AD_CS); diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c index df42e3906171..0d4b9019f76a 100644 --- a/drivers/staging/comedi/drivers/ni_660x.c +++ b/drivers/staging/comedi/drivers/ni_660x.c @@ -40,6 +40,7 @@ #include "../comedidev.h" +#include "comedi_fc.h" #include "mite.h" #include "ni_tio.h" @@ -789,13 +790,7 @@ static void ni_660x_handle_gpct_interrupt(struct comedi_device *dev, struct ni_gpct *counter = s->private; ni_tio_handle_interrupt(counter, s); - if (s->async->events) { - if (s->async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | - COMEDI_CB_OVERFLOW)) { - ni_660x_cancel(dev, s); - } - comedi_event(dev, s); - } + cfc_handle_events(dev, s); } static irqreturn_t ni_660x_interrupt(int irq, void *d) @@ -1187,7 +1182,7 @@ static int ni_660x_auto_attach(struct comedi_device *dev, global_interrupt_config_bits |= Cascade_Int_Enable_Bit; ni_660x_write_register(dev, 0, global_interrupt_config_bits, NI660X_GLOBAL_INT_CFG); - dev_info(dev->class_dev, "ni_660x: %s attached\n", dev->board_name); + return 0; } diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c index 8550fdc4ccd3..1002ceacfdcc 100644 --- a/drivers/staging/comedi/drivers/ni_670x.c +++ b/drivers/staging/comedi/drivers/ni_670x.c @@ -246,9 +246,6 @@ static int ni_670x_auto_attach(struct comedi_device *dev, /* Config of ao registers */ writel(0x00, devpriv->mite->daq_io_addr + AO_CONTROL_OFFSET); - dev_info(dev->class_dev, "%s: %s attached\n", - dev->driver->driver_name, dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c index f83eb9ebe278..4e39b1f63d81 100644 --- a/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -184,7 +184,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d) } /* initialize async here to make sure s is not NULL */ async = s->async; - async->events = 0; cmd = &async->cmd; status = inw(dev->iobase + STATUS_REG); @@ -196,15 +195,14 @@ static irqreturn_t a2150_interrupt(int irq, void *d) if (status & OVFL_BIT) { comedi_error(dev, "fifo overflow"); - a2150_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + cfc_handle_events(dev, s); } if ((status & DMA_TC_BIT) == 0) { comedi_error(dev, "caught non-dma interrupt? Aborting."); - a2150_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -249,7 +247,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d) cfc_write_to_buffer(s, dpnt); if (cmd->stop_src == TRIG_COUNT) { if (--devpriv->count == 0) { /* end of acquisition */ - a2150_cancel(dev, s); async->events |= COMEDI_CB_EOA; break; } @@ -265,7 +262,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d) async->events |= COMEDI_CB_BLOCK; - comedi_event(dev, s); + cfc_handle_events(dev, s); /* clear interrupt */ outw(0x00, dev->iobase + DMA_TC_CLEAR_REG); @@ -488,13 +485,25 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } +static int a2150_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + STATUS_REG); + if (status & FNE_BIT) + return 0; + return -EBUSY; +} + static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct a2150_private *devpriv = dev->private; - unsigned int i, n; - static const int timeout = 100000; - static const int filter_delay = 36; + unsigned int n; + int ret; /* clear fifo and reset triggering circuitry */ outw(0, dev->iobase + FIFO_RESET_REG); @@ -524,30 +533,20 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, * there is a 35.6 sample delay for data to get through the * antialias filter */ - for (n = 0; n < filter_delay; n++) { - for (i = 0; i < timeout; i++) { - if (inw(dev->iobase + STATUS_REG) & FNE_BIT) - break; - udelay(1); - } - if (i == timeout) { - comedi_error(dev, "timeout"); - return -ETIME; - } + for (n = 0; n < 36; n++) { + ret = comedi_timeout(dev, s, insn, a2150_ai_eoc, 0); + if (ret) + return ret; + inw(dev->iobase + FIFO_DATA_REG); } /* read data */ for (n = 0; n < insn->n; n++) { - for (i = 0; i < timeout; i++) { - if (inw(dev->iobase + STATUS_REG) & FNE_BIT) - break; - udelay(1); - } - if (i == timeout) { - comedi_error(dev, "timeout"); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, a2150_ai_eoc, 0); + if (ret) + return ret; + data[n] = inw(dev->iobase + FIFO_DATA_REG); data[n] ^= 0x8000; } diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c index e8cd5ddb85c5..4262385e4f46 100644 --- a/drivers/staging/comedi/drivers/ni_atmio16d.c +++ b/drivers/staging/comedi/drivers/ni_atmio16d.c @@ -96,7 +96,6 @@ Devices: [National Instruments] AT-MIO-16 (atmio16), AT-MIO-16D (atmio16d) #define CLOCK_100_HZ 0x8F25 /* Other miscellaneous defines */ #define ATMIO16D_SIZE 32 /* bus address range */ -#define ATMIO16D_TIMEOUT 10 struct atmio16_board_t { @@ -448,16 +447,32 @@ static int atmio16d_ai_cancel(struct comedi_device *dev, return 0; } -/* Mode 0 is used to get a single conversion on demand */ +static int atmio16d_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + STAT_REG); + if (status & STAT_AD_CONVAVAIL) + return 0; + if (status & STAT_AD_OVERFLOW) { + outw(0, dev->iobase + AD_CLEAR_REG); + return -EOVERFLOW; + } + return -EBUSY; +} + static int atmio16d_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct atmio16d_private *devpriv = dev->private; - int i, t; + int i; int chan; int gain; - int status; + int ret; chan = CR_CHAN(insn->chanspec); gain = CR_RANGE(insn->chanspec); @@ -473,26 +488,17 @@ static int atmio16d_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { /* start the conversion */ outw(0, dev->iobase + START_CONVERT_REG); + /* wait for it to finish */ - for (t = 0; t < ATMIO16D_TIMEOUT; t++) { - /* check conversion status */ - status = inw(dev->iobase + STAT_REG); - if (status & STAT_AD_CONVAVAIL) { - /* read the data now */ - data[i] = inw(dev->iobase + AD_FIFO_REG); - /* change to two's complement if need be */ - if (devpriv->adc_coding == adc_2comp) - data[i] ^= 0x800; - break; - } - if (status & STAT_AD_OVERFLOW) { - outw(0, dev->iobase + AD_CLEAR_REG); - return -ETIME; - } - } - /* end waiting, now check if it timed out */ - if (t == ATMIO16D_TIMEOUT) - return -ETIME; + ret = comedi_timeout(dev, s, insn, atmio16d_ai_eoc, 0); + if (ret) + return ret; + + /* read the data now */ + data[i] = inw(dev->iobase + AD_FIFO_REG); + /* change to two's complement if need be */ + if (devpriv->adc_coding == adc_2comp) + data[i] ^= 0x800; } return i; @@ -723,10 +729,13 @@ static int atmio16d_attach(struct comedi_device *dev, /* 8255 subdevice */ s = &dev->subdevices[3]; - if (board->has_8255) - subdev_8255_init(dev, s, NULL, dev->iobase); - else + if (board->has_8255) { + ret = subdev_8255_init(dev, s, NULL, dev->iobase); + if (ret) + return ret; + } else { s->type = COMEDI_SUBD_UNUSED; + } /* don't yet know how to deal with counter/timers */ #if 0 diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index e4cdca349157..171a71d20c88 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -109,14 +109,31 @@ static int daq700_dio_insn_config(struct comedi_device *dev, return insn->n; } +static int daq700_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + STA_R2); + if ((status & 0x03)) + return -EOVERFLOW; + status = inb(dev->iobase + STA_R1); + if ((status & 0x02)) + return -ENODATA; + if ((status & 0x11) == 0x01) + return 0; + return -EBUSY; +} + static int daq700_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i, chan; + int n, chan; int d; - unsigned int status; - enum { TIMEOUT = 100 }; + int ret; chan = CR_CHAN(insn->chanspec); /* write channel to multiplexer */ @@ -130,30 +147,12 @@ static int daq700_ai_rinsn(struct comedi_device *dev, outb(0x30, dev->iobase + CMO_R); /* mode 0 out0 L, from H */ /* mode 1 out0 H, L to H, start conversion */ outb(0x32, dev->iobase + CMO_R); + /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = inb(dev->iobase + STA_R2); - if ((status & 0x03) != 0) { - dev_info(dev->class_dev, - "Overflow/run Error\n"); - return -EOVERFLOW; - } - status = inb(dev->iobase + STA_R1); - if ((status & 0x02) != 0) { - dev_info(dev->class_dev, "Data Error\n"); - return -ENODATA; - } - if ((status & 0x11) == 0x01) { - /* ADC conversion complete */ - break; - } - udelay(1); - } - if (i == TIMEOUT) { - dev_info(dev->class_dev, - "timeout during ADC conversion\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, daq700_ai_eoc, 0); + if (ret) + return ret; + /* read data */ d = inw(dev->iobase + ADFIFO_R); /* mangle the data as necessary */ @@ -229,11 +228,6 @@ static int daq700_auto_attach(struct comedi_device *dev, s->insn_read = daq700_ai_rinsn; daq700_ai_config(dev, s); - dev_info(dev->class_dev, "%s: %s, io 0x%lx\n", - dev->driver->driver_name, - dev->board_name, - dev->iobase); - return 0; } diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index 335ea34fa57c..925e82c65b2d 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -3,8 +3,8 @@ Driver for National Instruments PCMCIA DAQ-Card DIO-24 Copyright (C) 2002 Daniel Vecino Castel - PCMCIA crap at end of file is adapted from dummy_cs.c 1.31 2001/08/24 12:13:13 - from the pcmcia package. + PCMCIA crap at end of file is adapted from dummy_cs.c 1.31 + 2001/08/24 12:13:13 from the pcmcia package. The initial developer of the pcmcia dummy_cs.c code is David A. Hinds . Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index 0512445df08e..f4216e825f03 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -73,7 +73,6 @@ #include "ni_labpc_isadma.h" #define LABPC_SIZE 0x20 /* size of ISA io region */ -#define LABPC_ADC_TIMEOUT 1000 enum scan_mode { MODE_SINGLE_CHAN, @@ -308,19 +307,17 @@ static void labpc_clear_adc_fifo(struct comedi_device *dev) labpc_read_adc_fifo(dev); } -static int labpc_ai_wait_for_data(struct comedi_device *dev, - int timeout) +static int labpc_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { struct labpc_private *devpriv = dev->private; - int i; - for (i = 0; i < timeout; i++) { - devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG); - if (devpriv->stat1 & STAT1_DAVAIL) - return 0; - udelay(1); - } - return -ETIME; + devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG); + if (devpriv->stat1 & STAT1_DAVAIL) + return 0; + return -EBUSY; } static int labpc_ai_insn_read(struct comedi_device *dev, @@ -363,7 +360,7 @@ static int labpc_ai_insn_read(struct comedi_device *dev, /* trigger conversion */ devpriv->write_byte(0x1, dev->iobase + ADC_START_CONVERT_REG); - ret = labpc_ai_wait_for_data(dev, LABPC_ADC_TIMEOUT); + ret = comedi_timeout(dev, s, insn, labpc_ai_eoc, 0); if (ret) return ret; @@ -950,7 +947,6 @@ static irqreturn_t labpc_interrupt(int irq, void *d) async = s->async; cmd = &async->cmd; - async->events = 0; /* read board status */ devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG); @@ -968,7 +964,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d) /* clear error interrupt */ devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); comedi_error(dev, "overrun"); return IRQ_HANDLED; } @@ -988,7 +984,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d) /* clear error interrupt */ devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); comedi_error(dev, "overflow"); return IRQ_HANDLED; } @@ -996,20 +992,17 @@ static irqreturn_t labpc_interrupt(int irq, void *d) if (cmd->stop_src == TRIG_EXT) { if (devpriv->stat2 & STAT2_OUTA1) { labpc_drain_dregs(dev); - labpc_cancel(dev, s); async->events |= COMEDI_CB_EOA; } } /* TRIG_COUNT end of acquisition */ if (cmd->stop_src == TRIG_COUNT) { - if (devpriv->count == 0) { - labpc_cancel(dev, s); + if (devpriv->count == 0) async->events |= COMEDI_CB_EOA; - } } - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 457b88481db0..8a0e3b7236ad 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -256,7 +256,6 @@ static int ni_rtsi_insn_config(struct comedi_device *dev, static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s); static int ni_read_eeprom(struct comedi_device *dev, int addr); -static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s); #ifndef PCIDMA static void ni_handle_fifo_half_full(struct comedi_device *dev); static int ni_ao_fifo_half_empty(struct comedi_device *dev, @@ -272,15 +271,12 @@ static void shutdown_ai_command(struct comedi_device *dev); static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum); -static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s); - static int ni_8255_callback(int dir, int port, int data, unsigned long arg); #ifdef PCIDMA static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s); +static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s); #endif -static int ni_gpct_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); static void handle_gpct_interrupt(struct comedi_device *dev, unsigned short counter_index); @@ -687,12 +683,22 @@ static void ni_clear_ai_fifo(struct comedi_device *dev) { const struct ni_board_struct *board = comedi_board(dev); struct ni_private *devpriv = dev->private; + static const int timeout = 10000; + int i; if (board->reg_type == ni_reg_6143) { /* Flush the 6143 data FIFO */ ni_writel(0x10, AIFIFO_Control_6143); /* Flush fifo */ ni_writel(0x00, AIFIFO_Control_6143); /* Flush fifo */ - while (ni_readl(AIFIFO_Status_6143) & 0x10) ; /* Wait for complete */ + /* Wait for complete */ + for (i = 0; i < timeout; i++) { + if (!(ni_readl(AIFIFO_Status_6143) & 0x10)) + break; + udelay(1); + } + if (i == timeout) { + comedi_error(dev, "FIFO flush timeout."); + } } else { devpriv->stc_writew(dev, 1, ADC_FIFO_Clear); if (board->reg_type == ni_reg_625x) { @@ -937,32 +943,6 @@ static void shutdown_ai_command(struct comedi_device *dev) s->async->events |= COMEDI_CB_EOA; } -static void ni_event(struct comedi_device *dev, struct comedi_subdevice *s) -{ - if (s-> - async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW | - COMEDI_CB_EOA)) { - switch (s->index) { - case NI_AI_SUBDEV: - ni_ai_reset(dev, s); - break; - case NI_AO_SUBDEV: - ni_ao_reset(dev, s); - break; - case NI_GPCT0_SUBDEV: - case NI_GPCT1_SUBDEV: - ni_gpct_cancel(dev, s); - break; - case NI_DIO_SUBDEV: - ni_cdio_cancel(dev, s); - break; - default: - break; - } - } - comedi_event(dev, s); -} - static void handle_gpct_interrupt(struct comedi_device *dev, unsigned short counter_index) { @@ -974,8 +954,7 @@ static void handle_gpct_interrupt(struct comedi_device *dev, ni_tio_handle_interrupt(&devpriv->counter_dev->counters[counter_index], s); - if (s->async->events) - ni_event(dev, s); + cfc_handle_events(dev, s); #endif } @@ -1033,7 +1012,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, if (comedi_is_subdevice_running(s)) { s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - ni_event(dev, s); + cfc_handle_events(dev, s); } return; } @@ -1048,8 +1027,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, if (status & (AI_Overrun_St | AI_Overflow_St)) s->async->events |= COMEDI_CB_OVERFLOW; - ni_event(dev, s); - + cfc_handle_events(dev, s); return; } if (status & AI_SC_TC_St) { @@ -1076,7 +1054,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, if ((status & AI_STOP_St)) ni_handle_eos(dev, s); - ni_event(dev, s); + cfc_handle_events(dev, s); } static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status) @@ -1151,7 +1129,7 @@ static void handle_b_interrupt(struct comedi_device *dev, } #endif - ni_event(dev, s); + cfc_handle_events(dev, s); } #ifndef PCIDMA @@ -3662,7 +3640,7 @@ static void handle_cdio_interrupt(struct comedi_device *dev) M_Offset_CDIO_Command); /* s->async->events |= COMEDI_CB_EOA; */ } - ni_event(dev, s); + cfc_handle_events(dev, s); } static int ni_serial_insn_config(struct comedi_device *dev, @@ -4282,10 +4260,14 @@ static int ni_E_init(struct comedi_device *dev) /* 8255 device */ s = &dev->subdevices[NI_8255_DIO_SUBDEV]; - if (board->has_8255) - subdev_8255_init(dev, s, ni_8255_callback, (unsigned long)dev); - else + if (board->has_8255) { + ret = subdev_8255_init(dev, s, ni_8255_callback, + (unsigned long)dev); + if (ret) + return ret; + } else { s->type = COMEDI_SUBD_UNUSED; + } /* formerly general purpose counter/timer device, but no longer used */ s = &dev->subdevices[NI_UNUSED_SUBDEV]; @@ -4393,6 +4375,9 @@ static int ni_E_init(struct comedi_device *dev) &ni_gpct_read_register, counter_variant, NUM_GPCT); + if (!devpriv->counter_dev) + return -ENOMEM; + /* General purpose counters */ for (j = 0; j < NUM_GPCT; ++j) { s = &dev->subdevices[NI_GPCT_SUBDEV(j)]; @@ -4483,7 +4468,6 @@ static int ni_E_init(struct comedi_device *dev) ni_writeb(0x0, M_Offset_AO_Calibration); } - printk("\n"); return 0; } @@ -4992,9 +4976,9 @@ static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } #endif +#ifdef PCIDMA static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { -#ifdef PCIDMA struct ni_gpct *counter = s->private; int retval; @@ -5002,10 +4986,8 @@ static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s) ni_e_series_enable_second_irq(dev, counter->counter_index, 0); ni_release_gpct_mite_channel(dev, counter->counter_index); return retval; -#else - return 0; -#endif } +#endif /* * diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index 30c46a3c1767..85ac2d964f5c 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -263,9 +263,6 @@ enum FPGA_Control_Bits { #define IntEn (TransferReady|CountExpired|Waited|PrimaryTC|SecondaryTC) #endif -static int ni_pcidio_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); - enum nidio_boardid { BOARD_PCIDIO_32HS, BOARD_PXI6533, @@ -353,17 +350,6 @@ static void ni_pcidio_release_di_mite_channel(struct comedi_device *dev) spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); } -static void ni_pcidio_event(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - if (s-> - async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | - COMEDI_CB_OVERFLOW)) { - ni_pcidio_cancel(dev, s); - } - comedi_event(dev, s); -} - static int ni_pcidio_poll(struct comedi_device *dev, struct comedi_subdevice *s) { struct nidio96_private *devpriv = dev->private; @@ -501,7 +487,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d) } out: - ni_pcidio_event(dev, s); + cfc_handle_events(dev, s); #if 0 if (!tag) { writeb(0x03, diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index 0ed980455875..d40df072583c 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c @@ -1551,7 +1551,7 @@ static int pcimio_auto_attach(struct comedi_device *dev, dev->subdevices[NI_GPCT_SUBDEV(1)].buf_change = &pcimio_gpct1_change; dev->subdevices[NI_DIO_SUBDEV].buf_change = &pcimio_dio_change; - return ret; + return 0; } static int pcimio_ai_change(struct comedi_device *dev, diff --git a/drivers/staging/comedi/drivers/ni_tio.h b/drivers/staging/comedi/drivers/ni_tio.h index 68378dab4e70..1056bf001e5e 100644 --- a/drivers/staging/comedi/drivers/ni_tio.h +++ b/drivers/staging/comedi/drivers/ni_tio.h @@ -115,10 +115,10 @@ struct ni_gpct { struct ni_gpct_device { struct comedi_device *dev; - void (*write_register) (struct ni_gpct *counter, unsigned bits, - enum ni_gpct_register reg); - unsigned (*read_register) (struct ni_gpct *counter, - enum ni_gpct_register reg); + void (*write_register)(struct ni_gpct *counter, unsigned bits, + enum ni_gpct_register reg); + unsigned (*read_register)(struct ni_gpct *counter, + enum ni_gpct_register reg); enum ni_gpct_variant variant; struct ni_gpct *counters; unsigned num_counters; diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c index f0fc123ef566..7c03a5d17b1b 100644 --- a/drivers/staging/comedi/drivers/pcl711.c +++ b/drivers/staging/comedi/drivers/pcl711.c @@ -253,18 +253,17 @@ static void pcl711_set_changain(struct comedi_device *dev, outb(mux | PCL711_MUX_CHAN(chan), dev->iobase + PCL711_MUX_REG); } -static int pcl711_ai_wait_for_eoc(struct comedi_device *dev, - unsigned int timeout) +static int pcl711_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - unsigned int msb; + unsigned int status; - while (timeout--) { - msb = inb(dev->iobase + PCL711_AI_MSB_REG); - if ((msb & PCL711_AI_MSB_DRDY) == 0) - return 0; - udelay(1); - } - return -ETIME; + status = inb(dev->iobase + PCL711_AI_MSB_REG); + if ((status & PCL711_AI_MSB_DRDY) == 0) + return 0; + return -EBUSY; } static int pcl711_ai_insn_read(struct comedi_device *dev, @@ -282,7 +281,7 @@ static int pcl711_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outb(PCL711_SOFTTRIG, dev->iobase + PCL711_SOFTTRIG_REG); - ret = pcl711_ai_wait_for_eoc(dev, 100); + ret = comedi_timeout(dev, s, insn, pcl711_ai_eoc, 0); if (ret) return ret; @@ -336,11 +335,8 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_NONE) { + if (cmd->stop_src == TRIG_NONE) err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - } else { - /* ignore */ - } if (err) return 3; diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c index 53613b385f35..160eac8083db 100644 --- a/drivers/staging/comedi/drivers/pcl812.c +++ b/drivers/staging/comedi/drivers/pcl812.c @@ -131,34 +131,32 @@ #define boardACL8216 8 /* and ICP DAS A-826PG */ #define boardA821 9 /* PGH, PGL, PGL/NDA versions */ -#define PCLx1x_IORANGE 16 - -#define PCL812_CTR0 0 -#define PCL812_CTR1 1 -#define PCL812_CTR2 2 -#define PCL812_CTRCTL 3 -#define PCL812_AD_LO 4 -#define PCL812_DA1_LO 4 -#define PCL812_AD_HI 5 -#define PCL812_DA1_HI 5 -#define PCL812_DA2_LO 6 -#define PCL812_DI_LO 6 -#define PCL812_DA2_HI 7 -#define PCL812_DI_HI 7 -#define PCL812_CLRINT 8 -#define PCL812_GAIN 9 -#define PCL812_MUX 10 -#define PCL812_MODE 11 -#define PCL812_CNTENABLE 10 -#define PCL812_SOFTTRIG 12 -#define PCL812_DO_LO 13 -#define PCL812_DO_HI 14 - -#define PCL812_DRDY 0x10 /* =0 data ready */ - -#define ACL8216_STATUS 8 /* 5. bit signalize data ready */ - -#define ACL8216_DRDY 0x20 /* =0 data ready */ +/* + * Register I/O map + */ +#define PCL812_TIMER_BASE 0x00 +#define PCL812_AI_LSB_REG 0x04 +#define PCL812_AI_MSB_REG 0x05 +#define PCL812_AI_MSB_DRDY (1 << 4) +#define PCL812_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define PCL812_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define PCL812_DI_LSB_REG 0x06 +#define PCL812_DI_MSB_REG 0x07 +#define PCL812_STATUS_REG 0x08 +#define PCL812_STATUS_DRDY (1 << 5) +#define PCL812_RANGE_REG 0x09 +#define PCL812_MUX_REG 0x0a +#define PCL812_MUX_CHAN(x) ((x) << 0) +#define PCL812_MUX_CS0 (1 << 4) +#define PCL812_MUX_CS1 (1 << 5) +#define PCL812_CTRL_REG 0x0b +#define PCL812_CTRL_DISABLE_TRIG (0 << 0) +#define PCL812_CTRL_SOFT_TRIG (1 << 0) +#define PCL812_CTRL_PACER_DMA_TRIG (2 << 0) +#define PCL812_CTRL_PACER_EOC_TRIG (6 << 0) +#define PCL812_SOFTTRIG_REG 0x0c +#define PCL812_DO_LSB_REG 0x0d +#define PCL812_DO_MSB_REG 0x0e #define MAX_CHANLIST_LEN 256 /* length of scan list */ @@ -331,213 +329,391 @@ static const struct comedi_lrange range_a821pgh_ai = { }; struct pcl812_board { + const char *name; + int board_type; + int n_aichan; + int n_aochan; + unsigned int ai_ns_min; + const struct comedi_lrange *rangelist_ai; + unsigned int IRQbits; + unsigned int has_dma:1; + unsigned int has_16bit_ai:1; + unsigned int has_mpc508_mux:1; + unsigned int has_dio:1; +}; - const char *name; /* board name */ - int board_type; /* type of this board */ - int n_aichan; /* num of AI chans in S.E. */ - int n_aichan_diff; /* DIFF num of chans */ - int n_aochan; /* num of DA chans */ - int n_dichan; /* DI and DO chans */ - int n_dochan; - int ai_maxdata; /* AI resolution */ - unsigned int ai_ns_min; /* max sample speed of card v ns */ - unsigned int i8254_osc_base; /* clock base */ - const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */ - const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ - unsigned int IRQbits; /* allowed IRQ */ - unsigned char DMAbits; /* allowed DMA chans */ - unsigned char io_range; /* iorange for this board */ - unsigned char haveMPC508; /* 1=board use MPC508A multiplexor */ +static const struct pcl812_board boardtypes[] = { + { + .name = "pcl812", + .board_type = boardPCL812, + .n_aichan = 16, + .n_aochan = 2, + .ai_ns_min = 33000, + .rangelist_ai = &range_bipolar10, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "pcl812pg", + .board_type = boardPCL812PG, + .n_aichan = 16, + .n_aochan = 2, + .ai_ns_min = 33000, + .rangelist_ai = &range_pcl812pg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "acl8112pg", + .board_type = boardPCL812PG, + .n_aichan = 16, + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl812pg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "acl8112dg", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112dg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_mpc508_mux = 1, + .has_dio = 1, + }, { + .name = "acl8112hg", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112hg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_mpc508_mux = 1, + .has_dio = 1, + }, { + .name = "a821pgl", + .board_type = boardA821, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 1, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b_ai, + .IRQbits = 0x000c, + .has_dio = 1, + }, { + .name = "a821pglnda", + .board_type = boardA821, + .n_aichan = 16, /* 8 differential */ + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b_ai, + .IRQbits = 0x000c, + }, { + .name = "a821pgh", + .board_type = boardA821, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 1, + .ai_ns_min = 10000, + .rangelist_ai = &range_a821pgh_ai, + .IRQbits = 0x000c, + .has_dio = 1, + }, { + .name = "a822pgl", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112dg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "a822pgh", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112hg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "a823pgl", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 8000, + .rangelist_ai = &range_acl8112dg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "a823pgh", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 8000, + .rangelist_ai = &range_acl8112hg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "pcl813", + .board_type = boardPCL813, + .n_aichan = 32, + .rangelist_ai = &range_pcl813b_ai, + }, { + .name = "pcl813b", + .board_type = boardPCL813B, + .n_aichan = 32, + .rangelist_ai = &range_pcl813b_ai, + }, { + .name = "acl8113", + .board_type = boardACL8113, + .n_aichan = 32, + .rangelist_ai = &range_acl8113_1_ai, + }, { + .name = "iso813", + .board_type = boardISO813, + .n_aichan = 32, + .rangelist_ai = &range_iso813_1_ai, + }, { + .name = "acl8216", + .board_type = boardACL8216, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b2_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_16bit_ai = 1, + .has_mpc508_mux = 1, + .has_dio = 1, + }, { + .name = "a826pg", + .board_type = boardACL8216, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b2_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_16bit_ai = 1, + .has_dio = 1, + }, }; struct pcl812_private { - - unsigned char valid; /* =1 device is OK */ unsigned char dma; /* >0 use dma ( usedDMA channel) */ - unsigned char use_diff; /* =1 diff inputs */ - unsigned char use_MPC; /* 1=board uses MPC508A multiplexor */ - unsigned char use_ext_trg; /* 1=board uses external trigger */ unsigned char range_correction; /* =1 we must add 1 to range number */ - unsigned char old_chan_reg; /* lastly used chan/gain pair */ - unsigned char old_gain_reg; + unsigned int last_ai_chanspec; unsigned char mode_reg_int; /* there is stored INT number for some card */ - unsigned char ai_neverending; /* =1 we do unlimited AI */ - unsigned char ai_eos; /* 1=EOS wake up */ - unsigned char ai_dma; /* =1 we use DMA */ unsigned int ai_poll_ptr; /* how many sampes transfer poll */ - unsigned int ai_scans; /* len of scanlist */ unsigned int ai_act_scan; /* how many scans we finished */ - unsigned int ai_chanlist[MAX_CHANLIST_LEN]; /* our copy of channel/range list */ - unsigned int ai_n_chan; /* how many channels is measured */ - unsigned int ai_flags; /* flaglist */ - unsigned int ai_data_len; /* len of data buffer */ - unsigned int ai_is16b; /* =1 we have 16 bit card */ + unsigned int dmapages; + unsigned int hwdmasize; unsigned long dmabuf[2]; /* PTR to DMA buf */ - unsigned int dmapages[2]; /* how many pages we have allocated */ unsigned int hwdmaptr[2]; /* HW PTR to DMA buf */ - unsigned int hwdmasize[2]; /* DMA buf size in bytes */ unsigned int dmabytestomove[2]; /* how many bytes DMA transfer */ int next_dma_buf; /* which buffer is next to use */ unsigned int dma_runs_to_end; /* how many times we must switch DMA buffers */ unsigned int last_dma_run; /* how many bytes to transfer on last DMA buffer */ unsigned int max_812_ai_mode0_rangewait; /* setling time for gain */ unsigned int ao_readback[2]; /* data for AO readback */ + unsigned int divisor1; + unsigned int divisor2; + unsigned int use_diff:1; + unsigned int use_mpc508:1; + unsigned int use_ext_trg:1; + unsigned int ai_dma:1; + unsigned int ai_eos:1; }; -/* -============================================================================== -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); -static void setup_range_channel(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int rangechan, char wait); -static int pcl812_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -/* -============================================================================== -*/ -static int pcl812_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_start_pacer(struct comedi_device *dev, bool load_timers) { struct pcl812_private *devpriv = dev->private; - int n; - int timeout, hi; + unsigned long timer_base = dev->iobase + PCL812_TIMER_BASE; - /* select software trigger */ - outb(devpriv->mode_reg_int | 1, dev->iobase + PCL812_MODE); - /* select channel and renge */ - setup_range_channel(dev, s, insn->chanspec, 1); - for (n = 0; n < insn->n; n++) { - /* start conversion */ - outb(255, dev->iobase + PCL812_SOFTTRIG); - udelay(5); - timeout = 50; /* wait max 50us, it must finish under 33us */ - while (timeout--) { - hi = inb(dev->iobase + PCL812_AD_HI); - if (!(hi & PCL812_DRDY)) - goto conv_finish; - udelay(1); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + udelay(1); + + if (load_timers) { + i8254_write(timer_base, 0, 2, devpriv->divisor2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); + } +} + +static void pcl812_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl812_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int dma_flags; + unsigned int bytes; + + /* we use EOS, so adapt DMA buffer to one scan */ + if (devpriv->ai_eos) { + devpriv->dmabytestomove[0] = + cmd->chanlist_len * sizeof(short); + devpriv->dmabytestomove[1] = + cmd->chanlist_len * sizeof(short); + devpriv->dma_runs_to_end = 1; + } else { + devpriv->dmabytestomove[0] = devpriv->hwdmasize; + devpriv->dmabytestomove[1] = devpriv->hwdmasize; + if (s->async->prealloc_bufsz < devpriv->hwdmasize) { + devpriv->dmabytestomove[0] = + s->async->prealloc_bufsz; + devpriv->dmabytestomove[1] = + s->async->prealloc_bufsz; } - dev_dbg(dev->class_dev, "A/D insn read timeout\n"); - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - return -ETIME; + if (cmd->stop_src == TRIG_NONE) { + devpriv->dma_runs_to_end = 1; + } else { + /* how many samples we must transfer? */ + bytes = cmd->chanlist_len * + cmd->stop_arg * sizeof(short); -conv_finish: - data[n] = ((hi & 0xf) << 8) | inb(dev->iobase + PCL812_AD_LO); - } - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - return n; -} + /* how many DMA pages we must fill */ + devpriv->dma_runs_to_end = + bytes / devpriv->dmabytestomove[0]; -/* -============================================================================== -*/ -static int acl8216_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int n; - int timeout; - - /* select software trigger */ - outb(1, dev->iobase + PCL812_MODE); - /* select channel and renge */ - setup_range_channel(dev, s, insn->chanspec, 1); - for (n = 0; n < insn->n; n++) { - /* start conversion */ - outb(255, dev->iobase + PCL812_SOFTTRIG); - udelay(5); - timeout = 50; /* wait max 50us, it must finish under 33us */ - while (timeout--) { - if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) - goto conv_finish; - udelay(1); + /* on last dma transfer must be moved */ + devpriv->last_dma_run = + bytes % devpriv->dmabytestomove[0]; + if (devpriv->dma_runs_to_end == 0) + devpriv->dmabytestomove[0] = + devpriv->last_dma_run; + devpriv->dma_runs_to_end--; } - dev_dbg(dev->class_dev, "A/D insn read timeout\n"); - outb(0, dev->iobase + PCL812_MODE); - return -ETIME; - -conv_finish: - data[n] = - (inb(dev->iobase + - PCL812_AD_HI) << 8) | inb(dev->iobase + PCL812_AD_LO); } - outb(0, dev->iobase + PCL812_MODE); - return n; + if (devpriv->dmabytestomove[0] > devpriv->hwdmasize) { + devpriv->dmabytestomove[0] = devpriv->hwdmasize; + devpriv->ai_eos = 0; + } + if (devpriv->dmabytestomove[1] > devpriv->hwdmasize) { + devpriv->dmabytestomove[1] = devpriv->hwdmasize; + devpriv->ai_eos = 0; + } + devpriv->next_dma_buf = 0; + set_dma_mode(devpriv->dma, DMA_MODE_READ); + dma_flags = claim_dma_lock(); + clear_dma_ff(devpriv->dma); + set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); + set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]); + release_dma_lock(dma_flags); + enable_dma(devpriv->dma); } -/* -============================================================================== -*/ -static int pcl812_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_ai_setup_next_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pcl812_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); - int i; + unsigned long dma_flags; - for (i = 0; i < insn->n; i++) { - outb((data[i] & 0xff), - dev->iobase + (chan ? PCL812_DA2_LO : PCL812_DA1_LO)); - outb((data[i] >> 8) & 0x0f, - dev->iobase + (chan ? PCL812_DA2_HI : PCL812_DA1_HI)); - devpriv->ao_readback[chan] = data[i]; + devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; + disable_dma(devpriv->dma); + set_dma_mode(devpriv->dma, DMA_MODE_READ); + dma_flags = claim_dma_lock(); + set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]); + if (devpriv->ai_eos) { + set_dma_count(devpriv->dma, + devpriv->dmabytestomove[devpriv->next_dma_buf]); + } else { + if (devpriv->dma_runs_to_end) { + set_dma_count(devpriv->dma, + devpriv->dmabytestomove[devpriv-> + next_dma_buf]); + } else { + set_dma_count(devpriv->dma, devpriv->last_dma_run); + } + devpriv->dma_runs_to_end--; } - - return i; + release_dma_lock(dma_flags); + enable_dma(devpriv->dma); } -/* -============================================================================== -*/ -static int pcl812_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_ai_set_chan_range(struct comedi_device *dev, + unsigned int chanspec, char wait) { struct pcl812_private *devpriv = dev->private; - int chan = CR_CHAN(insn->chanspec); - int i; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int mux = 0; - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; + if (chanspec == devpriv->last_ai_chanspec) + return; - return i; -} + devpriv->last_ai_chanspec = chanspec; -/* -============================================================================== -*/ -static int pcl812_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - data[1] = inb(dev->iobase + PCL812_DI_LO); - data[1] |= inb(dev->iobase + PCL812_DI_HI) << 8; - - return insn->n; -} - -static int pcl812_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - if (comedi_dio_update_state(s, data)) { - outb(s->state & 0xff, dev->iobase + PCL812_DO_LO); - outb((s->state >> 8), dev->iobase + PCL812_DO_HI); + if (devpriv->use_mpc508) { + if (devpriv->use_diff) { + mux |= PCL812_MUX_CS0 | PCL812_MUX_CS1; + } else { + if (chan < 8) + mux |= PCL812_MUX_CS0; + else + mux |= PCL812_MUX_CS1; + } } - data[1] = s->state; + outb(mux | PCL812_MUX_CHAN(chan), dev->iobase + PCL812_MUX_REG); + outb(range + devpriv->range_correction, dev->iobase + PCL812_RANGE_REG); - return insn->n; + if (wait) + /* + * XXX this depends on selected range and can be very long for + * some high gain ranges! + */ + udelay(devpriv->max_812_ai_mode0_rangewait); +} + +static void pcl812_ai_clear_eoc(struct comedi_device *dev) +{ + /* writing any value clears the interrupt request */ + outb(0, dev->iobase + PCL812_STATUS_REG); +} + +static void pcl812_ai_soft_trig(struct comedi_device *dev) +{ + /* writing any value triggers a software conversion */ + outb(255, dev->iobase + PCL812_SOFTTRIG_REG); +} + +static unsigned int pcl812_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int val; + + val = inb(dev->iobase + PCL812_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL812_AI_LSB_REG); + + return val & s->maxdata; +} + +static int pcl812_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + if (s->maxdata > 0x0fff) { + status = inb(dev->iobase + PCL812_STATUS_REG); + if ((status & PCL812_STATUS_DRDY) == 0) + return 0; + } else { + status = inb(dev->iobase + PCL812_AI_MSB_REG); + if ((status & PCL812_AI_MSB_DRDY) == 0) + return 0; + } + return -EBUSY; } -/* -============================================================================== -*/ static int pcl812_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { @@ -545,7 +721,7 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev, struct pcl812_private *devpriv = dev->private; int err = 0; unsigned int flags; - int tmp, divisor1, divisor2; + int tmp; /* Step 1 : check if triggers are trivially valid */ @@ -600,8 +776,9 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev, if (cmd->convert_src == TRIG_TIMER) { tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(board->i8254_osc_base, - &divisor1, &divisor2, + i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, + &devpriv->divisor1, + &devpriv->divisor2, &cmd->convert_arg, cmd->flags); if (cmd->convert_arg < board->ai_ns_min) cmd->convert_arg = board->ai_ns_min; @@ -615,54 +792,21 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev, return 0; } -/* -============================================================================== -*/ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct pcl812_board *board = comedi_board(dev); struct pcl812_private *devpriv = dev->private; - unsigned int divisor1 = 0, divisor2 = 0, i, dma_flags, bytes; struct comedi_cmd *cmd = &s->async->cmd; + unsigned int ctrl = 0; + unsigned int i; - if (cmd->start_src != TRIG_NOW) - return -EINVAL; - if (cmd->scan_begin_src != TRIG_FOLLOW) - return -EINVAL; - if (devpriv->use_ext_trg) { - if (cmd->convert_src != TRIG_EXT) - return -EINVAL; - } else { - if (cmd->convert_src != TRIG_TIMER) - return -EINVAL; - } - if (cmd->scan_end_src != TRIG_COUNT) - return -EINVAL; - if (cmd->scan_end_arg != cmd->chanlist_len) - return -EINVAL; - if (cmd->chanlist_len > MAX_CHANLIST_LEN) - return -EINVAL; + pcl812_start_pacer(dev, false); - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < board->ai_ns_min) - cmd->convert_arg = board->ai_ns_min; - i8253_cascade_ns_to_timer(board->i8254_osc_base, - &divisor1, &divisor2, - &cmd->convert_arg, cmd->flags); - } - - start_pacer(dev, -1, 0, 0); /* stop pacer */ - - devpriv->ai_n_chan = cmd->chanlist_len; - memcpy(devpriv->ai_chanlist, cmd->chanlist, - sizeof(unsigned int) * cmd->scan_end_arg); - /* select first channel and range */ - setup_range_channel(dev, s, devpriv->ai_chanlist[0], 1); + pcl812_ai_set_chan_range(dev, cmd->chanlist[0], 1); if (devpriv->dma) { /* check if we can use DMA transfer */ devpriv->ai_dma = 1; - for (i = 1; i < devpriv->ai_n_chan; i++) - if (devpriv->ai_chanlist[0] != devpriv->ai_chanlist[i]) { + for (i = 1; i < cmd->chanlist_len; i++) + if (cmd->chanlist[0] != cmd->chanlist[i]) { /* we cann't use DMA :-( */ devpriv->ai_dma = 0; break; @@ -670,212 +814,105 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } else devpriv->ai_dma = 0; - devpriv->ai_flags = cmd->flags; - devpriv->ai_data_len = s->async->prealloc_bufsz; - if (cmd->stop_src == TRIG_COUNT) { - devpriv->ai_scans = cmd->stop_arg; - devpriv->ai_neverending = 0; - } else { - devpriv->ai_scans = 0; - devpriv->ai_neverending = 1; - } - devpriv->ai_act_scan = 0; devpriv->ai_poll_ptr = 0; s->async->cur_chan = 0; /* don't we want wake up every scan? */ - if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { + if (cmd->flags & TRIG_WAKE_EOS) { devpriv->ai_eos = 1; /* DMA is useless for this situation */ - if (devpriv->ai_n_chan == 1) + if (cmd->chanlist_len == 1) devpriv->ai_dma = 0; } - if (devpriv->ai_dma) { - /* we use EOS, so adapt DMA buffer to one scan */ - if (devpriv->ai_eos) { - devpriv->dmabytestomove[0] = - devpriv->ai_n_chan * sizeof(short); - devpriv->dmabytestomove[1] = - devpriv->ai_n_chan * sizeof(short); - devpriv->dma_runs_to_end = 1; - } else { - devpriv->dmabytestomove[0] = devpriv->hwdmasize[0]; - devpriv->dmabytestomove[1] = devpriv->hwdmasize[1]; - if (devpriv->ai_data_len < devpriv->hwdmasize[0]) - devpriv->dmabytestomove[0] = - devpriv->ai_data_len; - if (devpriv->ai_data_len < devpriv->hwdmasize[1]) - devpriv->dmabytestomove[1] = - devpriv->ai_data_len; - if (devpriv->ai_neverending) { - devpriv->dma_runs_to_end = 1; - } else { - /* how many samples we must transfer? */ - bytes = devpriv->ai_n_chan * - devpriv->ai_scans * sizeof(short); - - /* how many DMA pages we must fill */ - devpriv->dma_runs_to_end = - bytes / devpriv->dmabytestomove[0]; - - /* on last dma transfer must be moved */ - devpriv->last_dma_run = - bytes % devpriv->dmabytestomove[0]; - if (devpriv->dma_runs_to_end == 0) - devpriv->dmabytestomove[0] = - devpriv->last_dma_run; - devpriv->dma_runs_to_end--; - } - } - if (devpriv->dmabytestomove[0] > devpriv->hwdmasize[0]) { - devpriv->dmabytestomove[0] = devpriv->hwdmasize[0]; - devpriv->ai_eos = 0; - } - if (devpriv->dmabytestomove[1] > devpriv->hwdmasize[1]) { - devpriv->dmabytestomove[1] = devpriv->hwdmasize[1]; - devpriv->ai_eos = 0; - } - devpriv->next_dma_buf = 0; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); - set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]); - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); - } + if (devpriv->ai_dma) + pcl812_ai_setup_dma(dev, s); switch (cmd->convert_src) { case TRIG_TIMER: - start_pacer(dev, 1, divisor1, divisor2); + pcl812_start_pacer(dev, true); break; } - if (devpriv->ai_dma) /* let's go! */ - outb(devpriv->mode_reg_int | 2, dev->iobase + PCL812_MODE); - else /* let's go! */ - outb(devpriv->mode_reg_int | 6, dev->iobase + PCL812_MODE); + if (devpriv->ai_dma) + ctrl |= PCL812_CTRL_PACER_DMA_TRIG; + else + ctrl |= PCL812_CTRL_PACER_EOC_TRIG; + outb(devpriv->mode_reg_int | ctrl, dev->iobase + PCL812_CTRL_REG); return 0; } -/* -============================================================================== -*/ -static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d) +static bool pcl812_ai_next_chan(struct comedi_device *dev, + struct comedi_subdevice *s) { - char err = 1; - unsigned int mask, timeout; - struct comedi_device *dev = d; struct pcl812_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; + + s->async->events |= COMEDI_CB_BLOCK; + + s->async->cur_chan++; + if (s->async->cur_chan >= cmd->chanlist_len) { + s->async->cur_chan = 0; + devpriv->ai_act_scan++; + s->async->events |= COMEDI_CB_EOS; + } + + if (cmd->stop_src == TRIG_COUNT && + devpriv->ai_act_scan >= cmd->stop_arg) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + return false; + } + + return true; +} + +static void pcl812_handle_eoc(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct comedi_cmd *cmd = &s->async->cmd; unsigned int next_chan; - s->async->events = 0; - - timeout = 50; /* wait max 50us, it must finish under 33us */ - if (devpriv->ai_is16b) { - mask = 0xffff; - while (timeout--) { - if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) { - err = 0; - break; - } - udelay(1); - } - } else { - mask = 0x0fff; - while (timeout--) { - if (!(inb(dev->iobase + PCL812_AD_HI) & PCL812_DRDY)) { - err = 0; - break; - } - udelay(1); - } - } - - if (err) { + if (pcl812_ai_eoc(dev, s, NULL, 0)) { dev_dbg(dev->class_dev, "A/D cmd IRQ without DRDY!\n"); - pcl812_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + return; } - comedi_buf_put(s->async, - ((inb(dev->iobase + PCL812_AD_HI) << 8) | - inb(dev->iobase + PCL812_AD_LO)) & mask); + comedi_buf_put(s->async, pcl812_ai_get_sample(dev, s)); /* Set up next channel. Added by abbotti 2010-01-20, but untested. */ next_chan = s->async->cur_chan + 1; - if (next_chan >= devpriv->ai_n_chan) + if (next_chan >= cmd->chanlist_len) next_chan = 0; - if (devpriv->ai_chanlist[s->async->cur_chan] != - devpriv->ai_chanlist[next_chan]) - setup_range_channel(dev, s, devpriv->ai_chanlist[next_chan], 0); + if (cmd->chanlist[s->async->cur_chan] != cmd->chanlist[next_chan]) + pcl812_ai_set_chan_range(dev, cmd->chanlist[next_chan], 0); - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ - - s->async->cur_chan = next_chan; - if (next_chan == 0) { /* one scan done */ - devpriv->ai_act_scan++; - if (!(devpriv->ai_neverending)) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - pcl812_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - } - } - - comedi_event(dev, s); - return IRQ_HANDLED; + pcl812_ai_next_chan(dev, s); } -/* -============================================================================== -*/ static void transfer_from_dma_buf(struct comedi_device *dev, struct comedi_subdevice *s, unsigned short *ptr, unsigned int bufptr, unsigned int len) { - struct pcl812_private *devpriv = dev->private; unsigned int i; - s->async->events = 0; for (i = len; i; i--) { - /* get one sample */ comedi_buf_put(s->async, ptr[bufptr++]); - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan++; - if (!devpriv->ai_neverending) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - pcl812_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - break; - } - } + if (!pcl812_ai_next_chan(dev, s)) + break; } - - comedi_event(dev, s); } -/* -============================================================================== -*/ -static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d) +static void pcl812_handle_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; struct pcl812_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - unsigned long dma_flags; int len, bufptr; unsigned short *ptr; @@ -883,58 +920,36 @@ static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d) len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) - devpriv->ai_poll_ptr; - devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; - disable_dma(devpriv->dma); - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]); - if (devpriv->ai_eos) { - set_dma_count(devpriv->dma, - devpriv->dmabytestomove[devpriv->next_dma_buf]); - } else { - if (devpriv->dma_runs_to_end) { - set_dma_count(devpriv->dma, - devpriv->dmabytestomove[devpriv-> - next_dma_buf]); - } else { - set_dma_count(devpriv->dma, devpriv->last_dma_run); - } - devpriv->dma_runs_to_end--; - } - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); - - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ + pcl812_ai_setup_next_dma(dev, s); bufptr = devpriv->ai_poll_ptr; devpriv->ai_poll_ptr = 0; transfer_from_dma_buf(dev, s, ptr, bufptr, len); - - return IRQ_HANDLED; } -/* -============================================================================== -*/ -static irqreturn_t interrupt_pcl812(int irq, void *d) +static irqreturn_t pcl812_interrupt(int irq, void *d) { struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; struct pcl812_private *devpriv = dev->private; if (!dev->attached) { - comedi_error(dev, "spurious interrupt"); + pcl812_ai_clear_eoc(dev); return IRQ_HANDLED; } + if (devpriv->ai_dma) - return interrupt_pcl812_ai_dma(irq, d); + pcl812_handle_dma(dev, s); else - return interrupt_pcl812_ai_int(irq, d); + pcl812_handle_eoc(dev, s); + + pcl812_ai_clear_eoc(dev); + + cfc_handle_events(dev, s); + return IRQ_HANDLED; } -/* -============================================================================== -*/ static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl812_private *devpriv = dev->private; @@ -979,72 +994,6 @@ static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) return s->async->buf_write_count - s->async->buf_read_count; } -/* -============================================================================== -*/ -static void setup_range_channel(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int rangechan, char wait) -{ - struct pcl812_private *devpriv = dev->private; - unsigned char chan_reg = CR_CHAN(rangechan); /* normal board */ - /* gain index */ - unsigned char gain_reg = CR_RANGE(rangechan) + - devpriv->range_correction; - - if ((chan_reg == devpriv->old_chan_reg) - && (gain_reg == devpriv->old_gain_reg)) - return; /* we can return, no change */ - - devpriv->old_chan_reg = chan_reg; - devpriv->old_gain_reg = gain_reg; - - if (devpriv->use_MPC) { - if (devpriv->use_diff) { - chan_reg = chan_reg | 0x30; /* DIFF inputs */ - } else { - if (chan_reg & 0x80) - /* SE inputs 8-15 */ - chan_reg = chan_reg | 0x20; - else - /* SE inputs 0-7 */ - chan_reg = chan_reg | 0x10; - } - } - - outb(chan_reg, dev->iobase + PCL812_MUX); /* select channel */ - outb(gain_reg, dev->iobase + PCL812_GAIN); /* select gain */ - - - if (wait) - /* - * XXX this depends on selected range and can be very long for - * some high gain ranges! - */ - udelay(devpriv->max_812_ai_mode0_rangewait); -} - -/* -============================================================================== -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2) -{ - outb(0xb4, dev->iobase + PCL812_CTRCTL); - outb(0x74, dev->iobase + PCL812_CTRCTL); - udelay(1); - - if (mode == 1) { - outb(divisor2 & 0xff, dev->iobase + PCL812_CTR2); - outb((divisor2 >> 8) & 0xff, dev->iobase + PCL812_CTR2); - outb(divisor1 & 0xff, dev->iobase + PCL812_CTR1); - outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1); - } -} - -/* -============================================================================== -*/ static int pcl812_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { @@ -1052,131 +1001,301 @@ static int pcl812_ai_cancel(struct comedi_device *dev, if (devpriv->ai_dma) disable_dma(devpriv->dma); - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ - /* Stop A/D */ - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - start_pacer(dev, -1, 0, 0); /* stop 8254 */ - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ + + outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG, + dev->iobase + PCL812_CTRL_REG); + pcl812_start_pacer(dev, false); + pcl812_ai_clear_eoc(dev); return 0; } -/* -============================================================================== -*/ +static int pcl812_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl812_private *devpriv = dev->private; + int ret = 0; + int i; + + outb(devpriv->mode_reg_int | PCL812_CTRL_SOFT_TRIG, + dev->iobase + PCL812_CTRL_REG); + + pcl812_ai_set_chan_range(dev, insn->chanspec, 1); + + for (i = 0; i < insn->n; i++) { + pcl812_ai_clear_eoc(dev); + pcl812_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, pcl812_ai_eoc, 0); + if (ret) + break; + + data[i] = pcl812_ai_get_sample(dev, s); + } + outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG, + dev->iobase + PCL812_CTRL_REG); + pcl812_ai_clear_eoc(dev); + + return ret ? ret : insn->n; +} + +static int pcl812_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl812_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) { + outb((data[i] & 0xff), + dev->iobase + PCL812_AO_LSB_REG(chan)); + outb((data[i] >> 8) & 0x0f, + dev->iobase + PCL812_AO_MSB_REG(chan)); + devpriv->ao_readback[chan] = data[i]; + } + + return insn->n; +} + +static int pcl812_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl812_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return insn->n; +} + +static int pcl812_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + PCL812_DI_LSB_REG) | + (inb(dev->iobase + PCL812_DI_MSB_REG) << 8); + + return insn->n; +} + +static int pcl812_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase + PCL812_DO_LSB_REG); + outb((s->state >> 8), dev->iobase + PCL812_DO_MSB_REG); + } + + data[1] = s->state; + + return insn->n; +} + static void pcl812_reset(struct comedi_device *dev) { const struct pcl812_board *board = comedi_board(dev); struct pcl812_private *devpriv = dev->private; + unsigned int chan; - outb(0, dev->iobase + PCL812_MUX); - outb(0 + devpriv->range_correction, dev->iobase + PCL812_GAIN); - devpriv->old_chan_reg = -1; /* invalidate chain/gain memory */ - devpriv->old_gain_reg = -1; + /* disable analog input trigger */ + outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG, + dev->iobase + PCL812_CTRL_REG); + pcl812_ai_clear_eoc(dev); + /* stop pacer */ + if (board->IRQbits) + pcl812_start_pacer(dev, false); + + /* + * Invalidate last_ai_chanspec then set analog input to + * known channel/range. + */ + devpriv->last_ai_chanspec = CR_PACK(16, 0, 0); + pcl812_ai_set_chan_range(dev, CR_PACK(0, 0, 0), 0); + + /* set analog output channels to 0V */ + for (chan = 0; chan < board->n_aochan; chan++) { + outb(0, dev->iobase + PCL812_AO_LSB_REG(chan)); + outb(0, dev->iobase + PCL812_AO_MSB_REG(chan)); + } + + /* set all digital outputs low */ + if (board->has_dio) { + outb(0, dev->iobase + PCL812_DO_MSB_REG); + outb(0, dev->iobase + PCL812_DO_LSB_REG); + } +} + +static void pcl812_set_ai_range_table(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_devconfig *it) +{ + const struct pcl812_board *board = comedi_board(dev); + struct pcl812_private *devpriv = dev->private; + + /* default to the range table from the boardinfo */ + s->range_table = board->rangelist_ai; + + /* now check the user config option based on the boardtype */ switch (board->board_type) { case boardPCL812PG: + if (it->options[4] == 1) + s->range_table = &range_pcl812pg2_ai; + break; case boardPCL812: - case boardACL8112: - case boardACL8216: - outb(0, dev->iobase + PCL812_DA2_LO); - outb(0, dev->iobase + PCL812_DA2_HI); - case boardA821: - outb(0, dev->iobase + PCL812_DA1_LO); - outb(0, dev->iobase + PCL812_DA1_HI); - start_pacer(dev, -1, 0, 0); /* stop 8254 */ - outb(0, dev->iobase + PCL812_DO_HI); - outb(0, dev->iobase + PCL812_DO_LO); - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - outb(0, dev->iobase + PCL812_CLRINT); + switch (it->options[4]) { + case 0: + s->range_table = &range_bipolar10; + break; + case 1: + s->range_table = &range_bipolar5; + break; + case 2: + s->range_table = &range_bipolar2_5; + break; + case 3: + s->range_table = &range812_bipolar1_25; + break; + case 4: + s->range_table = &range812_bipolar0_625; + break; + case 5: + s->range_table = &range812_bipolar0_3125; + break; + default: + s->range_table = &range_bipolar10; + break; + } break; case boardPCL813B: - case boardPCL813: + if (it->options[1] == 1) + s->range_table = &range_pcl813b2_ai; + break; case boardISO813: + switch (it->options[1]) { + case 0: + s->range_table = &range_iso813_1_ai; + break; + case 1: + s->range_table = &range_iso813_1_2_ai; + break; + case 2: + s->range_table = &range_iso813_2_ai; + devpriv->range_correction = 1; + break; + case 3: + s->range_table = &range_iso813_2_2_ai; + devpriv->range_correction = 1; + break; + default: + s->range_table = &range_iso813_1_ai; + break; + } + break; case boardACL8113: - udelay(5); + switch (it->options[1]) { + case 0: + s->range_table = &range_acl8113_1_ai; + break; + case 1: + s->range_table = &range_acl8113_1_2_ai; + break; + case 2: + s->range_table = &range_acl8113_2_ai; + devpriv->range_correction = 1; + break; + case 3: + s->range_table = &range_acl8113_2_2_ai; + devpriv->range_correction = 1; + break; + default: + s->range_table = &range_acl8113_1_ai; + break; + } break; } - udelay(5); } static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl812_board *board = comedi_board(dev); struct pcl812_private *devpriv; - int ret, subdev; - unsigned int dma; - unsigned long pages; struct comedi_subdevice *s; int n_subdevices; - - ret = comedi_request_region(dev, it->options[0], board->io_range); - if (ret) - return ret; + int subdev; + int ret; + int i; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; + ret = comedi_request_region(dev, it->options[0], 0x10); + if (ret) + return ret; + if ((1 << it->options[1]) & board->IRQbits) { - ret = request_irq(it->options[1], interrupt_pcl812, 0, + ret = request_irq(it->options[1], pcl812_interrupt, 0, dev->board_name, dev); if (ret == 0) dev->irq = it->options[1]; } - dma = 0; - devpriv->dma = dma; - if (!dev->irq) - goto no_dma; /* if we haven't IRQ, we can't use DMA */ - if (board->DMAbits != 0) { /* board support DMA */ - dma = it->options[2]; - if (((1 << dma) & board->DMAbits) == 0) { - dev_err(dev->class_dev, - "DMA is out of allowed range, FAIL!\n"); - return -EINVAL; /* Bad DMA */ - } - ret = request_dma(dma, dev->board_name); + /* we need an IRQ to do DMA on channel 3 or 1 */ + if (dev->irq && board->has_dma && + (it->options[2] == 3 || it->options[2] == 1)) { + ret = request_dma(it->options[2], dev->board_name); if (ret) { dev_err(dev->class_dev, - "unable to allocate DMA %u, FAIL!\n", dma); - return -EBUSY; /* DMA isn't free */ - } - devpriv->dma = dma; - pages = 1; /* we want 8KB */ - devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[0]) { - dev_err(dev->class_dev, - "unable to allocate DMA buffer, FAIL!\n"); - /* - * maybe experiment with try_to_free_pages() - * will help .... - */ - return -EBUSY; /* no buffer :-( */ - } - devpriv->dmapages[0] = pages; - devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); - devpriv->hwdmasize[0] = PAGE_SIZE * (1 << pages); - devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[1]) { - dev_err(dev->class_dev, - "unable to allocate DMA buffer, FAIL!\n"); + "unable to request DMA channel %d\n", + it->options[2]); return -EBUSY; } - devpriv->dmapages[1] = pages; - devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]); - devpriv->hwdmasize[1] = PAGE_SIZE * (1 << pages); - } -no_dma: + devpriv->dma = it->options[2]; - n_subdevices = 0; - if (board->n_aichan > 0) - n_subdevices++; + devpriv->dmapages = 1; /* we want 8KB */ + devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; + + for (i = 0; i < 2; i++) { + unsigned long dmabuf; + + dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); + if (!dmabuf) + return -ENOMEM; + + devpriv->dmabuf[i] = dmabuf; + devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); + } + } + + /* differential analog inputs? */ + switch (board->board_type) { + case boardA821: + if (it->options[2] == 1) + devpriv->use_diff = 1; + break; + case boardACL8112: + case boardACL8216: + if (it->options[4] == 1) + devpriv->use_diff = 1; + break; + } + + n_subdevices = 1; /* all boardtypes have analog inputs */ if (board->n_aochan > 0) n_subdevices++; - if (board->n_dichan > 0) - n_subdevices++; - if (board->n_dochan > 0) - n_subdevices++; + if (board->has_dio) + n_subdevices += 2; ret = comedi_alloc_subdevices(dev, n_subdevices); if (ret) @@ -1184,146 +1303,47 @@ no_dma: subdev = 0; - /* analog input */ - if (board->n_aichan > 0) { - s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE; - switch (board->board_type) { - case boardA821: - if (it->options[2] == 1) { - s->n_chan = board->n_aichan_diff; - s->subdev_flags |= SDF_DIFF; - devpriv->use_diff = 1; - } else { - s->n_chan = board->n_aichan; - s->subdev_flags |= SDF_GROUND; - } - break; - case boardACL8112: - case boardACL8216: - if (it->options[4] == 1) { - s->n_chan = board->n_aichan_diff; - s->subdev_flags |= SDF_DIFF; - devpriv->use_diff = 1; - } else { - s->n_chan = board->n_aichan; - s->subdev_flags |= SDF_GROUND; - } - break; - default: - s->n_chan = board->n_aichan; - s->subdev_flags |= SDF_GROUND; - break; - } - s->maxdata = board->ai_maxdata; - s->range_table = board->rangelist_ai; - if (board->board_type == boardACL8216) - s->insn_read = acl8216_ai_insn_read; - else - s->insn_read = pcl812_ai_insn_read; - - devpriv->use_MPC = board->haveMPC508; - if (dev->irq) { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->len_chanlist = MAX_CHANLIST_LEN; - s->do_cmdtest = pcl812_ai_cmdtest; - s->do_cmd = pcl812_ai_cmd; - s->poll = pcl812_ai_poll; - s->cancel = pcl812_ai_cancel; - } - switch (board->board_type) { - case boardPCL812PG: - if (it->options[4] == 1) - s->range_table = &range_pcl812pg2_ai; - break; - case boardPCL812: - switch (it->options[4]) { - case 0: - s->range_table = &range_bipolar10; - break; - case 1: - s->range_table = &range_bipolar5; - break; - case 2: - s->range_table = &range_bipolar2_5; - break; - case 3: - s->range_table = &range812_bipolar1_25; - break; - case 4: - s->range_table = &range812_bipolar0_625; - break; - case 5: - s->range_table = &range812_bipolar0_3125; - break; - default: - s->range_table = &range_bipolar10; - break; - } - break; - break; - case boardPCL813B: - if (it->options[1] == 1) - s->range_table = &range_pcl813b2_ai; - break; - case boardISO813: - switch (it->options[1]) { - case 0: - s->range_table = &range_iso813_1_ai; - break; - case 1: - s->range_table = &range_iso813_1_2_ai; - break; - case 2: - s->range_table = &range_iso813_2_ai; - devpriv->range_correction = 1; - break; - case 3: - s->range_table = &range_iso813_2_2_ai; - devpriv->range_correction = 1; - break; - default: - s->range_table = &range_iso813_1_ai; - break; - } - break; - case boardACL8113: - switch (it->options[1]) { - case 0: - s->range_table = &range_acl8113_1_ai; - break; - case 1: - s->range_table = &range_acl8113_1_2_ai; - break; - case 2: - s->range_table = &range_acl8113_2_ai; - devpriv->range_correction = 1; - break; - case 3: - s->range_table = &range_acl8113_2_2_ai; - devpriv->range_correction = 1; - break; - default: - s->range_table = &range_acl8113_1_ai; - break; - } - break; - } - subdev++; + /* Analog Input subdevice */ + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE; + if (devpriv->use_diff) { + s->subdev_flags |= SDF_DIFF; + s->n_chan = board->n_aichan / 2; + } else { + s->subdev_flags |= SDF_GROUND; + s->n_chan = board->n_aichan; } + s->maxdata = board->has_16bit_ai ? 0xffff : 0x0fff; + + pcl812_set_ai_range_table(dev, s, it); + + s->insn_read = pcl812_ai_insn_read; + + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = MAX_CHANLIST_LEN; + s->do_cmdtest = pcl812_ai_cmdtest; + s->do_cmd = pcl812_ai_cmd; + s->poll = pcl812_ai_poll; + s->cancel = pcl812_ai_cancel; + } + + devpriv->use_mpc508 = board->has_mpc508_mux; + + subdev++; /* analog output */ if (board->n_aochan > 0) { s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = board->n_aochan; - s->maxdata = 0xfff; - s->range_table = board->rangelist_ao; - s->insn_read = pcl812_ao_insn_read; - s->insn_write = pcl812_ao_insn_write; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->n_chan = board->n_aochan; + s->maxdata = 0xfff; + s->range_table = &range_unipolar5; + s->insn_read = pcl812_ao_insn_read; + s->insn_write = pcl812_ao_insn_write; switch (board->board_type) { case boardA821: if (it->options[3] == 1) @@ -1342,33 +1362,30 @@ no_dma: subdev++; } - /* digital input */ - if (board->n_dichan > 0) { + if (board->has_dio) { + /* Digital Input subdevice */ s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = board->n_dichan; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = pcl812_di_insn_bits; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl812_di_insn_bits; subdev++; - } - /* digital output */ - if (board->n_dochan > 0) { + /* Digital Output subdevice */ s = &dev->subdevices[subdev]; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_dochan; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = pcl812_do_insn_bits; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl812_do_insn_bits; subdev++; } switch (board->board_type) { case boardACL8216: - devpriv->ai_is16b = 1; case boardPCL812PG: case boardPCL812: case boardACL8112: @@ -1390,8 +1407,6 @@ no_dma: break; } - devpriv->valid = 1; - pcl812_reset(dev); return 0; @@ -1403,72 +1418,15 @@ static void pcl812_detach(struct comedi_device *dev) if (devpriv) { if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); + free_pages(devpriv->dmabuf[0], devpriv->dmapages); if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); + free_pages(devpriv->dmabuf[1], devpriv->dmapages); if (devpriv->dma) free_dma(devpriv->dma); } comedi_legacy_detach(dev); } -static const struct pcl812_board boardtypes[] = { - {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff, - 33000, I8254_OSC_BASE_2MHZ, &range_bipolar10, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, - 33000, I8254_OSC_BASE_2MHZ, &range_pcl812pg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_pcl812pg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b_ai, &range_unipolar5, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b_ai, NULL, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_a821pgh_ai, &range_unipolar5, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 8000, I8254_OSC_BASE_2MHZ, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 8000, I8254_OSC_BASE_2MHZ, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_pcl813b_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_pcl813b_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_acl8113_1_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_iso813_1_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff, - 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b2_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff, - 10000, I8254_OSC_BASE_2MHZ, &range_pcl813b2_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, -}; - static struct comedi_driver pcl812_driver = { .driver_name = "pcl812", .module = THIS_MODULE, diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c index e9d470459933..6f276f23fabe 100644 --- a/drivers/staging/comedi/drivers/pcl816.c +++ b/drivers/staging/comedi/drivers/pcl816.c @@ -44,40 +44,38 @@ Configuration Options: #include "comedi_fc.h" #include "8253.h" -/* boards constants */ -/* IO space len */ -#define PCLx1x_RANGE 16 - -/* INTEL 8254 counters */ -#define PCL816_CTR0 4 -#define PCL816_CTR1 5 -#define PCL816_CTR2 6 -/* R: counter read-back register W: counter control */ -#define PCL816_CTRCTL 7 - -/* R: A/D high byte W: A/D range control */ -#define PCL816_RANGE 9 -/* W: clear INT request */ -#define PCL816_CLRINT 10 -/* R: next mux scan channel W: mux scan channel & range control pointer */ -#define PCL816_MUX 11 -/* R/W: operation control register */ -#define PCL816_CONTROL 12 - -/* R: return status byte W: set DMA/IRQ */ -#define PCL816_STATUS 13 -#define PCL816_STATUS_DRDY_MASK 0x80 - -/* R: low byte of A/D W: soft A/D trigger */ -#define PCL816_AD_LO 8 -/* R: high byte of A/D W: A/D range control */ -#define PCL816_AD_HI 9 - -/* type of interrupt handler */ -#define INT_TYPE_AI1_INT 1 -#define INT_TYPE_AI1_DMA 2 -#define INT_TYPE_AI3_INT 4 -#define INT_TYPE_AI3_DMA 5 +/* + * Register I/O map + */ +#define PCL816_DO_DI_LSB_REG 0x00 +#define PCL816_DO_DI_MSB_REG 0x01 +#define PCL816_TIMER_BASE 0x04 +#define PCL816_AI_LSB_REG 0x08 +#define PCL816_AI_MSB_REG 0x09 +#define PCL816_RANGE_REG 0x09 +#define PCL816_CLRINT_REG 0x0a +#define PCL816_MUX_REG 0x0b +#define PCL816_MUX_SCAN(_first, _last) (((_last) << 4) | (_first)) +#define PCL816_CTRL_REG 0x0c +#define PCL816_CTRL_DISABLE_TRIG (0 << 0) +#define PCL816_CTRL_SOFT_TRIG (1 << 0) +#define PCL816_CTRL_PACER_TRIG (1 << 1) +#define PCL816_CTRL_EXT_TRIG (1 << 2) +#define PCL816_CTRL_POE (1 << 3) +#define PCL816_CTRL_DMAEN (1 << 4) +#define PCL816_CTRL_INTEN (1 << 5) +#define PCL816_CTRL_DMASRC_SLOT0 (0 << 6) +#define PCL816_CTRL_DMASRC_SLOT1 (1 << 6) +#define PCL816_CTRL_DMASRC_SLOT2 (2 << 6) +#define PCL816_STATUS_REG 0x0d +#define PCL816_STATUS_NEXT_CHAN_MASK (0xf << 0) +#define PCL816_STATUS_INTSRC_MASK (3 << 4) +#define PCL816_STATUS_INTSRC_SLOT0 (0 << 4) +#define PCL816_STATUS_INTSRC_SLOT1 (1 << 4) +#define PCL816_STATUS_INTSRC_SLOT2 (2 << 4) +#define PCL816_STATUS_INTSRC_DMA (3 << 4) +#define PCL816_STATUS_INTACT (1 << 6) +#define PCL816_STATUS_DRDY (1 << 7) #define MAGIC_DMA_WORD 0x5a5a @@ -95,314 +93,284 @@ static const struct comedi_lrange range_pcl816 = { }; struct pcl816_board { + const char *name; + int ai_maxdata; + int ao_maxdata; + int ai_chanlist; +}; - const char *name; /* board name */ - int n_ranges; /* len of range list */ - int n_aichan; /* num of A/D chans in diferencial mode */ - unsigned int ai_ns_min; /* minimal allowed delay between samples (in ns) */ - int n_aochan; /* num of D/A chans */ - int n_dichan; /* num of DI chans */ - int n_dochan; /* num of DO chans */ - const struct comedi_lrange *ai_range_type; /* default A/D rangelist */ - const struct comedi_lrange *ao_range_type; /* default D/A rangelist */ - unsigned int io_range; /* len of IO space */ - unsigned int IRQbits; /* allowed interrupts */ - unsigned int DMAbits; /* allowed DMA chans */ - int ai_maxdata; /* maxdata for A/D */ - int ao_maxdata; /* maxdata for D/A */ - int ai_chanlist; /* allowed len of channel list A/D */ - int ao_chanlist; /* allowed len of channel list D/A */ - int i8254_osc_base; /* 1/frequency of on board oscilator in ns */ +static const struct pcl816_board boardtypes[] = { + { + .name = "pcl816", + .ai_maxdata = 0xffff, + .ao_maxdata = 0xffff, + .ai_chanlist = 1024, + }, { + .name = "pcl814b", + .ai_maxdata = 0x3fff, + .ao_maxdata = 0x3fff, + .ai_chanlist = 1024, + }, }; struct pcl816_private { - unsigned int dma; /* used DMA, 0=don't use DMA */ + unsigned int dmapages; + unsigned int hwdmasize; unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */ - unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */ unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */ - unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */ - unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */ int next_dma_buf; /* which DMA buffer will be used next round */ long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */ unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */ - - unsigned int ai_scans; /* len of scanlist */ - unsigned char ai_neverending; /* if=1, then we do neverending record (you must use cancel()) */ - int irq_blocked; /* 1=IRQ now uses any subdev */ - int irq_was_now_closed; /* when IRQ finish, there's stored int816_mode for last interrupt */ - int int816_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */ - struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */ int ai_act_scan; /* how many scans we finished */ - unsigned int ai_act_chanlist[16]; /* MUX setting for actual AI operations */ - unsigned int ai_act_chanlist_len; /* how long is actual MUX list */ - unsigned int ai_act_chanlist_pos; /* actual position in MUX list */ - unsigned int ai_n_chan; /* how many channels per scan */ unsigned int ai_poll_ptr; /* how many sampes transfer poll */ + unsigned int divisor1; + unsigned int divisor2; + unsigned int ai_cmd_running:1; + unsigned int ai_cmd_canceled:1; }; -/* -============================================================================== -*/ static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int chanlen); -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int seglen); -static int pcl816_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); -static int pcl816_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); - -/* -============================================================================== - ANALOG INPUT MODE0, 816 cards, slow version -*/ -static int pcl816_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int n; - int timeout; - - /* software trigger, DMA and INT off */ - outb(0, dev->iobase + PCL816_CONTROL); - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL816_CLRINT); - - /* Set the input channel */ - outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX); - /* select gain */ - outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE); - - for (n = 0; n < insn->n; n++) { - - outb(0, dev->iobase + PCL816_AD_LO); /* start conversion */ - - timeout = 100; - while (timeout--) { - if (!(inb(dev->iobase + PCL816_STATUS) & - PCL816_STATUS_DRDY_MASK)) { - /* return read value */ - data[n] = - ((inb(dev->iobase + - PCL816_AD_HI) << 8) | - (inb(dev->iobase + PCL816_AD_LO))); - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL816_CLRINT); - break; - } - udelay(1); - } - /* Return timeout error */ - if (!timeout) { - comedi_error(dev, "A/D insn timeout\n"); - data[0] = 0; - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL816_CLRINT); - return -EIO; - } - - } - return n; -} - -/* -============================================================================== - analog input interrupt mode 1 & 3, 818 cards - one sample per interrupt version -*/ -static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d) -{ - struct comedi_device *dev = d; - struct pcl816_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - unsigned char low, hi; - int timeout = 50; /* wait max 50us */ - - while (timeout--) { - if (!(inb(dev->iobase + PCL816_STATUS) & - PCL816_STATUS_DRDY_MASK)) - break; - udelay(1); - } - if (!timeout) { /* timeout, bail error */ - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ - comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); - pcl816_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - - } - - /* get the sample */ - low = inb(dev->iobase + PCL816_AD_LO); - hi = inb(dev->iobase + PCL816_AD_HI); - - comedi_buf_put(s->async, (hi << 8) | low); - - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ - - if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len) - devpriv->ai_act_chanlist_pos = 0; - - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan++; - } - - if (!devpriv->ai_neverending) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - /* all data sampled */ - pcl816_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - } - comedi_event(dev, s); - return IRQ_HANDLED; -} - -/* -============================================================================== - analog input dma mode 1 & 3, 816 cards -*/ -static void transfer_from_dma_buf(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned short *ptr, - unsigned int bufptr, unsigned int len) +static void pcl816_start_pacer(struct comedi_device *dev, bool load_counters) { struct pcl816_private *devpriv = dev->private; - int i; + unsigned long timer_base = dev->iobase + PCL816_TIMER_BASE; - s->async->events = 0; + i8254_set_mode(timer_base, 0, 0, I8254_MODE1 | I8254_BINARY); + i8254_write(timer_base, 0, 0, 0x00ff); + udelay(1); - for (i = 0; i < len; i++) { + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + udelay(1); - comedi_buf_put(s->async, ptr[bufptr++]); - - if (++devpriv->ai_act_chanlist_pos >= - devpriv->ai_act_chanlist_len) { - devpriv->ai_act_chanlist_pos = 0; - } - - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan++; - } - - if (!devpriv->ai_neverending) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - pcl816_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_BLOCK; - break; - } + if (load_counters) { + i8254_write(timer_base, 0, 2, devpriv->divisor2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); } - - comedi_event(dev, s); } -static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d) +static void pcl816_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; struct pcl816_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - int len, bufptr, this_dma_buf; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int dma_flags; + unsigned int bytes; + + bytes = devpriv->hwdmasize; + if (cmd->stop_src == TRIG_COUNT) { + /* how many */ + bytes = s->async->cmd.chanlist_len * + s->async->cmd.chanlist_len * + sizeof(short); + + /* how many DMA pages we must fill */ + devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize; + + /* on last dma transfer must be moved */ + devpriv->last_dma_run = bytes % devpriv->hwdmasize; + devpriv->dma_runs_to_end--; + if (devpriv->dma_runs_to_end >= 0) + bytes = devpriv->hwdmasize; + } else + devpriv->dma_runs_to_end = -1; + + devpriv->next_dma_buf = 0; + set_dma_mode(devpriv->dma, DMA_MODE_READ); + dma_flags = claim_dma_lock(); + clear_dma_ff(devpriv->dma); + set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); + set_dma_count(devpriv->dma, bytes); + release_dma_lock(dma_flags); + enable_dma(devpriv->dma); +} + +static void pcl816_ai_setup_next_dma(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl816_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned long dma_flags; - unsigned short *ptr; disable_dma(devpriv->dma); - this_dma_buf = devpriv->next_dma_buf; - - /* switch dma bufs */ - if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) { - + if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) { + /* switch dma bufs */ devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; set_dma_mode(devpriv->dma, DMA_MODE_READ); dma_flags = claim_dma_lock(); -/* clear_dma_ff (devpriv->dma); */ set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]); - if (devpriv->dma_runs_to_end) { - set_dma_count(devpriv->dma, - devpriv->hwdmasize[devpriv-> - next_dma_buf]); - } else { + if (devpriv->dma_runs_to_end) + set_dma_count(devpriv->dma, devpriv->hwdmasize); + else set_dma_count(devpriv->dma, devpriv->last_dma_run); - } release_dma_lock(dma_flags); enable_dma(devpriv->dma); } devpriv->dma_runs_to_end--; - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ +} - ptr = (unsigned short *)devpriv->dmabuf[this_dma_buf]; +static void pcl816_ai_set_chan_range(struct comedi_device *dev, + unsigned int chan, + unsigned int range) +{ + outb(chan, dev->iobase + PCL816_MUX_REG); + outb(range, dev->iobase + PCL816_RANGE_REG); +} - len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr; +static void pcl816_ai_set_chan_scan(struct comedi_device *dev, + unsigned int first_chan, + unsigned int last_chan) +{ + outb(PCL816_MUX_SCAN(first_chan, last_chan), + dev->iobase + PCL816_MUX_REG); +} + +static void pcl816_ai_setup_chanlist(struct comedi_device *dev, + unsigned int *chanlist, + unsigned int seglen) +{ + unsigned int first_chan = CR_CHAN(chanlist[0]); + unsigned int last_chan; + unsigned int range; + unsigned int i; + + /* store range list to card */ + for (i = 0; i < seglen; i++) { + last_chan = CR_CHAN(chanlist[i]); + range = CR_RANGE(chanlist[i]); + + pcl816_ai_set_chan_range(dev, last_chan, range); + } + + udelay(1); + + pcl816_ai_set_chan_scan(dev, first_chan, last_chan); +} + +static void pcl816_ai_clear_eoc(struct comedi_device *dev) +{ + /* writing any value clears the interrupt request */ + outb(0, dev->iobase + PCL816_CLRINT_REG); +} + +static void pcl816_ai_soft_trig(struct comedi_device *dev) +{ + /* writing any value triggers a software conversion */ + outb(0, dev->iobase + PCL816_AI_LSB_REG); +} + +static unsigned int pcl816_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int val; + + val = inb(dev->iobase + PCL816_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL816_AI_LSB_REG); + + return val & s->maxdata; +} + +static int pcl816_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + PCL816_STATUS_REG); + if ((status & PCL816_STATUS_DRDY) == 0) + return 0; + return -EBUSY; +} + +static bool pcl816_ai_next_chan(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl816_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + + s->async->events |= COMEDI_CB_BLOCK; + + s->async->cur_chan++; + if (s->async->cur_chan >= cmd->chanlist_len) { + s->async->cur_chan = 0; + devpriv->ai_act_scan++; + s->async->events |= COMEDI_CB_EOS; + } + + if (cmd->stop_src == TRIG_COUNT && + devpriv->ai_act_scan >= cmd->stop_arg) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + return false; + } + + return true; +} + +static void transfer_from_dma_buf(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned short *ptr, + unsigned int bufptr, unsigned int len) +{ + int i; + + for (i = 0; i < len; i++) { + comedi_buf_put(s->async, ptr[bufptr++]); + + if (!pcl816_ai_next_chan(dev, s)) + return; + } +} + +static irqreturn_t pcl816_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; + struct pcl816_private *devpriv = dev->private; + unsigned short *ptr; + unsigned int bufptr; + unsigned int len; + + if (!dev->attached || !devpriv->ai_cmd_running) { + pcl816_ai_clear_eoc(dev); + return IRQ_HANDLED; + } + + if (devpriv->ai_cmd_canceled) { + devpriv->ai_cmd_canceled = 0; + pcl816_ai_clear_eoc(dev); + return IRQ_HANDLED; + } + + ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf]; + + pcl816_ai_setup_next_dma(dev, s); + + len = (devpriv->hwdmasize >> 1) - devpriv->ai_poll_ptr; bufptr = devpriv->ai_poll_ptr; devpriv->ai_poll_ptr = 0; transfer_from_dma_buf(dev, s, ptr, bufptr, len); + + pcl816_ai_clear_eoc(dev); + + cfc_handle_events(dev, s); return IRQ_HANDLED; } -/* -============================================================================== - INT procedure -*/ -static irqreturn_t interrupt_pcl816(int irq, void *d) -{ - struct comedi_device *dev = d; - struct pcl816_private *devpriv = dev->private; - - if (!dev->attached) { - comedi_error(dev, "premature interrupt"); - return IRQ_HANDLED; - } - - switch (devpriv->int816_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - return interrupt_pcl816_ai_mode13_dma(irq, d); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - return interrupt_pcl816_ai_mode13_int(irq, d); - } - - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ - if (!dev->irq || !devpriv->irq_blocked || !devpriv->int816_mode) { - if (devpriv->irq_was_now_closed) { - devpriv->irq_was_now_closed = 0; - /* comedi_error(dev,"last IRQ.."); */ - return IRQ_HANDLED; - } - comedi_error(dev, "bad IRQ!"); - return IRQ_NONE; - } - comedi_error(dev, "IRQ from unknown source!"); - return IRQ_NONE; -} - -/* -============================================================================== -*/ static int pcl816_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct pcl816_board *board = comedi_board(dev); + struct pcl816_private *devpriv = dev->private; int err = 0; - int tmp, divisor1 = 0, divisor2 = 0; + int tmp; /* Step 1 : check if triggers are trivially valid */ @@ -432,8 +400,7 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); if (cmd->convert_src == TRIG_TIMER) - err |= cfc_check_trigger_arg_min(&cmd->convert_arg, - board->ai_ns_min); + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000); else /* TRIG_EXT */ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); @@ -451,11 +418,12 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(board->i8254_osc_base, - &divisor1, &divisor2, + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->divisor1, + &devpriv->divisor2, &cmd->convert_arg, cmd->flags); - if (cmd->convert_arg < board->ai_ns_min) - cmd->convert_arg = board->ai_ns_min; + if (cmd->convert_arg < 10000) + cmd->convert_arg = 10000; if (tmp != cmd->convert_arg) err++; } @@ -477,120 +445,40 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev, static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - const struct pcl816_board *board = comedi_board(dev); struct pcl816_private *devpriv = dev->private; - unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq; struct comedi_cmd *cmd = &s->async->cmd; + unsigned int ctrl; unsigned int seglen; - if (cmd->start_src != TRIG_NOW) - return -EINVAL; - if (cmd->scan_begin_src != TRIG_FOLLOW) - return -EINVAL; - if (cmd->scan_end_src != TRIG_COUNT) - return -EINVAL; - if (cmd->scan_end_arg != cmd->chanlist_len) - return -EINVAL; -/* if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL; */ - if (devpriv->irq_blocked) + if (devpriv->ai_cmd_running) return -EBUSY; - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < board->ai_ns_min) - cmd->convert_arg = board->ai_ns_min; - - i8253_cascade_ns_to_timer(board->i8254_osc_base, - &divisor1, &divisor2, - &cmd->convert_arg, cmd->flags); - - /* PCL816 crash if any divisor is set to 1 */ - if (divisor1 == 1) { - divisor1 = 2; - divisor2 /= 2; - } - if (divisor2 == 1) { - divisor2 = 2; - divisor1 /= 2; - } - } - - start_pacer(dev, -1, 0, 0); /* stop pacer */ + pcl816_start_pacer(dev, false); seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len); if (seglen < 1) return -EINVAL; - setup_channel_list(dev, s, cmd->chanlist, seglen); + pcl816_ai_setup_chanlist(dev, cmd->chanlist, seglen); udelay(1); - devpriv->ai_n_chan = cmd->chanlist_len; devpriv->ai_act_scan = 0; s->async->cur_chan = 0; - devpriv->irq_blocked = 1; + devpriv->ai_cmd_running = 1; devpriv->ai_poll_ptr = 0; - devpriv->irq_was_now_closed = 0; + devpriv->ai_cmd_canceled = 0; - if (cmd->stop_src == TRIG_COUNT) { - devpriv->ai_scans = cmd->stop_arg; - devpriv->ai_neverending = 0; - } else { - devpriv->ai_scans = 0; - devpriv->ai_neverending = 1; - } + pcl816_ai_setup_dma(dev, s); - if (devpriv->dma) { - bytes = devpriv->hwdmasize[0]; - if (!devpriv->ai_neverending) { - /* how many */ - bytes = s->async->cmd.chanlist_len * - s->async->cmd.chanlist_len * - sizeof(short); + pcl816_start_pacer(dev, true); - /* how many DMA pages we must fill */ - devpriv->dma_runs_to_end = bytes / - devpriv->hwdmasize[0]; + ctrl = PCL816_CTRL_INTEN | PCL816_CTRL_DMAEN | PCL816_CTRL_DMASRC_SLOT0; + if (cmd->convert_src == TRIG_TIMER) + ctrl |= PCL816_CTRL_PACER_TRIG; + else /* TRIG_EXT */ + ctrl |= PCL816_CTRL_EXT_TRIG; - /* on last dma transfer must be moved */ - devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; - devpriv->dma_runs_to_end--; - if (devpriv->dma_runs_to_end >= 0) - bytes = devpriv->hwdmasize[0]; - } else - devpriv->dma_runs_to_end = -1; - - devpriv->next_dma_buf = 0; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); - set_dma_count(devpriv->dma, bytes); - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); - } - - start_pacer(dev, 1, divisor1, divisor2); - dmairq = ((devpriv->dma & 0x3) << 4) | (dev->irq & 0x7); - - switch (cmd->convert_src) { - case TRIG_TIMER: - devpriv->int816_mode = INT_TYPE_AI1_DMA; - - /* Pacer+IRQ+DMA */ - outb(0x32, dev->iobase + PCL816_CONTROL); - - /* write irq and DMA to card */ - outb(dmairq, dev->iobase + PCL816_STATUS); - break; - - default: - devpriv->int816_mode = INT_TYPE_AI3_DMA; - - /* Ext trig+IRQ+DMA */ - outb(0x34, dev->iobase + PCL816_CONTROL); - - /* write irq to card */ - outb(dmairq, dev->iobase + PCL816_STATUS); - break; - } + outb(ctrl, dev->iobase + PCL816_CTRL_REG); + outb((devpriv->dma << 4) | dev->irq, dev->iobase + PCL816_STATUS_REG); return 0; } @@ -601,9 +489,6 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) unsigned long flags; unsigned int top1, top2, i; - if (!devpriv->dma) - return 0; /* poll is valid only for DMA transfer */ - spin_lock_irqsave(&dev->spinlock, flags); for (i = 0; i < 20; i++) { @@ -618,7 +503,7 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) } /* where is now DMA in buffer */ - top1 = devpriv->hwdmasize[0] - top1; + top1 = devpriv->hwdmasize - top1; top1 >>= 1; /* sample position */ top2 = top1 - devpriv->ai_poll_ptr; if (top2 < 1) { /* no new samples */ @@ -634,134 +519,34 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_poll_ptr = top1; /* new buffer position */ spin_unlock_irqrestore(&dev->spinlock, flags); + cfc_handle_events(dev, s); + return s->async->buf_write_count - s->async->buf_read_count; } -/* -============================================================================== - cancel any mode 1-4 AI -*/ static int pcl816_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl816_private *devpriv = dev->private; - if (devpriv->irq_blocked > 0) { - switch (devpriv->int816_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - disable_dma(devpriv->dma); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - outb(inb(dev->iobase + PCL816_CONTROL) & 0x73, - dev->iobase + PCL816_CONTROL); /* Stop A/D */ - udelay(1); - outb(0, dev->iobase + PCL816_CONTROL); /* Stop A/D */ + if (!devpriv->ai_cmd_running) + return 0; - /* Stop pacer */ - outb(0xb0, dev->iobase + PCL816_CTRCTL); - outb(0x70, dev->iobase + PCL816_CTRCTL); - outb(0, dev->iobase + PCL816_AD_LO); - inb(dev->iobase + PCL816_AD_LO); - inb(dev->iobase + PCL816_AD_HI); + outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + pcl816_ai_clear_eoc(dev); - /* clear INT request */ - outb(0, dev->iobase + PCL816_CLRINT); + /* Stop pacer */ + i8254_set_mode(dev->iobase + PCL816_TIMER_BASE, 0, + 2, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(dev->iobase + PCL816_TIMER_BASE, 0, + 1, I8254_MODE0 | I8254_BINARY); + + devpriv->ai_cmd_running = 0; + devpriv->ai_cmd_canceled = 1; - /* Stop A/D */ - outb(0, dev->iobase + PCL816_CONTROL); - devpriv->irq_blocked = 0; - devpriv->irq_was_now_closed = devpriv->int816_mode; - devpriv->int816_mode = 0; - devpriv->last_int_sub = s; -/* s->busy = 0; */ - break; - } - } return 0; } -/* -============================================================================== - chech for PCL816 -*/ -static int pcl816_check(unsigned long iobase) -{ - outb(0x00, iobase + PCL816_MUX); - udelay(1); - if (inb(iobase + PCL816_MUX) != 0x00) - return 1; /* there isn't card */ - outb(0x55, iobase + PCL816_MUX); - udelay(1); - if (inb(iobase + PCL816_MUX) != 0x55) - return 1; /* there isn't card */ - outb(0x00, iobase + PCL816_MUX); - udelay(1); - outb(0x18, iobase + PCL816_CONTROL); - udelay(1); - if (inb(iobase + PCL816_CONTROL) != 0x18) - return 1; /* there isn't card */ - return 0; /* ok, card exist */ -} - -/* -============================================================================== - reset whole PCL-816 cards -*/ -static void pcl816_reset(struct comedi_device *dev) -{ -/* outb (0, dev->iobase + PCL818_DA_LO); DAC=0V */ -/* outb (0, dev->iobase + PCL818_DA_HI); */ -/* udelay (1); */ -/* outb (0, dev->iobase + PCL818_DO_HI); DO=$0000 */ -/* outb (0, dev->iobase + PCL818_DO_LO); */ -/* udelay (1); */ - outb(0, dev->iobase + PCL816_CONTROL); - outb(0, dev->iobase + PCL816_MUX); - outb(0, dev->iobase + PCL816_CLRINT); - outb(0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */ - outb(0x70, dev->iobase + PCL816_CTRCTL); - outb(0x30, dev->iobase + PCL816_CTRCTL); - outb(0, dev->iobase + PCL816_RANGE); -} - -/* -============================================================================== - Start/stop pacer onboard pacer -*/ -static void -start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, - unsigned int divisor2) -{ - outb(0x32, dev->iobase + PCL816_CTRCTL); - outb(0xff, dev->iobase + PCL816_CTR0); - outb(0x00, dev->iobase + PCL816_CTR0); - udelay(1); - - /* set counter 2 as mode 3 */ - outb(0xb4, dev->iobase + PCL816_CTRCTL); - /* set counter 1 as mode 3 */ - outb(0x74, dev->iobase + PCL816_CTRCTL); - udelay(1); - - if (mode == 1) { - dev_dbg(dev->class_dev, "mode %d, divisor1 %d, divisor2 %d\n", - mode, divisor1, divisor2); - outb(divisor2 & 0xff, dev->iobase + PCL816_CTR2); - outb((divisor2 >> 8) & 0xff, dev->iobase + PCL816_CTR2); - outb(divisor1 & 0xff, dev->iobase + PCL816_CTR1); - outb((divisor1 >> 8) & 0xff, dev->iobase + PCL816_CTR1); - } - - /* clear pending interrupts (just in case) */ -/* outb(0, dev->iobase + PCL816_CLRINT); */ -} - -/* -============================================================================== - Check if channel list from user is built correctly - If it's ok, then return non-zero length of repeated segment of channel list -*/ static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, @@ -818,180 +603,181 @@ check_channel_list(struct comedi_device *dev, return seglen; /* we can serve this with MUX logic */ } -/* -============================================================================== - Program scan/gain logic with channel list. -*/ -static void -setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int *chanlist, - unsigned int seglen) +static int pcl816_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct pcl816_private *devpriv = dev->private; - unsigned int i; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + int ret = 0; + int i; - devpriv->ai_act_chanlist_len = seglen; - devpriv->ai_act_chanlist_pos = 0; + outb(PCL816_CTRL_SOFT_TRIG, dev->iobase + PCL816_CTRL_REG); - for (i = 0; i < seglen; i++) { /* store range list to card */ - devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]); - outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX); - /* select gain */ - outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE); + pcl816_ai_set_chan_range(dev, chan, range); + pcl816_ai_set_chan_scan(dev, chan, chan); + + for (i = 0; i < insn->n; i++) { + pcl816_ai_clear_eoc(dev); + pcl816_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, pcl816_ai_eoc, 0); + if (ret) + break; + + data[i] = pcl816_ai_get_sample(dev, s); + } + outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + pcl816_ai_clear_eoc(dev); + + return ret ? ret : insn->n; +} + +static int pcl816_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + PCL816_DO_DI_LSB_REG) | + (inb(dev->iobase + PCL816_DO_DI_MSB_REG) << 8); + + return insn->n; +} + +static int pcl816_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase + PCL816_DO_DI_LSB_REG); + outb((s->state >> 8), dev->iobase + PCL816_DO_DI_MSB_REG); } - udelay(1); - /* select channel interval to scan */ - outb(devpriv->ai_act_chanlist[0] | - (devpriv->ai_act_chanlist[seglen - 1] << 4), - dev->iobase + PCL816_MUX); + data[1] = s->state; + + return insn->n; +} + +static void pcl816_reset(struct comedi_device *dev) +{ + unsigned long timer_base = dev->iobase + PCL816_TIMER_BASE; + + outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + pcl816_ai_set_chan_range(dev, 0, 0); + pcl816_ai_clear_eoc(dev); + + /* Stop pacer */ + i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY); + + /* set all digital outputs low */ + outb(0, dev->iobase + PCL816_DO_DI_LSB_REG); + outb(0, dev->iobase + PCL816_DO_DI_MSB_REG); } static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl816_board *board = comedi_board(dev); struct pcl816_private *devpriv; - int ret; - unsigned int dma; - unsigned long pages; - /* int i; */ struct comedi_subdevice *s; - - ret = comedi_request_region(dev, it->options[0], board->io_range); - if (ret) - return ret; - - if (pcl816_check(dev->iobase)) { - dev_err(dev->class_dev, "I can't detect board. FAIL!\n"); - return -EIO; - } + int ret; + int i; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - if ((1 << it->options[1]) & board->IRQbits) { - ret = request_irq(it->options[1], interrupt_pcl816, 0, + ret = comedi_request_region(dev, it->options[0], 0x10); + if (ret) + return ret; + + /* we can use IRQ 2-7 for async command support */ + if (it->options[1] >= 2 && it->options[1] <= 7) { + ret = request_irq(it->options[1], pcl816_interrupt, 0, dev->board_name, dev); if (ret == 0) dev->irq = it->options[1]; } - devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */ - devpriv->int816_mode = 0; /* mode of irq */ - - /* grab our DMA */ - dma = 0; - devpriv->dma = dma; - if (!dev->irq) - goto no_dma; /* if we haven't IRQ, we can't use DMA */ - - if (board->DMAbits != 0) { /* board support DMA */ - dma = it->options[2]; - if (dma < 1) - goto no_dma; /* DMA disabled */ - - if (((1 << dma) & board->DMAbits) == 0) { - dev_err(dev->class_dev, - "DMA is out of allowed range, FAIL!\n"); - return -EINVAL; /* Bad DMA */ - } - ret = request_dma(dma, dev->board_name); + /* we need an IRQ to do DMA on channel 3 or 1 */ + if (dev->irq && (it->options[2] == 3 || it->options[2] == 1)) { + ret = request_dma(it->options[2], dev->board_name); if (ret) { dev_err(dev->class_dev, - "unable to allocate DMA %u, FAIL!\n", dma); - return -EBUSY; /* DMA isn't free */ - } - - devpriv->dma = dma; - pages = 2; /* we need 16KB */ - devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); - - if (!devpriv->dmabuf[0]) { - dev_err(dev->class_dev, - "unable to allocate DMA buffer, FAIL!\n"); - /* - * maybe experiment with try_to_free_pages() - * will help .... - */ - return -EBUSY; /* no buffer :-( */ - } - devpriv->dmapages[0] = pages; - devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); - devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE; - - devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[1]) { - dev_err(dev->class_dev, - "unable to allocate DMA buffer, FAIL!\n"); + "unable to request DMA channel %d\n", + it->options[2]); return -EBUSY; } - devpriv->dmapages[1] = pages; - devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]); - devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE; + devpriv->dma = it->options[2]; + + devpriv->dmapages = 2; /* we need 16KB */ + devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; + + for (i = 0; i < 2; i++) { + unsigned long dmabuf; + + dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); + if (!dmabuf) + return -ENOMEM; + + devpriv->dmabuf[i] = dmabuf; + devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); + } } -no_dma: - -/* if (board->n_aochan > 0) - subdevs[1] = COMEDI_SUBD_AO; - if (board->n_dichan > 0) - subdevs[2] = COMEDI_SUBD_DI; - if (board->n_dochan > 0) - subdevs[3] = COMEDI_SUBD_DO; -*/ - - ret = comedi_alloc_subdevices(dev, 1); + ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; s = &dev->subdevices[0]; - if (board->n_aichan > 0) { - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_CMD_READ | SDF_DIFF; - s->n_chan = board->n_aichan; - s->maxdata = board->ai_maxdata; - s->range_table = board->ai_range_type; - s->insn_read = pcl816_ai_insn_read; - if (dev->irq) { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->len_chanlist = board->ai_chanlist; - s->do_cmdtest = pcl816_ai_cmdtest; - s->do_cmd = pcl816_ai_cmd; - s->poll = pcl816_ai_poll; - s->cancel = pcl816_ai_cancel; - } - } else { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_CMD_READ | SDF_DIFF; + s->n_chan = 16; + s->maxdata = board->ai_maxdata; + s->range_table = &range_pcl816; + s->insn_read = pcl816_ai_insn_read; + if (devpriv->dma) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = board->ai_chanlist; + s->do_cmdtest = pcl816_ai_cmdtest; + s->do_cmd = pcl816_ai_cmd; + s->poll = pcl816_ai_poll; + s->cancel = pcl816_ai_cancel; } + /* Analog OUtput subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_UNUSED; #if 0 -case COMEDI_SUBD_AO: + subdevs[1] = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = board->n_aochan; + s->n_chan = 1; s->maxdata = board->ao_maxdata; - s->len_chanlist = board->ao_chanlist; - s->range_table = board->ao_range_type; - break; - -case COMEDI_SUBD_DI: - s->subdev_flags = SDF_READABLE; - s->n_chan = board->n_dichan; - s->maxdata = 1; - s->len_chanlist = board->n_dichan; - s->range_table = &range_digital; - break; - -case COMEDI_SUBD_DO: - s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_dochan; - s->maxdata = 1; - s->len_chanlist = board->n_dochan; - s->range_table = &range_digital; - break; + s->range_table = &range_pcl816; #endif + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl816_di_insn_bits; + + /* Digital Output subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl816_do_insn_bits; + pcl816_reset(dev); return 0; @@ -1007,34 +793,13 @@ static void pcl816_detach(struct comedi_device *dev) if (devpriv->dma) free_dma(devpriv->dma); if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); + free_pages(devpriv->dmabuf[0], devpriv->dmapages); if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); + free_pages(devpriv->dmabuf[1], devpriv->dmapages); } comedi_legacy_detach(dev); } -static const struct pcl816_board boardtypes[] = { - {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816, - &range_pcl816, PCLx1x_RANGE, - 0x00fc, /* IRQ mask */ - 0x0a, /* DMA mask */ - 0xffff, /* 16-bit card */ - 0xffff, /* D/A maxdata */ - 1024, - 1, /* ao chan list */ - I8254_OSC_BASE_10MHZ}, - {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816, - &range_pcl816, PCLx1x_RANGE, - 0x00fc, - 0x0a, - 0x3fff, /* 14 bit card */ - 0x3fff, - 1024, - 1, - I8254_OSC_BASE_10MHZ}, -}; - static struct comedi_driver pcl816_driver = { .driver_name = "pcl816", .module = THIS_MODULE, diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c index fa1758ad49d5..6463476ce45a 100644 --- a/drivers/staging/comedi/drivers/pcl818.c +++ b/drivers/staging/comedi/drivers/pcl818.c @@ -110,8 +110,6 @@ A word or two about DMA. Driver support DMA operations at two ways: #include "comedi_fc.h" #include "8253.h" -/* #define PCL818_MODE13_AO 1 */ - /* boards constants */ #define boardPCL818L 0 @@ -121,46 +119,38 @@ A word or two about DMA. Driver support DMA operations at two ways: #define boardPCL818 4 #define boardPCL718 5 -/* IO space len */ -#define PCLx1x_RANGE 16 -/* IO space len if we use FIFO */ -#define PCLx1xFIFO_RANGE 32 - -/* W: clear INT request */ -#define PCL818_CLRINT 8 -/* R: return status byte */ -#define PCL818_STATUS 8 -/* R: A/D high byte W: A/D range control */ -#define PCL818_RANGE 1 -/* R: next mux scan channel W: mux scan channel & range control pointer */ -#define PCL818_MUX 2 -/* R/W: operation control register */ -#define PCL818_CONTROL 9 -/* W: counter enable */ -#define PCL818_CNTENABLE 10 - -/* R: low byte of A/D W: soft A/D trigger */ -#define PCL818_AD_LO 0 -/* R: high byte of A/D W: A/D range control */ -#define PCL818_AD_HI 1 -/* W: D/A low&high byte */ -#define PCL818_DA_LO 4 -#define PCL818_DA_HI 5 -/* R: low&high byte of DI */ -#define PCL818_DI_LO 3 -#define PCL818_DI_HI 11 -/* W: low&high byte of DO */ -#define PCL818_DO_LO 3 -#define PCL818_DO_HI 11 -/* W: PCL718 second D/A */ -#define PCL718_DA2_LO 6 -#define PCL718_DA2_HI 7 -/* counters */ -#define PCL818_CTR0 12 -#define PCL818_CTR1 13 -#define PCL818_CTR2 14 -/* W: counter control */ -#define PCL818_CTRCTL 15 +/* + * Register I/O map + */ +#define PCL818_AI_LSB_REG 0x00 +#define PCL818_AI_MSB_REG 0x01 +#define PCL818_RANGE_REG 0x01 +#define PCL818_MUX_REG 0x02 +#define PCL818_MUX_SCAN(_first, _last) (((_last) << 4) | (_first)) +#define PCL818_DO_DI_LSB_REG 0x03 +#define PCL818_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define PCL818_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define PCL818_STATUS_REG 0x08 +#define PCL818_STATUS_NEXT_CHAN_MASK (0xf << 0) +#define PCL818_STATUS_INT (1 << 4) +#define PCL818_STATUS_MUX (1 << 5) +#define PCL818_STATUS_UNI (1 << 6) +#define PCL818_STATUS_EOC (1 << 7) +#define PCL818_CTRL_REG 0x09 +#define PCL818_CTRL_DISABLE_TRIG (0 << 0) +#define PCL818_CTRL_SOFT_TRIG (1 << 0) +#define PCL818_CTRL_EXT_TRIG (2 << 0) +#define PCL818_CTRL_PACER_TRIG (3 << 0) +#define PCL818_CTRL_DMAE (1 << 2) +#define PCL818_CTRL_IRQ(x) ((x) << 4) +#define PCL818_CTRL_INTE (1 << 7) +#define PCL818_CNTENABLE_REG 0x0a +#define PCL818_CNTENABLE_PACER_ENA (0 << 0) +#define PCL818_CNTENABLE_PACER_TRIG0 (1 << 0) +#define PCL818_CNTENABLE_CNT0_EXT_CLK (0 << 1) +#define PCL818_CNTENABLE_CNT0_INT_CLK (1 << 1) +#define PCL818_DO_DI_MSB_REG 0x0b +#define PCL818_TIMER_BASE 0x0c /* W: fifo enable/disable */ #define PCL818_FI_ENABLE 6 @@ -172,19 +162,7 @@ A word or two about DMA. Driver support DMA operations at two ways: #define PCL818_FI_STATUS 25 /* R: one record from FIFO */ #define PCL818_FI_DATALO 23 -#define PCL818_FI_DATAHI 23 - -/* type of interrupt handler */ -#define INT_TYPE_AI1_INT 1 -#define INT_TYPE_AI1_DMA 2 -#define INT_TYPE_AI1_FIFO 3 -#define INT_TYPE_AI3_INT 4 -#define INT_TYPE_AI3_DMA 5 -#define INT_TYPE_AI3_FIFO 6 -#ifdef PCL818_MODE13_AO -#define INT_TYPE_AO1_INT 7 -#define INT_TYPE_AO3_INT 8 -#endif +#define PCL818_FI_DATAHI 24 #define MAGIC_DMA_WORD 0x5a5a @@ -262,493 +240,125 @@ static const struct comedi_lrange range718_unipolar1 = { }; struct pcl818_board { + const char *name; + unsigned int ns_min; + int n_aochan; + const struct comedi_lrange *ai_range_type; + unsigned int has_dma:1; + unsigned int has_fifo:1; + unsigned int is_818:1; +}; - const char *name; /* driver name */ - int n_ranges; /* len of range list */ - int n_aichan_se; /* num of A/D chans in single ended mode */ - int n_aichan_diff; /* num of A/D chans in diferencial mode */ - unsigned int ns_min; /* minimal allowed delay between samples (in ns) */ - int n_aochan; /* num of D/A chans */ - int n_dichan; /* num of DI chans */ - int n_dochan; /* num of DO chans */ - const struct comedi_lrange *ai_range_type; /* default A/D rangelist */ - const struct comedi_lrange *ao_range_type; /* default D/A rangelist */ - unsigned int io_range; /* len of IO space */ - unsigned int IRQbits; /* allowed interrupts */ - unsigned int DMAbits; /* allowed DMA chans */ - int ai_maxdata; /* maxdata for A/D */ - int ao_maxdata; /* maxdata for D/A */ - unsigned char fifo; /* 1=board has FIFO */ - int is_818; +static const struct pcl818_board boardtypes[] = { + { + .name = "pcl818l", + .ns_min = 25000, + .n_aochan = 1, + .ai_range_type = &range_pcl818l_l_ai, + .has_dma = 1, + .is_818 = 1, + }, { + .name = "pcl818h", + .ns_min = 10000, + .n_aochan = 1, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .is_818 = 1, + }, { + .name = "pcl818hd", + .ns_min = 10000, + .n_aochan = 1, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .has_fifo = 1, + .is_818 = 1, + }, { + .name = "pcl818hg", + .ns_min = 10000, + .n_aochan = 1, + .ai_range_type = &range_pcl818hg_ai, + .has_dma = 1, + .has_fifo = 1, + .is_818 = 1, + }, { + .name = "pcl818", + .ns_min = 10000, + .n_aochan = 2, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .is_818 = 1, + }, { + .name = "pcl718", + .ns_min = 16000, + .n_aochan = 2, + .ai_range_type = &range_unipolar5, + .has_dma = 1, + }, { + .name = "pcm3718", + .ns_min = 10000, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .is_818 = 1, + }, }; struct pcl818_private { - unsigned int dma; /* used DMA, 0=don't use DMA */ - unsigned int io_range; + unsigned int dmapages; + unsigned int hwdmasize; unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */ - unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */ unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */ - unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */ int next_dma_buf; /* which DMA buffer will be used next round */ long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */ unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */ - unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */ unsigned int ns_min; /* manimal allowed delay between samples (in us) for actual card */ int i8253_osc_base; /* 1/frequency of on board oscilator in ns */ - int irq_blocked; /* 1=IRQ now uses any subdev */ - int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */ - int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */ - struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */ int ai_act_scan; /* how many scans we finished */ int ai_act_chan; /* actual position in actual scan */ unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */ unsigned int act_chanlist_len; /* how long is actual MUX list */ unsigned int act_chanlist_pos; /* actual position in MUX list */ - unsigned int ai_scans; /* len of scanlist */ - unsigned int ai_n_chan; /* how many channels is measured */ - unsigned int *ai_chanlist; /* actaul chanlist */ - unsigned int ai_flags; /* flaglist */ unsigned int ai_data_len; /* len of data buffer */ - unsigned int ai_timer1; /* timers */ - unsigned int ai_timer2; - unsigned char usefifo; /* 1=use fifo */ unsigned int ao_readback[2]; + unsigned int divisor1; + unsigned int divisor2; + unsigned int usefifo:1; + unsigned int ai_cmd_running:1; + unsigned int ai_cmd_canceled:1; }; -static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */ - 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff -}; - -/* -============================================================================== -*/ -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan, - unsigned int seglen); -static int check_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan); - -static int pcl818_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); - -/* -============================================================================== - ANALOG INPUT MODE0, 818 cards, slow version -*/ -static int pcl818_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int n; - int timeout; - - /* software trigger, DMA and INT off */ - outb(0, dev->iobase + PCL818_CONTROL); - - /* select channel */ - outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX); - - /* select gain */ - outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE); - - for (n = 0; n < insn->n; n++) { - - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL818_CLRINT); - - /* start conversion */ - outb(0, dev->iobase + PCL818_AD_LO); - - timeout = 100; - while (timeout--) { - if (inb(dev->iobase + PCL818_STATUS) & 0x10) - goto conv_finish; - udelay(1); - } - comedi_error(dev, "A/D insn timeout"); - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL818_CLRINT); - return -EIO; - -conv_finish: - data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) | - (inb(dev->iobase + PCL818_AD_LO) >> 4)); - } - - return n; -} - -/* -============================================================================== - ANALOG OUTPUT MODE0, 818 cards - only one sample per call is supported -*/ -static int pcl818_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl818_start_pacer(struct comedi_device *dev, bool load_counters) { struct pcl818_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); + unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE; - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_readback[chan]; + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + udelay(1); - return n; + if (load_counters) { + i8254_write(timer_base, 0, 2, devpriv->divisor2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); + } } -static int pcl818_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct pcl818_private *devpriv = dev->private; - int n; - int chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) { - devpriv->ao_readback[chan] = data[n]; - outb((data[n] & 0x000f) << 4, dev->iobase + - (chan ? PCL718_DA2_LO : PCL818_DA_LO)); - outb((data[n] & 0x0ff0) >> 4, dev->iobase + - (chan ? PCL718_DA2_HI : PCL818_DA_HI)); - } - - return n; -} - -/* -============================================================================== - DIGITAL INPUT MODE0, 818 cards - - only one sample per call is supported -*/ -static int pcl818_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - data[1] = inb(dev->iobase + PCL818_DI_LO) | - (inb(dev->iobase + PCL818_DI_HI) << 8); - - return insn->n; -} - -static int pcl818_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - if (comedi_dio_update_state(s, data)) { - outb(s->state & 0xff, dev->iobase + PCL818_DO_LO); - outb((s->state >> 8), dev->iobase + PCL818_DO_HI); - } - - data[1] = s->state; - - return insn->n; -} - -/* -============================================================================== - analog input interrupt mode 1 & 3, 818 cards - one sample per interrupt version -*/ -static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d) -{ - struct comedi_device *dev = d; - struct pcl818_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - unsigned char low; - int timeout = 50; /* wait max 50us */ - - while (timeout--) { - if (inb(dev->iobase + PCL818_STATUS) & 0x10) - goto conv_finish; - udelay(1); - } - outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */ - comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - -conv_finish: - low = inb(dev->iobase + PCL818_AD_LO); - comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */ - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - - if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ - dev_dbg(dev->class_dev, - "A/D mode1/3 IRQ - channel dropout %x!=%x !\n", - (low & 0xf), - devpriv->act_chanlist[devpriv->act_chanlist_pos]); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } - devpriv->act_chanlist_pos++; - if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) - devpriv->act_chanlist_pos = 0; - - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan--; - } - - if (!devpriv->neverending_ai) { - if (devpriv->ai_act_scan == 0) { /* all data sampled */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - } - } - comedi_event(dev, s); - return IRQ_HANDLED; -} - -/* -============================================================================== - analog input dma mode 1 & 3, 818 cards -*/ -static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d) -{ - struct comedi_device *dev = d; - struct pcl818_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - int i, len, bufptr; - unsigned long flags; - unsigned short *ptr; - - disable_dma(devpriv->dma); - devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; - if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */ - set_dma_mode(devpriv->dma, DMA_MODE_READ); - flags = claim_dma_lock(); - set_dma_addr(devpriv->dma, - devpriv->hwdmaptr[devpriv->next_dma_buf]); - if (devpriv->dma_runs_to_end || devpriv->neverending_ai) { - set_dma_count(devpriv->dma, - devpriv->hwdmasize[devpriv-> - next_dma_buf]); - } else { - set_dma_count(devpriv->dma, devpriv->last_dma_run); - } - release_dma_lock(flags); - enable_dma(devpriv->dma); - } - - devpriv->dma_runs_to_end--; - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf]; - - len = devpriv->hwdmasize[0] >> 1; - bufptr = 0; - - for (i = 0; i < len; i++) { - if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ - dev_dbg(dev->class_dev, - "A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n", - (ptr[bufptr] & 0xf), - devpriv->act_chanlist[devpriv->act_chanlist_pos], - devpriv->act_chanlist_pos); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } - - comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */ - - devpriv->act_chanlist_pos++; - if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) - devpriv->act_chanlist_pos = 0; - - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan--; - } - - if (!devpriv->neverending_ai) - if (devpriv->ai_act_scan == 0) { /* all data sampled */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return IRQ_HANDLED; - } - } - - if (len > 0) - comedi_event(dev, s); - return IRQ_HANDLED; -} - -/* -============================================================================== - analog input interrupt mode 1 & 3, 818HD/HG cards -*/ -static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d) -{ - struct comedi_device *dev = d; - struct pcl818_private *devpriv = dev->private; - struct comedi_subdevice *s = dev->read_subdev; - int i, len; - unsigned char lo; - - outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */ - - lo = inb(dev->iobase + PCL818_FI_STATUS); - - if (lo & 4) { - comedi_error(dev, "A/D mode1/3 FIFO overflow!"); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } - - if (lo & 1) { - comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!"); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } - - if (lo & 2) - len = 512; - else - len = 0; - - for (i = 0; i < len; i++) { - lo = inb(dev->iobase + PCL818_FI_DATALO); - if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ - dev_dbg(dev->class_dev, - "A/D mode1/3 FIFO - channel dropout %d!=%d !\n", - (lo & 0xf), - devpriv->act_chanlist[devpriv->act_chanlist_pos]); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } - - comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */ - - devpriv->act_chanlist_pos++; - if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) - devpriv->act_chanlist_pos = 0; - - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan--; - } - - if (!devpriv->neverending_ai) - if (devpriv->ai_act_scan == 0) { /* all data sampled */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return IRQ_HANDLED; - } - } - - if (len > 0) - comedi_event(dev, s); - return IRQ_HANDLED; -} - -/* -============================================================================== - INT procedure -*/ -static irqreturn_t interrupt_pcl818(int irq, void *d) -{ - struct comedi_device *dev = d; - struct pcl818_private *devpriv = dev->private; - - if (!dev->attached) { - comedi_error(dev, "premature interrupt"); - return IRQ_HANDLED; - } - - if (devpriv->irq_blocked && devpriv->irq_was_now_closed) { - if ((devpriv->neverending_ai || (!devpriv->neverending_ai && - devpriv->ai_act_scan > 0)) && - (devpriv->ai_mode == INT_TYPE_AI1_DMA || - devpriv->ai_mode == INT_TYPE_AI3_DMA)) { - /* The cleanup from ai_cancel() has been delayed - until now because the card doesn't seem to like - being reprogrammed while a DMA transfer is in - progress. - */ - devpriv->ai_act_scan = 0; - devpriv->neverending_ai = 0; - pcl818_ai_cancel(dev, dev->read_subdev); - } - - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - - return IRQ_HANDLED; - } - - switch (devpriv->ai_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - return interrupt_pcl818_ai_mode13_dma(irq, d); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - return interrupt_pcl818_ai_mode13_int(irq, d); - case INT_TYPE_AI1_FIFO: - case INT_TYPE_AI3_FIFO: - return interrupt_pcl818_ai_mode13_fifo(irq, d); -#ifdef PCL818_MODE13_AO - case INT_TYPE_AO1_INT: - case INT_TYPE_AO3_INT: - return interrupt_pcl818_ao_mode13_int(irq, d); -#endif - default: - break; - } - - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - - if (!devpriv->irq_blocked || !devpriv->ai_mode) { - comedi_error(dev, "bad IRQ!"); - return IRQ_NONE; - } - - comedi_error(dev, "IRQ from unknown source!"); - return IRQ_NONE; -} - -/* -============================================================================== - ANALOG INPUT MODE 1 or 3 DMA , 818 cards -*/ -static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev, - struct comedi_subdevice *s) +static void pcl818_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int flags; unsigned int bytes; disable_dma(devpriv->dma); /* disable dma */ - bytes = devpriv->hwdmasize[0]; - if (!devpriv->neverending_ai) { - bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */ - devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */ - devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */ + bytes = devpriv->hwdmasize; + if (cmd->stop_src == TRIG_COUNT) { + bytes = cmd->chanlist_len * cmd->stop_arg * sizeof(short); + devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize; + devpriv->last_dma_run = bytes % devpriv->hwdmasize; devpriv->dma_runs_to_end--; if (devpriv->dma_runs_to_end >= 0) - bytes = devpriv->hwdmasize[0]; + bytes = devpriv->hwdmasize; } devpriv->next_dma_buf = 0; @@ -759,133 +369,310 @@ static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev, set_dma_count(devpriv->dma, bytes); release_dma_lock(flags); enable_dma(devpriv->dma); - - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_DMA; - outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */ - } else { - devpriv->ai_mode = INT_TYPE_AI3_DMA; - outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */ - } } -/* -============================================================================== - ANALOG INPUT MODE 1 or 3, 818 cards -*/ -static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev, - struct comedi_subdevice *s) +static void pcl818_ai_setup_next_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pcl818_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - int divisor1 = 0, divisor2 = 0; - unsigned int seglen; + unsigned long flags; - if (devpriv->irq_blocked) - return -EBUSY; - - start_pacer(dev, -1, 0, 0); /* stop pacer */ - - seglen = check_channel_list(dev, s, devpriv->ai_chanlist, - devpriv->ai_n_chan); - if (seglen < 1) - return -EINVAL; - setup_channel_list(dev, s, devpriv->ai_chanlist, - devpriv->ai_n_chan, seglen); - - udelay(1); - - devpriv->ai_act_scan = devpriv->ai_scans; - devpriv->ai_act_chan = 0; - devpriv->irq_blocked = 1; - devpriv->irq_was_now_closed = 0; - devpriv->neverending_ai = 0; - devpriv->act_chanlist_pos = 0; - devpriv->dma_runs_to_end = 0; - - if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1)) - devpriv->neverending_ai = 1; /* well, user want neverending */ - - if (mode == 1) { - i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, - &divisor1, &divisor2, - &cmd->convert_arg, - TRIG_ROUND_NEAREST); - if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */ - divisor1 = 2; - divisor2 /= 2; - } - if (divisor2 == 1) { - divisor2 = 2; - divisor1 /= 2; - } + disable_dma(devpriv->dma); + devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; + if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) { + /* switch dma bufs */ + set_dma_mode(devpriv->dma, DMA_MODE_READ); + flags = claim_dma_lock(); + set_dma_addr(devpriv->dma, + devpriv->hwdmaptr[devpriv->next_dma_buf]); + if (devpriv->dma_runs_to_end || cmd->stop_src == TRIG_NONE) + set_dma_count(devpriv->dma, devpriv->hwdmasize); + else + set_dma_count(devpriv->dma, devpriv->last_dma_run); + release_dma_lock(flags); + enable_dma(devpriv->dma); } - outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */ - - switch (devpriv->dma) { - case 1: /* DMA */ - case 3: - pcl818_ai_mode13dma_int(mode, dev, s); - break; - case 0: - if (!devpriv->usefifo) { - /* IRQ */ - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_INT; - /* Pacer+IRQ */ - outb(0x83 | (dev->irq << 4), - dev->iobase + PCL818_CONTROL); - } else { - devpriv->ai_mode = INT_TYPE_AI3_INT; - /* Ext trig+IRQ */ - outb(0x82 | (dev->irq << 4), - dev->iobase + PCL818_CONTROL); - } - } else { - /* FIFO */ - /* enable FIFO */ - outb(1, dev->iobase + PCL818_FI_ENABLE); - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_FIFO; - /* Pacer */ - outb(0x03, dev->iobase + PCL818_CONTROL); - } else { - devpriv->ai_mode = INT_TYPE_AI3_FIFO; - outb(0x02, dev->iobase + PCL818_CONTROL); - } - } - } - - start_pacer(dev, mode, divisor1, divisor2); - - return 0; + devpriv->dma_runs_to_end--; } -/* -============================================================================== - Start/stop pacer onboard pacer -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2) +static void pcl818_ai_set_chan_range(struct comedi_device *dev, + unsigned int chan, + unsigned int range) { - outb(0xb4, dev->iobase + PCL818_CTRCTL); - outb(0x74, dev->iobase + PCL818_CTRCTL); + outb(chan, dev->iobase + PCL818_MUX_REG); + outb(range, dev->iobase + PCL818_RANGE_REG); +} + +static void pcl818_ai_set_chan_scan(struct comedi_device *dev, + unsigned int first_chan, + unsigned int last_chan) +{ + outb(PCL818_MUX_SCAN(first_chan, last_chan), + dev->iobase + PCL818_MUX_REG); +} + +static void pcl818_ai_setup_chanlist(struct comedi_device *dev, + unsigned int *chanlist, + unsigned int seglen) +{ + struct pcl818_private *devpriv = dev->private; + unsigned int first_chan = CR_CHAN(chanlist[0]); + unsigned int last_chan; + unsigned int range; + int i; + + devpriv->act_chanlist_len = seglen; + devpriv->act_chanlist_pos = 0; + + /* store range list to card */ + for (i = 0; i < seglen; i++) { + last_chan = CR_CHAN(chanlist[i]); + range = CR_RANGE(chanlist[i]); + + devpriv->act_chanlist[i] = last_chan; + + pcl818_ai_set_chan_range(dev, last_chan, range); + } + udelay(1); - if (mode == 1) { - outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2); - outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2); - outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1); - outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1); + pcl818_ai_set_chan_scan(dev, first_chan, last_chan); +} + +static void pcl818_ai_clear_eoc(struct comedi_device *dev) +{ + /* writing any value clears the interrupt request */ + outb(0, dev->iobase + PCL818_STATUS_REG); +} + +static void pcl818_ai_soft_trig(struct comedi_device *dev) +{ + /* writing any value triggers a software conversion */ + outb(0, dev->iobase + PCL818_AI_LSB_REG); +} + +static unsigned int pcl818_ai_get_fifo_sample(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int *chan) +{ + unsigned int val; + + val = inb(dev->iobase + PCL818_FI_DATALO); + val |= (inb(dev->iobase + PCL818_FI_DATAHI) << 8); + + if (chan) + *chan = val & 0xf; + + return (val >> 4) & s->maxdata; +} + +static unsigned int pcl818_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int *chan) +{ + unsigned int val; + + val = inb(dev->iobase + PCL818_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL818_AI_LSB_REG); + + if (chan) + *chan = val & 0xf; + + return (val >> 4) & s->maxdata; +} + +static int pcl818_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + PCL818_STATUS_REG); + if (status & PCL818_STATUS_INT) + return 0; + return -EBUSY; +} + +static bool pcl818_ai_dropout(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan) +{ + struct pcl818_private *devpriv = dev->private; + unsigned int expected_chan; + + expected_chan = devpriv->act_chanlist[devpriv->act_chanlist_pos]; + if (chan != expected_chan) { + dev_dbg(dev->class_dev, + "A/D mode1/3 %s - channel dropout %d!=%d !\n", + (devpriv->dma) ? "DMA" : + (devpriv->usefifo) ? "FIFO" : "IRQ", + chan, expected_chan); + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + return true; + } + return false; +} + +static bool pcl818_ai_next_chan(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + + s->async->events |= COMEDI_CB_BLOCK; + + devpriv->act_chanlist_pos++; + if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) + devpriv->act_chanlist_pos = 0; + + s->async->cur_chan++; + if (s->async->cur_chan >= cmd->chanlist_len) { + s->async->cur_chan = 0; + devpriv->ai_act_scan--; + s->async->events |= COMEDI_CB_EOS; + } + + if (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan == 0) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + return false; + } + + return true; +} + +static void pcl818_handle_eoc(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int chan; + unsigned int val; + + if (pcl818_ai_eoc(dev, s, NULL, 0)) { + comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + return; + } + + val = pcl818_ai_get_sample(dev, s, &chan); + + if (pcl818_ai_dropout(dev, s, chan)) + return; + + comedi_buf_put(s->async, val); + + pcl818_ai_next_chan(dev, s); +} + +static void pcl818_handle_dma(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl818_private *devpriv = dev->private; + unsigned short *ptr; + unsigned int chan; + unsigned int val; + int i, len, bufptr; + + pcl818_ai_setup_next_dma(dev, s); + + ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf]; + + len = devpriv->hwdmasize >> 1; + bufptr = 0; + + for (i = 0; i < len; i++) { + val = ptr[bufptr++]; + chan = val & 0xf; + val = (val >> 4) & s->maxdata; + + if (pcl818_ai_dropout(dev, s, chan)) + break; + + comedi_buf_put(s->async, val); + + if (!pcl818_ai_next_chan(dev, s)) + break; } } -/* -============================================================================== - Check if channel list from user is builded correctly - If it's ok, then program scan/gain logic -*/ +static void pcl818_handle_fifo(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int status; + unsigned int chan; + unsigned int val; + int i, len; + + status = inb(dev->iobase + PCL818_FI_STATUS); + + if (status & 4) { + comedi_error(dev, "A/D mode1/3 FIFO overflow!"); + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + return; + } + + if (status & 1) { + comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!"); + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + return; + } + + if (status & 2) + len = 512; + else + len = 0; + + for (i = 0; i < len; i++) { + val = pcl818_ai_get_fifo_sample(dev, s, &chan); + + if (pcl818_ai_dropout(dev, s, chan)) + break; + + comedi_buf_put(s->async, val); + + if (!pcl818_ai_next_chan(dev, s)) + break; + } +} + +static irqreturn_t pcl818_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct pcl818_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + + if (!dev->attached || !devpriv->ai_cmd_running) { + pcl818_ai_clear_eoc(dev); + return IRQ_HANDLED; + } + + if (devpriv->ai_cmd_canceled) { + /* + * The cleanup from ai_cancel() has been delayed + * until now because the card doesn't seem to like + * being reprogrammed while a DMA transfer is in + * progress. + */ + devpriv->ai_act_scan = 0; + s->cancel(dev, s); + return IRQ_HANDLED; + } + + if (devpriv->dma) + pcl818_handle_dma(dev, s); + else if (devpriv->usefifo) + pcl818_handle_fifo(dev, s); + else + pcl818_handle_eoc(dev, s); + + pcl818_ai_clear_eoc(dev); + + cfc_handle_events(dev, s); + return IRQ_HANDLED; +} + static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan) @@ -941,52 +728,20 @@ static int check_channel_list(struct comedi_device *dev, return seglen; } -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan, - unsigned int seglen) -{ - struct pcl818_private *devpriv = dev->private; - int i; - - devpriv->act_chanlist_len = seglen; - devpriv->act_chanlist_pos = 0; - - for (i = 0; i < seglen; i++) { /* store range list to card */ - devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]); - outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */ - outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */ - } - - udelay(1); - - /* select channel interval to scan */ - outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen - - 1] << 4), - dev->iobase + PCL818_MUX); -} - -/* -============================================================================== - Check if board is switched to SE (1) or DIFF(0) mode -*/ static int check_single_ended(unsigned int port) { - if (inb(port + PCL818_STATUS) & 0x20) + if (inb(port + PCL818_STATUS_REG) & PCL818_STATUS_MUX) return 1; return 0; } -/* -============================================================================== -*/ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { const struct pcl818_board *board = comedi_board(dev); struct pcl818_private *devpriv = dev->private; int err = 0; - int tmp, divisor1 = 0, divisor2 = 0; + int tmp; /* Step 1 : check if triggers are trivially valid */ @@ -1035,7 +790,8 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (cmd->convert_src == TRIG_TIMER) { tmp = cmd->convert_arg; i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, - &divisor1, &divisor2, + &devpriv->divisor1, + &devpriv->divisor2, &cmd->convert_arg, cmd->flags); if (cmd->convert_arg < board->ns_min) cmd->convert_arg = board->ns_min; @@ -1057,152 +813,272 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, return 0; } -/* -============================================================================== -*/ -static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) +static int pcl818_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { struct pcl818_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - int retval; + unsigned int ctrl = 0; + unsigned int seglen; + + if (devpriv->ai_cmd_running) + return -EBUSY; + + pcl818_start_pacer(dev, false); + + seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len); + if (seglen < 1) + return -EINVAL; + pcl818_ai_setup_chanlist(dev, cmd->chanlist, seglen); - devpriv->ai_n_chan = cmd->chanlist_len; - devpriv->ai_chanlist = cmd->chanlist; - devpriv->ai_flags = cmd->flags; devpriv->ai_data_len = s->async->prealloc_bufsz; - devpriv->ai_timer1 = 0; - devpriv->ai_timer2 = 0; + devpriv->ai_act_scan = cmd->stop_arg; + devpriv->ai_act_chan = 0; + devpriv->ai_cmd_running = 1; + devpriv->ai_cmd_canceled = 0; + devpriv->act_chanlist_pos = 0; + devpriv->dma_runs_to_end = 0; - if (cmd->stop_src == TRIG_COUNT) - devpriv->ai_scans = cmd->stop_arg; + if (cmd->convert_src == TRIG_TIMER) + ctrl |= PCL818_CTRL_PACER_TRIG; else - devpriv->ai_scans = 0; + ctrl |= PCL818_CTRL_EXT_TRIG; - if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */ - if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */ - devpriv->ai_timer1 = cmd->convert_arg; - retval = pcl818_ai_cmd_mode(1, dev, s); - return retval; - } - if (cmd->convert_src == TRIG_EXT) { /* mode 3 */ - return pcl818_ai_cmd_mode(3, dev, s); - } + outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG); + + if (devpriv->dma) { + pcl818_ai_setup_dma(dev, s); + + ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq) | + PCL818_CTRL_DMAE; + } else if (devpriv->usefifo) { + /* enable FIFO */ + outb(1, dev->iobase + PCL818_FI_ENABLE); + } else { + ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq); } + outb(ctrl, dev->iobase + PCL818_CTRL_REG); - return -1; + if (cmd->convert_src == TRIG_TIMER) + pcl818_start_pacer(dev, true); + + return 0; } -/* -============================================================================== - cancel any mode 1-4 AI -*/ static int pcl818_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - if (devpriv->irq_blocked > 0) { - devpriv->irq_was_now_closed = 1; + if (!devpriv->ai_cmd_running) + return 0; - switch (devpriv->ai_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - if (devpriv->neverending_ai || - (!devpriv->neverending_ai && - devpriv->ai_act_scan > 0)) { - /* wait for running dma transfer to end, do cleanup in interrupt */ - goto end; + if (devpriv->dma) { + if (cmd->stop_src == TRIG_NONE || + (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan > 0)) { + if (!devpriv->ai_cmd_canceled) { + /* + * Wait for running dma transfer to end, + * do cleanup in interrupt. + */ + devpriv->ai_cmd_canceled = 1; + return 0; } - disable_dma(devpriv->dma); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - case INT_TYPE_AI1_FIFO: - case INT_TYPE_AI3_FIFO: -#ifdef PCL818_MODE13_AO - case INT_TYPE_AO1_INT: - case INT_TYPE_AO3_INT: -#endif - outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */ - udelay(1); - start_pacer(dev, -1, 0, 0); - outb(0, dev->iobase + PCL818_AD_LO); - inb(dev->iobase + PCL818_AD_LO); - inb(dev->iobase + PCL818_AD_HI); - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */ - if (devpriv->usefifo) { /* FIFO shutdown */ - outb(0, dev->iobase + PCL818_FI_INTCLR); - outb(0, dev->iobase + PCL818_FI_FLUSH); - outb(0, dev->iobase + PCL818_FI_ENABLE); - } - devpriv->irq_blocked = 0; - devpriv->last_int_sub = s; - devpriv->neverending_ai = 0; - devpriv->ai_mode = 0; - devpriv->irq_was_now_closed = 0; - break; } + disable_dma(devpriv->dma); } -end: - return 0; -} - -/* -============================================================================== - chech for PCL818 -*/ -static int pcl818_check(unsigned long iobase) -{ - outb(0x00, iobase + PCL818_MUX); - udelay(1); - if (inb(iobase + PCL818_MUX) != 0x00) - return 1; /* there isn't card */ - outb(0x55, iobase + PCL818_MUX); - udelay(1); - if (inb(iobase + PCL818_MUX) != 0x55) - return 1; /* there isn't card */ - outb(0x00, iobase + PCL818_MUX); - udelay(1); - outb(0x18, iobase + PCL818_CONTROL); - udelay(1); - if (inb(iobase + PCL818_CONTROL) != 0x18) - return 1; /* there isn't card */ - return 0; /* ok, card exist */ -} - -/* -============================================================================== - reset whole PCL-818 cards -*/ -static void pcl818_reset(struct comedi_device *dev) -{ - const struct pcl818_board *board = comedi_board(dev); - struct pcl818_private *devpriv = dev->private; + outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG); + pcl818_start_pacer(dev, false); + pcl818_ai_clear_eoc(dev); if (devpriv->usefifo) { /* FIFO shutdown */ outb(0, dev->iobase + PCL818_FI_INTCLR); outb(0, dev->iobase + PCL818_FI_FLUSH); outb(0, dev->iobase + PCL818_FI_ENABLE); } - outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */ - outb(0, dev->iobase + PCL818_DA_HI); - udelay(1); - outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */ - outb(0, dev->iobase + PCL818_DO_LO); - udelay(1); - outb(0, dev->iobase + PCL818_CONTROL); - outb(0, dev->iobase + PCL818_CNTENABLE); - outb(0, dev->iobase + PCL818_MUX); - outb(0, dev->iobase + PCL818_CLRINT); - outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */ - outb(0x70, dev->iobase + PCL818_CTRCTL); - outb(0x30, dev->iobase + PCL818_CTRCTL); + devpriv->ai_cmd_running = 0; + devpriv->ai_cmd_canceled = 0; + + return 0; +} + +static int pcl818_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + int ret = 0; + int i; + + outb(PCL818_CTRL_SOFT_TRIG, dev->iobase + PCL818_CTRL_REG); + + pcl818_ai_set_chan_range(dev, chan, range); + pcl818_ai_set_chan_scan(dev, chan, chan); + + for (i = 0; i < insn->n; i++) { + pcl818_ai_clear_eoc(dev); + pcl818_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, pcl818_ai_eoc, 0); + if (ret) + break; + + data[i] = pcl818_ai_get_sample(dev, s, NULL); + } + pcl818_ai_clear_eoc(dev); + + return ret ? ret : insn->n; +} + +static int pcl818_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl818_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) { + devpriv->ao_readback[chan] = data[i]; + outb((data[i] & 0x000f) << 4, + dev->iobase + PCL818_AO_LSB_REG(chan)); + outb((data[i] & 0x0ff0) >> 4, + dev->iobase + PCL818_AO_MSB_REG(chan)); + } + + return insn->n; +} + +static int pcl818_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl818_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return insn->n; +} + +static int pcl818_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + PCL818_DO_DI_LSB_REG) | + (inb(dev->iobase + PCL818_DO_DI_MSB_REG) << 8); + + return insn->n; +} + +static int pcl818_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase + PCL818_DO_DI_LSB_REG); + outb((s->state >> 8), dev->iobase + PCL818_DO_DI_MSB_REG); + } + + data[1] = s->state; + + return insn->n; +} + +static void pcl818_reset(struct comedi_device *dev) +{ + const struct pcl818_board *board = comedi_board(dev); + unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE; + unsigned int chan; + + /* flush and disable the FIFO */ + if (board->has_fifo) { + outb(0, dev->iobase + PCL818_FI_INTCLR); + outb(0, dev->iobase + PCL818_FI_FLUSH); + outb(0, dev->iobase + PCL818_FI_ENABLE); + } + + /* disable analog input trigger */ + outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG); + pcl818_ai_clear_eoc(dev); + + pcl818_ai_set_chan_range(dev, 0, 0); + + /* stop pacer */ + outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG); + i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY); + + /* set analog output channels to 0V */ + for (chan = 0; chan < board->n_aochan; chan++) { + outb(0, dev->iobase + PCL818_AO_LSB_REG(chan)); + outb(0, dev->iobase + PCL818_AO_MSB_REG(chan)); + } + + /* set all digital outputs low */ + outb(0, dev->iobase + PCL818_DO_DI_MSB_REG); + outb(0, dev->iobase + PCL818_DO_DI_LSB_REG); +} + +static void pcl818_set_ai_range_table(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_devconfig *it) +{ + const struct pcl818_board *board = comedi_board(dev); + + /* default to the range table from the boardinfo */ + s->range_table = board->ai_range_type; + + /* now check the user config option based on the boardtype */ if (board->is_818) { - outb(0, dev->iobase + PCL818_RANGE); + if (it->options[4] == 1 || it->options[4] == 10) { + /* secondary range list jumper selectable */ + s->range_table = &range_pcl818l_h_ai; + } } else { - outb(0, dev->iobase + PCL718_DA2_LO); - outb(0, dev->iobase + PCL718_DA2_HI); + switch (it->options[4]) { + case 0: + s->range_table = &range_bipolar10; + break; + case 1: + s->range_table = &range_bipolar5; + break; + case 2: + s->range_table = &range_bipolar2_5; + break; + case 3: + s->range_table = &range718_bipolar1; + break; + case 4: + s->range_table = &range718_bipolar0_5; + break; + case 6: + s->range_table = &range_unipolar10; + break; + case 7: + s->range_table = &range_unipolar5; + break; + case 8: + s->range_table = &range718_unipolar2; + break; + case 9: + s->range_table = &range718_unipolar1; + break; + default: + s->range_table = &range_unknown; + break; + } } } @@ -1210,154 +1086,96 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl818_board *board = comedi_board(dev); struct pcl818_private *devpriv; - int ret; - int dma; - unsigned long pages; struct comedi_subdevice *s; + int ret; + int i; devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); if (!devpriv) return -ENOMEM; - devpriv->io_range = board->io_range; - if ((board->fifo) && (it->options[2] == -1)) { - /* we've board with FIFO and we want to use FIFO */ - devpriv->io_range = PCLx1xFIFO_RANGE; - devpriv->usefifo = 1; - } - ret = comedi_request_region(dev, it->options[0], devpriv->io_range); + ret = comedi_request_region(dev, it->options[0], + board->has_fifo ? 0x20 : 0x10); if (ret) return ret; - if (pcl818_check(dev->iobase)) { - comedi_error(dev, "I can't detect board. FAIL!\n"); - return -EIO; - } - - if ((1 << it->options[1]) & board->IRQbits) { - ret = request_irq(it->options[1], interrupt_pcl818, 0, + /* we can use IRQ 2-7 for async command support */ + if (it->options[1] >= 2 && it->options[1] <= 7) { + ret = request_irq(it->options[1], pcl818_interrupt, 0, dev->board_name, dev); if (ret == 0) dev->irq = it->options[1]; } - devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */ - devpriv->ai_mode = 0; /* mode of irq */ + /* should we use the FIFO? */ + if (dev->irq && board->has_fifo && it->options[2] == -1) + devpriv->usefifo = 1; - /* grab our DMA */ - dma = 0; - devpriv->dma = dma; - if (!dev->irq) - goto no_dma; /* if we haven't IRQ, we can't use DMA */ - if (board->DMAbits != 0) { /* board support DMA */ - dma = it->options[2]; - if (dma < 1) - goto no_dma; /* DMA disabled */ - if (((1 << dma) & board->DMAbits) == 0) { + /* we need an IRQ to do DMA on channel 3 or 1 */ + if (dev->irq && board->has_dma && + (it->options[2] == 3 || it->options[2] == 1)) { + ret = request_dma(it->options[2], dev->board_name); + if (ret) { dev_err(dev->class_dev, - "DMA is out of allowed range, FAIL!\n"); - return -EINVAL; /* Bad DMA */ - } - ret = request_dma(dma, dev->board_name); - if (ret) - return -EBUSY; /* DMA isn't free */ - devpriv->dma = dma; - pages = 2; /* we need 16KB */ - devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[0]) - /* maybe experiment with try_to_free_pages() will help .... */ - return -EBUSY; /* no buffer :-( */ - devpriv->dmapages[0] = pages; - devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); - devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE; - devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[1]) + "unable to request DMA channel %d\n", + it->options[2]); return -EBUSY; - devpriv->dmapages[1] = pages; - devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]); - devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE; - } + } + devpriv->dma = it->options[2]; -no_dma: + devpriv->dmapages = 2; /* we need 16KB */ + devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; + + for (i = 0; i < 2; i++) { + unsigned long dmabuf; + + dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); + if (!dmabuf) + return -ENOMEM; + + devpriv->dmabuf[i] = dmabuf; + devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); + } + } ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; s = &dev->subdevices[0]; - if (!board->n_aichan_se) { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE; + if (check_single_ended(dev->iobase)) { + s->n_chan = 16; + s->subdev_flags |= SDF_COMMON | SDF_GROUND; } else { - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE; - if (check_single_ended(dev->iobase)) { - s->n_chan = board->n_aichan_se; - s->subdev_flags |= SDF_COMMON | SDF_GROUND; - } else { - s->n_chan = board->n_aichan_diff; - s->subdev_flags |= SDF_DIFF; - } - s->maxdata = board->ai_maxdata; - s->range_table = board->ai_range_type; - s->insn_read = pcl818_ai_insn_read; - if (dev->irq) { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->len_chanlist = s->n_chan; - s->do_cmdtest = ai_cmdtest; - s->do_cmd = ai_cmd; - s->cancel = pcl818_ai_cancel; - } - if (board->is_818) { - if ((it->options[4] == 1) || (it->options[4] == 10)) - s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */ - } else { - switch (it->options[4]) { - case 0: - s->range_table = &range_bipolar10; - break; - case 1: - s->range_table = &range_bipolar5; - break; - case 2: - s->range_table = &range_bipolar2_5; - break; - case 3: - s->range_table = &range718_bipolar1; - break; - case 4: - s->range_table = &range718_bipolar0_5; - break; - case 6: - s->range_table = &range_unipolar10; - break; - case 7: - s->range_table = &range_unipolar5; - break; - case 8: - s->range_table = &range718_unipolar2; - break; - case 9: - s->range_table = &range718_unipolar1; - break; - default: - s->range_table = &range_unknown; - break; - } - } + s->n_chan = 8; + s->subdev_flags |= SDF_DIFF; + } + s->maxdata = 0x0fff; + + pcl818_set_ai_range_table(dev, s, it); + + s->insn_read = pcl818_ai_insn_read; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmdtest = ai_cmdtest; + s->do_cmd = pcl818_ai_cmd; + s->cancel = pcl818_ai_cancel; } + /* Analog Output subdevice */ s = &dev->subdevices[1]; - if (!board->n_aochan) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = board->n_aochan; - s->maxdata = board->ao_maxdata; - s->range_table = board->ao_range_type; - s->insn_read = pcl818_ao_insn_read; - s->insn_write = pcl818_ao_insn_write; + if (board->n_aochan) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->n_chan = board->n_aochan; + s->maxdata = 0x0fff; + s->range_table = &range_unipolar5; + s->insn_read = pcl818_ao_insn_read; + s->insn_write = pcl818_ao_insn_write; if (board->is_818) { if ((it->options[4] == 1) || (it->options[4] == 10)) s->range_table = &range_unipolar10; @@ -1369,31 +1187,27 @@ no_dma: if (it->options[5] == 2) s->range_table = &range_unknown; } + } else { + s->type = COMEDI_SUBD_UNUSED; } + /* Digital Input subdevice */ s = &dev->subdevices[2]; - if (!board->n_dichan) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = board->n_dichan; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = pcl818_di_insn_bits; - } + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl818_di_insn_bits; + /* Digital Output subdevice */ s = &dev->subdevices[3]; - if (!board->n_dochan) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = board->n_dochan; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = pcl818_do_insn_bits; - } + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl818_do_insn_bits; /* select 1/10MHz oscilator */ if ((it->options[3] == 0) || (it->options[3] == 10)) @@ -1424,38 +1238,13 @@ static void pcl818_detach(struct comedi_device *dev) if (devpriv->dma) free_dma(devpriv->dma); if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); + free_pages(devpriv->dmabuf[0], devpriv->dmapages); if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); + free_pages(devpriv->dmabuf[1], devpriv->dmapages); } comedi_legacy_detach(dev); } -static const struct pcl818_board boardtypes[] = { - {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 1, 1}, - {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 1, 1}, - {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 0}, - /* pcm3718 */ - {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ }, -}; - static struct comedi_driver pcl818_driver = { .driver_name = "pcl818", .module = THIS_MODULE, diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c index f4a49bd649f0..53e73737a906 100644 --- a/drivers/staging/comedi/drivers/pcm3724.c +++ b/drivers/staging/comedi/drivers/pcm3724.c @@ -225,8 +225,10 @@ static int pcm3724_attach(struct comedi_device *dev, for (i = 0; i < dev->n_subdevices; i++) { s = &dev->subdevices[i]; - subdev_8255_init(dev, s, subdev_8255_cb, - (unsigned long)(dev->iobase + SIZE_8255 * i)); + ret = subdev_8255_init(dev, s, subdev_8255_cb, + dev->iobase + SIZE_8255 * i); + if (ret) + return ret; s->insn_config = subdev_3724_insn_config; } return 0; diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c index fe482fdd512e..87c61d9b11da 100644 --- a/drivers/staging/comedi/drivers/pcmad.c +++ b/drivers/staging/comedi/drivers/pcmad.c @@ -61,18 +61,17 @@ static const struct pcmad_board_struct pcmad_boards[] = { }, }; -#define TIMEOUT 100 - -static int pcmad_ai_wait_for_eoc(struct comedi_device *dev, - int timeout) +static int pcmad_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - int i; + unsigned int status; - for (i = 0; i < timeout; i++) { - if ((inb(dev->iobase + PCMAD_STATUS) & 0x3) == 0x3) - return 0; - } - return -ETIME; + status = inb(dev->iobase + PCMAD_STATUS); + if ((status & 0x3) == 0x3) + return 0; + return -EBUSY; } static int pcmad_ai_insn_read(struct comedi_device *dev, @@ -89,7 +88,7 @@ static int pcmad_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outb(chan, dev->iobase + PCMAD_CONVERT); - ret = pcmad_ai_wait_for_eoc(dev, TIMEOUT); + ret = comedi_timeout(dev, s, insn, pcmad_ai_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index c388f7f32227..e89bca845349 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -589,16 +589,17 @@ static int pcmmio_cmdtest(struct comedi_device *dev, return 0; } -static int pcmmio_ai_wait_for_eoc(unsigned long iobase, unsigned int timeout) +static int pcmmio_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned char status; - while (timeout--) { - status = inb(iobase + PCMMIO_AI_STATUS_REG); - if (status & PCMMIO_AI_STATUS_DATA_READY) - return 0; - } - return -ETIME; + status = inb(dev->iobase + PCMMIO_AI_STATUS_REG); + if (status & PCMMIO_AI_STATUS_DATA_READY) + return 0; + return -EBUSY; } static int pcmmio_ai_insn_read(struct comedi_device *dev, @@ -643,7 +644,8 @@ static int pcmmio_ai_insn_read(struct comedi_device *dev, cmd |= PCMMIO_AI_CMD_RANGE(range); outb(cmd, iobase + PCMMIO_AI_CMD_REG); - ret = pcmmio_ai_wait_for_eoc(iobase, 100000); + + ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0); if (ret) return ret; @@ -652,7 +654,8 @@ static int pcmmio_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outb(cmd, iobase + PCMMIO_AI_CMD_REG); - ret = pcmmio_ai_wait_for_eoc(iobase, 100000); + + ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0); if (ret) return ret; @@ -684,16 +687,17 @@ static int pcmmio_ao_insn_read(struct comedi_device *dev, return insn->n; } -static int pcmmio_ao_wait_for_eoc(unsigned long iobase, unsigned int timeout) +static int pcmmio_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned char status; - while (timeout--) { - status = inb(iobase + PCMMIO_AO_STATUS_REG); - if (status & PCMMIO_AO_STATUS_DATA_READY) - return 0; - } - return -ETIME; + status = inb(dev->iobase + PCMMIO_AO_STATUS_REG); + if (status & PCMMIO_AO_STATUS_DATA_READY) + return 0; + return -EBUSY; } static int pcmmio_ao_insn_write(struct comedi_device *dev, @@ -726,7 +730,8 @@ static int pcmmio_ao_insn_write(struct comedi_device *dev, outb(PCMMIO_AO_LSB_SPAN(range), iobase + PCMMIO_AO_LSB_REG); outb(0, iobase + PCMMIO_AO_MSB_REG); outb(cmd | PCMMIO_AO_CMD_WR_SPAN_UPDATE, iobase + PCMMIO_AO_CMD_REG); - ret = pcmmio_ao_wait_for_eoc(iobase, 100000); + + ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0); if (ret) return ret; @@ -738,7 +743,8 @@ static int pcmmio_ao_insn_write(struct comedi_device *dev, outb((val >> 8) & 0xff, iobase + PCMMIO_AO_MSB_REG); outb(cmd | PCMMIO_AO_CMD_WR_CODE_UPDATE, iobase + PCMMIO_AO_CMD_REG); - ret = pcmmio_ao_wait_for_eoc(iobase, 100000); + + ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 55e3c2e2bc52..25706531b885 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -29,13 +29,13 @@ /* descriptor block used for chained dma transfers */ struct plx_dma_desc { - volatile uint32_t pci_start_addr; - volatile uint32_t local_start_addr; + __le32 pci_start_addr; + __le32 local_start_addr; /* transfer_size is in bytes, only first 23 bits of register are used */ - volatile uint32_t transfer_size; + __le32 transfer_size; /* address of next descriptor (quad word aligned), plus some * additional bits (see PLX_DMA0_DESCRIPTOR_REG) */ - volatile uint32_t next; + __le32 next; }; /********************************************************************** diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c deleted file mode 100644 index 2ae4ee15704c..000000000000 --- a/drivers/staging/comedi/drivers/poc.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - comedi/drivers/poc.c - Mini-drivers for POC (Piece of Crap) boards - Copyright (C) 2000 Frank Mori Hess - Copyright (C) 2001 David A. Schleef - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: poc -Description: Generic driver for very simple devices -Author: ds -Devices: [Keithley Metrabyte] DAC-02 (dac02) -Updated: Sat, 16 Mar 2002 17:34:48 -0800 -Status: unknown - -This driver is indended to support very simple ISA-based devices, -including: - dac02 - Keithley DAC-02 analog output board - -Configuration options: - [0] - I/O port base -*/ - -#include -#include "../comedidev.h" - -struct boarddef_struct { - const char *name; - unsigned int iosize; - int (*setup) (struct comedi_device *); - int type; - int n_chan; - int n_bits; - int (*winsn) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*rinsn) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*insnbits) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - const struct comedi_lrange *range; -}; - -struct poc_private { - unsigned int ao_readback[32]; -}; - -static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct poc_private *devpriv = dev->private; - int chan; - - chan = CR_CHAN(insn->chanspec); - data[0] = devpriv->ao_readback[chan]; - - return 1; -} - -/* DAC-02 registers */ -#define DAC02_LSB(a) (2 * a) -#define DAC02_MSB(a) (2 * a + 1) - -static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct poc_private *devpriv = dev->private; - int temp; - int chan; - int output; - - chan = CR_CHAN(insn->chanspec); - devpriv->ao_readback[chan] = data[0]; - output = data[0]; -#ifdef wrong - /* convert to complementary binary if range is bipolar */ - if ((CR_RANGE(insn->chanspec) & 0x2) == 0) - output = ~output; -#endif - temp = (output << 4) & 0xf0; - outb(temp, dev->iobase + DAC02_LSB(chan)); - temp = (output >> 4) & 0xff; - outb(temp, dev->iobase + DAC02_MSB(chan)); - - return 1; -} - -static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - const struct boarddef_struct *board = comedi_board(dev); - struct poc_private *devpriv; - struct comedi_subdevice *s; - int ret; - - ret = comedi_request_region(dev, it->options[0], board->iosize); - if (ret) - return ret; - - ret = comedi_alloc_subdevices(dev, 1); - if (ret) - return ret; - - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - - /* analog output subdevice */ - s = &dev->subdevices[0]; - s->type = board->type; - s->n_chan = board->n_chan; - s->maxdata = (1 << board->n_bits) - 1; - s->range_table = board->range; - s->insn_write = board->winsn; - s->insn_read = board->rinsn; - s->insn_bits = board->insnbits; - if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO) - s->subdev_flags = SDF_WRITABLE; - - return 0; -} - -static const struct boarddef_struct boards[] = { - { - .name = "dac02", - .iosize = 8, - /* .setup = dac02_setup, */ - .type = COMEDI_SUBD_AO, - .n_chan = 2, - .n_bits = 12, - .winsn = dac02_ao_winsn, - .rinsn = readback_insn, - .range = &range_unknown, - }, -}; - -static struct comedi_driver poc_driver = { - .driver_name = "poc", - .module = THIS_MODULE, - .attach = poc_attach, - .detach = comedi_legacy_detach, - .board_name = &boards[0].name, - .num_names = ARRAY_SIZE(boards), - .offset = sizeof(boards[0]), -}; -module_comedi_driver(poc_driver); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index 96a46954b3c0..298dba03f902 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -214,7 +214,6 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) s->async->events |= COMEDI_CB_EOA | COMEDI_CB_OVERFLOW; dev_warn(dev->class_dev, "data lost\n"); - daqp_ai_cancel(dev, s); break; } @@ -231,7 +230,6 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) if (devpriv->count > 0) { devpriv->count--; if (devpriv->count == 0) { - daqp_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; break; } @@ -244,13 +242,12 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) if (loop_limit <= 0) { dev_warn(dev->class_dev, "loop_limit reached in daqp_interrupt()\n"); - daqp_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } s->async->events |= COMEDI_CB_BLOCK; - comedi_event(dev, s); + cfc_handle_events(dev, s); } return IRQ_HANDLED; } diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 0f026afde9be..cd3fdf973bdd 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -237,20 +237,6 @@ /* The board support a channel list up to the FIFO length (1K or 8K) */ #define RTD_MAX_CHANLIST 128 /* max channel list that we allow */ -/* tuning for ai/ao instruction done polling */ -#ifdef FAST_SPIN -#define WAIT_QUIETLY /* as nothing, spin on done bit */ -#define RTD_ADC_TIMEOUT 66000 /* 2 msec at 33mhz bus rate */ -#define RTD_DAC_TIMEOUT 66000 -#define RTD_DMA_TIMEOUT 33000 /* 1 msec */ -#else -/* by delaying, power and electrical noise are reduced somewhat */ -#define WAIT_QUIETLY udelay(1) -#define RTD_ADC_TIMEOUT 2000 /* in usec */ -#define RTD_DAC_TIMEOUT 2000 /* in usec */ -#define RTD_DMA_TIMEOUT 1000 /* in usec */ -#endif - /*====================================================================== Board specific stuff ======================================================================*/ @@ -562,21 +548,27 @@ static int rtd520_probe_fifo_depth(struct comedi_device *dev) return fifo_size; } -/* - "instructions" read/write data in "one-shot" or "software-triggered" - mode (simplest case). - This doesn't use interrupts. +static int rtd_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct rtd_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->las0 + LAS0_ADC); + if (status & FS_ADC_NOT_EMPTY) + return 0; + return -EBUSY; +} - Note, we don't do any settling delays. Use a instruction list to - select, delay, then read. - */ static int rtd_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct rtd_private *devpriv = dev->private; - int n, ii; - int stat; + int ret; + int n; /* clear any old fifo data */ writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR); @@ -593,14 +585,9 @@ static int rtd_ai_rinsn(struct comedi_device *dev, /* trigger conversion */ writew(0, devpriv->las0 + LAS0_ADC); - for (ii = 0; ii < RTD_ADC_TIMEOUT; ++ii) { - stat = readl(devpriv->las0 + LAS0_ADC); - if (stat & FS_ADC_NOT_EMPTY) /* 1 -> not empty */ - break; - WAIT_QUIETLY; - } - if (ii >= RTD_ADC_TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, rtd_ai_eoc, 0); + if (ret) + return ret; /* read data */ d = readw(devpriv->las1 + LAS1_ADC_FIFO); @@ -1116,9 +1103,22 @@ static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -/* - Output one (or more) analog values to a single port as fast as possible. -*/ +static int rtd_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct rtd_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int bit = (chan == 0) ? FS_DAC1_NOT_EMPTY : FS_DAC2_NOT_EMPTY; + unsigned int status; + + status = readl(devpriv->las0 + LAS0_ADC); + if (status & bit) + return 0; + return -EBUSY; +} + static int rtd_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -1127,6 +1127,7 @@ static int rtd_ao_winsn(struct comedi_device *dev, int i; int chan = CR_CHAN(insn->chanspec); int range = CR_RANGE(insn->chanspec); + int ret; /* Configure the output range (table index matches the range values) */ writew(range & 7, devpriv->las0 + @@ -1136,8 +1137,6 @@ static int rtd_ao_winsn(struct comedi_device *dev, * very useful, but that's how the interface is defined. */ for (i = 0; i < insn->n; ++i) { int val = data[i] << 3; - int stat = 0; /* initialize to avoid bogus warning */ - int ii; /* VERIFY: comedi range and offset conversions */ @@ -1157,16 +1156,9 @@ static int rtd_ao_winsn(struct comedi_device *dev, devpriv->ao_readback[chan] = data[i]; - for (ii = 0; ii < RTD_DAC_TIMEOUT; ++ii) { - stat = readl(devpriv->las0 + LAS0_ADC); - /* 1 -> not empty */ - if (stat & ((0 == chan) ? FS_DAC1_NOT_EMPTY : - FS_DAC2_NOT_EMPTY)) - break; - WAIT_QUIETLY; - } - if (ii >= RTD_DAC_TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, rtd_ao_eoc, 0); + if (ret) + return ret; } /* return the number of samples read/written */ @@ -1382,8 +1374,6 @@ static int rtd_auto_attach(struct comedi_device *dev, if (dev->irq) writel(ICS_PIE | ICS_PLIE, devpriv->lcfg + PLX_INTRCS_REG); - dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 0; } diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c index e1f3671ac056..bd447b2add7b 100644 --- a/drivers/staging/comedi/drivers/rti800.c +++ b/drivers/staging/comedi/drivers/rti800.c @@ -83,8 +83,6 @@ #define RTI800_IOSIZE 0x10 -#define RTI800_AI_TIMEOUT 100 - static const struct comedi_lrange range_rti800_ai_10_bipolar = { 4, { BIP_RANGE(10), @@ -145,23 +143,21 @@ struct rti800_private { unsigned char muxgain_bits; }; -static int rti800_ai_wait_for_conversion(struct comedi_device *dev, - int timeout) +static int rti800_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { unsigned char status; - int i; - for (i = 0; i < timeout; i++) { - status = inb(dev->iobase + RTI800_CSR); - if (status & RTI800_CSR_OVERRUN) { - outb(0, dev->iobase + RTI800_CLRFLAGS); - return -EIO; - } - if (status & RTI800_CSR_DONE) - return 0; - udelay(1); + status = inb(dev->iobase + RTI800_CSR); + if (status & RTI800_CSR_OVERRUN) { + outb(0, dev->iobase + RTI800_CLRFLAGS); + return -EOVERFLOW; } - return -ETIME; + if (status & RTI800_CSR_DONE) + return 0; + return -EBUSY; } static int rti800_ai_insn_read(struct comedi_device *dev, @@ -198,7 +194,8 @@ static int rti800_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { outb(0, dev->iobase + RTI800_CONVERT); - ret = rti800_ai_wait_for_conversion(dev, RTI800_AI_TIMEOUT); + + ret = comedi_timeout(dev, s, insn, rti800_ai_eoc, 0); if (ret) return ret; diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c index a3fa2a4baef4..605a31d702e0 100644 --- a/drivers/staging/comedi/drivers/rti802.c +++ b/drivers/staging/comedi/drivers/rti802.c @@ -1,45 +1,44 @@ /* - comedi/drivers/rti802.c - Hardware driver for Analog Devices RTI-802 board - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999 Anders Blomdell - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * rti802.c + * Comedi driver for Analog Devices RTI-802 board + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1999 Anders Blomdell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ -/* -Driver: rti802 -Description: Analog Devices RTI-802 -Author: Anders Blomdell -Devices: [Analog Devices] RTI-802 (rti802) -Status: works -Configuration Options: - [0] - i/o base - [1] - unused - [2] - dac#0 0=two's comp, 1=straight - [3] - dac#0 0=bipolar, 1=unipolar - [4] - dac#1 ... - ... - [17] - dac#7 ... -*/ +/* + * Driver: rti802 + * Description: Analog Devices RTI-802 + * Author: Anders Blomdell + * Devices: (Analog Devices) RTI-802 [rti802] + * Status: works + * + * Configuration Options: + * [0] - i/o base + * [1] - unused + * [2,4,6,8,10,12,14,16] - dac#[0-7] 0=two's comp, 1=straight + * [3,5,7,9,11,13,15,17] - dac#[0-7] 0=bipolar, 1=unipolar + */ #include #include "../comedidev.h" -#define RTI802_SIZE 4 - -#define RTI802_SELECT 0 -#define RTI802_DATALOW 1 -#define RTI802_DATAHIGH 2 +/* + * Register I/O map + */ +#define RTI802_SELECT 0x00 +#define RTI802_DATALOW 0x01 +#define RTI802_DATAHIGH 0x02 struct rti802_private { enum { @@ -51,34 +50,45 @@ struct rti802_private { static int rti802_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct rti802_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; + data[i] = devpriv->ao_readback[chan]; - return i; + return insn->n; } static int rti802_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { struct rti802_private *devpriv = dev->private; - int i, d; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; + + outb(chan, dev->iobase + RTI802_SELECT); for (i = 0; i < insn->n; i++) { - d = devpriv->ao_readback[chan] = data[i]; + val = data[i]; + + devpriv->ao_readback[chan] = val; + + /* munge offset binary to two's complement if needed */ if (devpriv->dac_coding[chan] == dac_2comp) - d ^= 0x800; - outb(chan, dev->iobase + RTI802_SELECT); - outb(d & 0xff, dev->iobase + RTI802_DATALOW); - outb(d >> 8, dev->iobase + RTI802_DATAHIGH); + val = comedi_offset_munge(s, val); + + outb(val & 0xff, dev->iobase + RTI802_DATALOW); + outb((val >> 8) & 0xff, dev->iobase + RTI802_DATAHIGH); } - return i; + + return insn->n; } static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) @@ -88,7 +98,7 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) int i; int ret; - ret = comedi_request_region(dev, it->options[0], RTI802_SIZE); + ret = comedi_request_region(dev, it->options[0], 0x04); if (ret) return ret; @@ -100,22 +110,21 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; + /* Analog Output subdevice */ s = &dev->subdevices[0]; - /* ao subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 0xfff; - s->n_chan = 8; - s->insn_read = rti802_ao_insn_read; - s->insn_write = rti802_ao_insn_write; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->maxdata = 0xfff; + s->n_chan = 8; + s->insn_read = rti802_ao_insn_read; + s->insn_write = rti802_ao_insn_write; s->range_table_list = devpriv->range_type_list; for (i = 0; i < 8; i++) { devpriv->dac_coding[i] = (it->options[3 + 2 * i]) - ? (dac_straight) - : (dac_2comp); + ? (dac_straight) : (dac_2comp); devpriv->range_type_list[i] = (it->options[2 + 2 * i]) - ? &range_unipolar10 : &range_bipolar10; + ? &range_unipolar10 : &range_bipolar10; } return 0; @@ -130,5 +139,5 @@ static struct comedi_driver rti802_driver = { module_comedi_driver(rti802_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Analog Devices RTI-802 board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c index 9950f59b1192..85d2b7a3c125 100644 --- a/drivers/staging/comedi/drivers/s526.c +++ b/drivers/staging/comedi/drivers/s526.c @@ -420,15 +420,28 @@ static int s526_ai_insn_config(struct comedi_device *dev, return result; } +static int s526_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + REG_ISR); + if (status & ISR_ADC_DONE) + return 0; + return -EBUSY; +} + static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { struct s526_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); - int n, i; + int n; unsigned short value; unsigned int d; - unsigned int status; + int ret; /* Set configured delay, enable channel for this channel only, * select "ADC read" channel, set "ADC start" bit. */ @@ -440,17 +453,12 @@ static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* trigger conversion */ outw(value, dev->iobase + REG_ADC); -#define TIMEOUT 100 /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = inw(dev->iobase + REG_ISR); - if (status & ISR_ADC_DONE) { - outw(ISR_ADC_DONE, dev->iobase + REG_ISR); - break; - } - } - if (i == TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, s526_ai_eoc, 0); + if (ret) + return ret; + + outw(ISR_ADC_DONE, dev->iobase + REG_ISR); /* read data */ d = inw(dev->iobase + REG_ADD); @@ -604,7 +612,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_bits = s526_dio_insn_bits; s->insn_config = s526_dio_insn_config; - return 1; + return 0; } static struct comedi_driver s526_driver = { diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 19da1dbea494..95fadf343f27 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -106,16 +106,16 @@ struct s626_private { struct s626_enc_info { /* Pointers to functions that differ for A and B counters: */ /* Return clock enable. */ - uint16_t(*get_enable)(struct comedi_device *dev, + uint16_t (*get_enable)(struct comedi_device *dev, const struct s626_enc_info *k); /* Return interrupt source. */ - uint16_t(*get_int_src)(struct comedi_device *dev, + uint16_t (*get_int_src)(struct comedi_device *dev, const struct s626_enc_info *k); /* Return preload trigger source. */ - uint16_t(*get_load_trig)(struct comedi_device *dev, + uint16_t (*get_load_trig)(struct comedi_device *dev, const struct s626_enc_info *k); /* Return standardized operating mode. */ - uint16_t(*get_mode)(struct comedi_device *dev, + uint16_t (*get_mode)(struct comedi_device *dev, const struct s626_enc_info *k); /* Generate soft index strobe. */ void (*pulse_index)(struct comedi_device *dev, @@ -209,6 +209,8 @@ static const struct comedi_lrange s626_range_table = { static void s626_debi_transfer(struct comedi_device *dev) { struct s626_private *devpriv = dev->private; + static const int timeout = 10000; + int i; /* Initiate upload of shadow RAM to DEBI control register */ s626_mc_enable(dev, S626_MC2_UPLD_DEBI, S626_P_MC2); @@ -217,12 +219,23 @@ static void s626_debi_transfer(struct comedi_device *dev) * Wait for completion of upload from shadow RAM to * DEBI control register. */ - while (!s626_mc_test(dev, S626_MC2_UPLD_DEBI, S626_P_MC2)) - ; + for (i = 0; i < timeout; i++) { + if (s626_mc_test(dev, S626_MC2_UPLD_DEBI, S626_P_MC2)) + break; + udelay(1); + } + if (i == timeout) + comedi_error(dev, + "Timeout while uploading to DEBI control register."); /* Wait until DEBI transfer is done */ - while (readl(devpriv->mmio + S626_P_PSR) & S626_PSR_DEBI_S) - ; + for (i = 0; i < timeout; i++) { + if (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_DEBI_S)) + break; + udelay(1); + } + if (i == timeout) + comedi_error(dev, "DEBI transfer timeout."); } /* @@ -351,14 +364,57 @@ static const uint8_t s626_trimadrs[] = { 0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63 }; +enum { + s626_send_dac_wait_not_mc1_a2out, + s626_send_dac_wait_ssr_af2_out, + s626_send_dac_wait_fb_buffer2_msb_00, + s626_send_dac_wait_fb_buffer2_msb_ff +}; + +static int s626_send_dac_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct s626_private *devpriv = dev->private; + unsigned int status; + + switch (context) { + case s626_send_dac_wait_not_mc1_a2out: + status = readl(devpriv->mmio + S626_P_MC1); + if (!(status & S626_MC1_A2OUT)) + return 0; + break; + case s626_send_dac_wait_ssr_af2_out: + status = readl(devpriv->mmio + S626_P_SSR); + if (status & S626_SSR_AF2_OUT) + return 0; + break; + case s626_send_dac_wait_fb_buffer2_msb_00: + status = readl(devpriv->mmio + S626_P_FB_BUFFER2); + if (!(status & 0xff000000)) + return 0; + break; + case s626_send_dac_wait_fb_buffer2_msb_ff: + status = readl(devpriv->mmio + S626_P_FB_BUFFER2); + if (status & 0xff000000) + return 0; + break; + default: + return -EINVAL; + } + return -EBUSY; +} + /* * Private helper function: Transmit serial data to DAC via Audio * channel 2. Assumes: (1) TSL2 slot records initialized, and (2) * dacpol contains valid target image. */ -static void s626_send_dac(struct comedi_device *dev, uint32_t val) +static int s626_send_dac(struct comedi_device *dev, uint32_t val) { struct s626_private *devpriv = dev->private; + int ret; /* START THE SERIAL CLOCK RUNNING ------------- */ @@ -404,8 +460,12 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val) * Done by polling the DMAC enable flag; this flag is automatically * cleared when the transfer has finished. */ - while (readl(devpriv->mmio + S626_P_MC1) & S626_MC1_A2OUT) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_not_mc1_a2out); + if (ret) { + comedi_error(dev, "DMA transfer timeout."); + return ret; + } /* START THE OUTPUT STREAM TO THE TARGET DAC -------------------- */ @@ -425,8 +485,12 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val) * finished transferring the DAC's data DWORD from the output FIFO * to the output buffer register. */ - while (!(readl(devpriv->mmio + S626_P_SSR) & S626_SSR_AF2_OUT)) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_ssr_af2_out); + if (ret) { + comedi_error(dev, "TSL timeout waiting for slot 1 to execute."); + return ret; + } /* * Set up to trap execution at slot 0 when the TSL sequencer cycles @@ -466,8 +530,13 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val) * from 0xFF to 0x00, which slot 0 causes to happen by shifting * out/in on SD2 the 0x00 that is always referenced by slot 5. */ - while (readl(devpriv->mmio + S626_P_FB_BUFFER2) & 0xff000000) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_fb_buffer2_msb_00); + if (ret) { + comedi_error(dev, + "TSL timeout waiting for slot 0 to execute."); + return ret; + } } /* * Either (1) we were too late setting the slot 0 trap; the TSL @@ -486,14 +555,19 @@ static void s626_send_dac(struct comedi_device *dev, uint32_t val) * the next DAC write. This is detected when FB_BUFFER2 MSB changes * from 0x00 to 0xFF. */ - while (!(readl(devpriv->mmio + S626_P_FB_BUFFER2) & 0xff000000)) - ; + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_fb_buffer2_msb_ff); + if (ret) { + comedi_error(dev, "TSL timeout waiting for slot 0 to execute."); + return ret; + } + return 0; } /* * Private helper function: Write setpoint to an application DAC channel. */ -static void s626_set_dac(struct comedi_device *dev, uint16_t chan, +static int s626_set_dac(struct comedi_device *dev, uint16_t chan, int16_t dacdata) { struct s626_private *devpriv = dev->private; @@ -556,10 +630,10 @@ static void s626_set_dac(struct comedi_device *dev, uint16_t chan, val |= ((uint32_t)(chan & 1) << 15); /* Address the DAC channel * within the device. */ val |= (uint32_t)dacdata; /* Include DAC setpoint data. */ - s626_send_dac(dev, val); + return s626_send_dac(dev, val); } -static void s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan, +static int s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan, uint8_t dac_data) { struct s626_private *devpriv = dev->private; @@ -606,17 +680,22 @@ static void s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan, * Address the DAC channel within the trimdac device. * Include DAC setpoint data. */ - s626_send_dac(dev, (chan << 8) | dac_data); + return s626_send_dac(dev, (chan << 8) | dac_data); } -static void s626_load_trim_dacs(struct comedi_device *dev) +static int s626_load_trim_dacs(struct comedi_device *dev) { uint8_t i; + int ret; /* Copy TrimDac setpoint values from EEPROM to TrimDacs. */ - for (i = 0; i < ARRAY_SIZE(s626_trimchan); i++) - s626_write_trim_dac(dev, i, + for (i = 0; i < ARRAY_SIZE(s626_trimchan); i++) { + ret = s626_write_trim_dac(dev, i, s626_i2c_read(dev, s626_trimadrs[i])); + if (ret) + return ret; + } + return 0; } /* ****** COUNTER FUNCTIONS ******* */ @@ -1846,6 +1925,20 @@ static int s626_ai_rinsn(struct comedi_device *dev, } #endif +static int s626_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct s626_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->mmio + S626_P_PSR); + if (status & S626_PSR_GPIO2) + return 0; + return -EBUSY; +} + static int s626_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -1856,6 +1949,7 @@ static int s626_ai_insn_read(struct comedi_device *dev, uint16_t adc_spec = 0; uint32_t gpio_image; uint32_t tmp; + int ret; int n; /* @@ -1897,8 +1991,9 @@ static int s626_ai_insn_read(struct comedi_device *dev, */ /* Wait for ADC done */ - while (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_GPIO2)) - ; + ret = comedi_timeout(dev, s, insn, s626_ai_eoc, 0); + if (ret) + return ret; /* Fetch ADC data */ if (n != 0) { @@ -2299,6 +2394,7 @@ static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, { struct s626_private *devpriv = dev->private; int i; + int ret; uint16_t chan = CR_CHAN(insn->chanspec); int16_t dacdata; @@ -2307,7 +2403,9 @@ static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[i]; dacdata -= (0x1fff); - s626_set_dac(dev, chan, dacdata); + ret = s626_set_dac(dev, chan, dacdata); + if (ret) + return ret; } return i; @@ -2543,12 +2641,13 @@ static int s626_allocate_dma_buffers(struct comedi_device *dev) return 0; } -static void s626_initialize(struct comedi_device *dev) +static int s626_initialize(struct comedi_device *dev) { struct s626_private *devpriv = dev->private; dma_addr_t phys_buf; uint16_t chan; int i; + int ret; /* Enable DEBI and audio pins, enable I2C interface */ s626_mc_enable(dev, S626_MC1_DEBI | S626_MC1_AUDIO | S626_MC1_I2C, @@ -2749,7 +2848,9 @@ static void s626_initialize(struct comedi_device *dev) * sometimes causes the first few TrimDAC writes to malfunction. */ s626_load_trim_dacs(dev); - s626_load_trim_dacs(dev); + ret = s626_load_trim_dacs(dev); + if (ret) + return ret; /* * Manually init all gate array hardware in case this is a soft @@ -2763,8 +2864,11 @@ static void s626_initialize(struct comedi_device *dev) * Init all DAC outputs to 0V and init all DAC setpoint and * polarity images. */ - for (chan = 0; chan < S626_DAC_CHANNELS; chan++) - s626_set_dac(dev, chan, 0); + for (chan = 0; chan < S626_DAC_CHANNELS; chan++) { + ret = s626_set_dac(dev, chan, 0); + if (ret) + return ret; + } /* Init counters */ s626_counters_init(dev); @@ -2780,6 +2884,8 @@ static void s626_initialize(struct comedi_device *dev) /* Initialize the digital I/O subsystem */ s626_dio_init(dev); + + return 0; } static int s626_auto_attach(struct comedi_device *dev, @@ -2900,9 +3006,9 @@ static int s626_auto_attach(struct comedi_device *dev, s->insn_read = s626_enc_insn_read; s->insn_write = s626_enc_insn_write; - s626_initialize(dev); - - dev_info(dev->class_dev, "%s attached\n", dev->board_name); + ret = s626_initialize(dev); + if (ret) + return ret; return 0; } diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c index 77e2059ff62e..39008cf30ecb 100644 --- a/drivers/staging/comedi/drivers/skel.c +++ b/drivers/staging/comedi/drivers/skel.c @@ -141,6 +141,29 @@ static int skel_ns_to_timer(unsigned int *ns, int round) return *ns; } +/* + * This function doesn't require a particular form, this is just + * what happens to be used in some of the drivers. The comedi_timeout() + * helper uses this callback to check for the end-of-conversion while + * waiting for up to 1 second. This function should return 0 when the + * conversion is finished and -EBUSY to keep waiting. Any other errno + * will terminate comedi_timeout() and return that errno to the caller. + * If the timeout occurs, comedi_timeout() will return -ETIMEDOUT. + */ +static int skel_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + /* status = inb(dev->iobase + SKEL_STATUS); */ + status = 1; + if (status) + return 0; + return -EBUSY; +} + /* * "instructions" read/write data in "one-shot" or "software-triggered" * mode. @@ -149,9 +172,9 @@ static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { const struct skel_board *thisboard = comedi_board(dev); - int n, i; + int n; unsigned int d; - unsigned int status; + int ret; /* a typical programming sequence */ @@ -165,18 +188,10 @@ static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* trigger conversion */ /* outw(0,dev->iobase + SKEL_CONVERT); */ -#define TIMEOUT 100 /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = 1; - /* status = inb(dev->iobase + SKEL_STATUS); */ - if (status) - break; - } - if (i == TIMEOUT) { - dev_warn(dev->class_dev, "ai timeout\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, skel_ai_eoc, 0); + if (ret) + return ret; /* read data */ /* d = inw(dev->iobase + SKEL_AI_DATA); */ @@ -456,8 +471,6 @@ static int skel_common_attach(struct comedi_device *dev) s->type = COMEDI_SUBD_UNUSED; } - dev_info(dev->class_dev, "skel: attached\n"); - return 0; } diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c index df22a78d2b7e..848c30801580 100644 --- a/drivers/staging/comedi/drivers/ssv_dnp.c +++ b/drivers/staging/comedi/drivers/ssv_dnp.c @@ -161,8 +161,7 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) outb(PCMR, CSCIR); outb((inb(CSCDR) & 0xAA), CSCDR); - dev_info(dev->class_dev, "%s: attached\n", dev->board_name); - return 1; + return 0; } static void dnp_detach(struct comedi_device *dev) diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index 5f85c55c1109..d6fae11ee4e0 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -372,7 +372,7 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT | TRIG_INT); err |= cfc_check_trigger_src(&cmd->scan_begin_src, - TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); + TRIG_FOLLOW | TRIG_EXT); err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); @@ -424,9 +424,6 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, err |= cfc_check_trigger_arg_is(&cmd->convert_arg, tmp); } - if (cmd->scan_begin_src == TRIG_TIMER) - err |= -EINVAL; - /* stop source */ switch (cmd->stop_src) { case TRIG_COUNT: @@ -514,36 +511,28 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, */ devpriv->ignore = PACKETS_TO_IGNORE; - if (cmd->chanlist_len > 0) { - gain = CR_RANGE(cmd->chanlist[0]); - for (i = 0; i < cmd->chanlist_len; ++i) { - chan = CR_CHAN(cmd->chanlist[i]); - if (chan != i) { - dev_err(dev->class_dev, - "channels are not consecutive\n"); - up(&devpriv->sem); - return -EINVAL; - } - if ((gain != CR_RANGE(cmd->chanlist[i])) - && (cmd->chanlist_len > 3)) { - dev_err(dev->class_dev, - "gain must be the same for all channels\n"); - up(&devpriv->sem); - return -EINVAL; - } - if (i >= NUMCHANNELS) { - dev_err(dev->class_dev, "chanlist too long\n"); - break; - } + gain = CR_RANGE(cmd->chanlist[0]); + for (i = 0; i < cmd->chanlist_len; ++i) { + chan = CR_CHAN(cmd->chanlist[i]); + if (chan != i) { + dev_err(dev->class_dev, + "channels are not consecutive\n"); + up(&devpriv->sem); + return -EINVAL; + } + if ((gain != CR_RANGE(cmd->chanlist[i])) + && (cmd->chanlist_len > 3)) { + dev_err(dev->class_dev, + "gain must be the same for all channels\n"); + up(&devpriv->sem); + return -EINVAL; + } + if (i >= NUMCHANNELS) { + dev_err(dev->class_dev, "chanlist too long\n"); + break; } } steps = 0; - if (cmd->scan_begin_src == TRIG_TIMER) { - dev_err(dev->class_dev, - "scan_begin_src==TRIG_TIMER not valid\n"); - up(&devpriv->sem); - return -EINVAL; - } if (cmd->convert_src == TRIG_TIMER) steps = (cmd->convert_arg * 30) / 1000; diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c index 7dc5a18e69d4..8777f958c041 100644 --- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c +++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c @@ -41,7 +41,8 @@ struct comedi_device *comedi_open(const char *filename) if (strncmp(filename, "/dev/comedi", 11) != 0) return NULL; - minor = simple_strtoul(filename + 11, NULL, 0); + if (kstrtouint(filename + 11, 0, &minor)) + return NULL; if (minor >= COMEDI_NUM_BOARD_MINORS) return NULL; diff --git a/drivers/staging/comedi/proc.c b/drivers/staging/comedi/proc.c index da6bc5855ebc..91dea25b5724 100644 --- a/drivers/staging/comedi/proc.c +++ b/drivers/staging/comedi/proc.c @@ -1,27 +1,26 @@ /* - module/proc.c - /proc interface for comedi - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998 David A. Schleef - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ + * /proc interface for comedi + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* - This is some serious bloatware. - - Taken from Dave A.'s PCL-711 driver, 'cuz I thought it - was cool. -*/ + * This is some serious bloatware. + * + * Taken from Dave A.'s PCL-711 driver, 'cuz I thought it + * was cool. + */ #include "comedidev.h" #include "comedi_internal.h" @@ -34,11 +33,8 @@ static int comedi_read(struct seq_file *m, void *v) int devices_q = 0; struct comedi_driver *driv; - seq_printf(m, - "comedi version " COMEDI_RELEASE "\n" - "format string: %s\n", - "\"%2d: %-20s %-20s %4d\", i, " - "driver_name, board_name, n_subdevices"); + seq_printf(m, "comedi version " COMEDI_RELEASE "\nformat string: %s\n", + "\"%2d: %-20s %-20s %4d\", i, driver_name, board_name, n_subdevices"); for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) { struct comedi_device *dev = comedi_dev_get_from_minor(i); diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c index 46b3da686384..b6849545b810 100644 --- a/drivers/staging/comedi/range.c +++ b/drivers/staging/comedi/range.c @@ -143,28 +143,23 @@ int comedi_check_chanlist(struct comedi_subdevice *s, int n, unsigned int chanspec; int chan, range_len, i; - if (s->range_table || s->range_table_list) { - for (i = 0; i < n; i++) { - chanspec = chanlist[i]; - chan = CR_CHAN(chanspec); - if (s->range_table) - range_len = s->range_table->length; - else if (s->range_table_list && chan < s->n_chan) - range_len = s->range_table_list[chan]->length; - else - range_len = 0; - if (chan >= s->n_chan || - CR_RANGE(chanspec) >= range_len || - aref_invalid(s, chanspec)) { - dev_warn(dev->class_dev, - "bad chanlist[%d]=0x%08x chan=%d range length=%d\n", - i, chanspec, chan, range_len); - return -EINVAL; - } + for (i = 0; i < n; i++) { + chanspec = chanlist[i]; + chan = CR_CHAN(chanspec); + if (s->range_table) + range_len = s->range_table->length; + else if (s->range_table_list && chan < s->n_chan) + range_len = s->range_table_list[chan]->length; + else + range_len = 0; + if (chan >= s->n_chan || + CR_RANGE(chanspec) >= range_len || + aref_invalid(s, chanspec)) { + dev_warn(dev->class_dev, + "bad chanlist[%d]=0x%08x chan=%d range length=%d\n", + i, chanspec, chan, range_len); + return -EINVAL; } - } else { - dev_err(dev->class_dev, "(bug) no range type list!\n"); - return -EINVAL; } return 0; } diff --git a/drivers/staging/crystalhd/bcm_70012_regs.h b/drivers/staging/crystalhd/bcm_70012_regs.h index f3ab3146cd90..da199ad8e27e 100644 --- a/drivers/staging/crystalhd/bcm_70012_regs.h +++ b/drivers/staging/crystalhd/bcm_70012_regs.h @@ -31,7 +31,8 @@ #define BRCM_SHIFT(c, r, f) c##_##r##_##f##_SHIFT #define GET_FIELD(m, c, r, f) \ - ((((m) & BRCM_MASK(c, r, f)) >> BRCM_SHIFT(c, r, f)) << BRCM_ALIGN(c, r, f)) + ((((m) & BRCM_MASK(c, r, f)) >> BRCM_SHIFT(c, r, f)) << \ + BRCM_ALIGN(c, r, f)) #define SET_FIELD(m, c, r, f, d) \ ((m) = (((m) & ~BRCM_MASK(c, r, f)) | ((((d) >> BRCM_ALIGN(c, r, f)) << \ diff --git a/drivers/staging/crystalhd/crystalhd_hw.c b/drivers/staging/crystalhd/crystalhd_hw.c index 8d0680d93684..4765d528279b 100644 --- a/drivers/staging/crystalhd/crystalhd_hw.c +++ b/drivers/staging/crystalhd/crystalhd_hw.c @@ -433,10 +433,12 @@ static void crystalhd_rx_pkt_rel_call_back(void *context, void *data) } #define crystalhd_hw_delete_ioq(adp, q) \ +do { \ if (q) { \ crystalhd_delete_dioq(adp, q); \ q = NULL; \ - } + } \ +} while (0) static void crystalhd_hw_delete_ioqs(struct crystalhd_hw *hw) { @@ -1437,7 +1439,7 @@ static bool crystalhd_rx_list0_handler(struct crystalhd_hw *hw, crystalhd_reg_wr(hw->adp, MISC1_UV_RX_ERROR_STATUS, tmp); } - return (tmp_lsts != hw->rx_list_sts[0]); + return tmp_lsts != hw->rx_list_sts[0]; } static bool crystalhd_rx_list1_handler(struct crystalhd_hw *hw, @@ -1507,7 +1509,7 @@ static bool crystalhd_rx_list1_handler(struct crystalhd_hw *hw, crystalhd_reg_wr(hw->adp, MISC1_UV_RX_ERROR_STATUS, tmp); } - return (tmp_lsts != hw->rx_list_sts[1]); + return tmp_lsts != hw->rx_list_sts[1]; } diff --git a/drivers/staging/crystalhd/crystalhd_lnx.c b/drivers/staging/crystalhd/crystalhd_lnx.c index 99eefd0291c3..20be9571990a 100644 --- a/drivers/staging/crystalhd/crystalhd_lnx.c +++ b/drivers/staging/crystalhd/crystalhd_lnx.c @@ -111,7 +111,7 @@ static void chd_dec_free_iodata(struct crystalhd_adp *adp, spin_unlock_irqrestore(&adp->lock, flags); } -static inline int crystalhd_user_data(unsigned long ud, void *dr, +static inline int crystalhd_user_data(void __user *ud, void *dr, int size, int set) { int rc; @@ -122,9 +122,9 @@ static inline int crystalhd_user_data(unsigned long ud, void *dr, } if (set) - rc = copy_to_user((void *)ud, dr, size); + rc = copy_to_user(ud, dr, size); else - rc = copy_from_user(dr, (void *)ud, size); + rc = copy_from_user(dr, ud, size); if (rc) { BCMLOG_ERR("Invalid args for command\n"); @@ -153,7 +153,8 @@ static int chd_dec_fetch_cdata(struct crystalhd_adp *adp, io->add_cdata_sz = m_sz; ua_off = ua + sizeof(io->udata); - rc = crystalhd_user_data(ua_off, io->add_cdata, io->add_cdata_sz, 0); + rc = crystalhd_user_data((void __user *)ua_off, io->add_cdata, + io->add_cdata_sz, 0); if (rc) { BCMLOG_ERR("failed to pull add_cdata sz:%x ua_off:%x\n", io->add_cdata_sz, (unsigned int)ua_off); @@ -178,7 +179,7 @@ static int chd_dec_release_cdata(struct crystalhd_adp *adp, if (io->cmd != BCM_IOC_FW_DOWNLOAD) { ua_off = ua + sizeof(io->udata); - rc = crystalhd_user_data(ua_off, io->add_cdata, + rc = crystalhd_user_data((void __user *)ua_off, io->add_cdata, io->add_cdata_sz, 1); if (rc) { BCMLOG_ERR( @@ -208,7 +209,8 @@ static int chd_dec_proc_user_data(struct crystalhd_adp *adp, return -EINVAL; } - rc = crystalhd_user_data(ua, &io->udata, sizeof(io->udata), set); + rc = crystalhd_user_data((void __user *)ua, &io->udata, + sizeof(io->udata), set); if (rc) { BCMLOG_ERR("failed to %s iodata\n", (set ? "set" : "get")); return rc; @@ -546,9 +548,10 @@ static int chd_dec_pci_probe(struct pci_dev *pdev, int rc; enum BC_STATUS sts = BC_STS_SUCCESS; - BCMLOG(BCMLOG_DBG, "PCI_INFO: Vendor:0x%04x Device:0x%04x s_vendor:0x%04x s_device: 0x%04x\n", - pdev->vendor, pdev->device, pdev->subsystem_vendor, - pdev->subsystem_device); + BCMLOG(BCMLOG_DBG, + "PCI_INFO: Vendor:0x%04x Device:0x%04x s_vendor:0x%04x s_device: 0x%04x\n", + pdev->vendor, pdev->device, pdev->subsystem_vendor, + pdev->subsystem_device); pinfo = kzalloc(sizeof(struct crystalhd_adp), GFP_KERNEL); if (!pinfo) { diff --git a/drivers/staging/crystalhd/crystalhd_lnx.h b/drivers/staging/crystalhd/crystalhd_lnx.h index 816e1cd5db62..49e1ef3a19af 100644 --- a/drivers/staging/crystalhd/crystalhd_lnx.h +++ b/drivers/staging/crystalhd/crystalhd_lnx.h @@ -58,11 +58,11 @@ struct crystalhd_adp { unsigned long pci_mem_start; uint32_t pci_mem_len; - void *addr; + void __iomem *addr; unsigned long pci_i2o_start; uint32_t pci_i2o_len; - void *i2o_addr; + void __iomem *i2o_addr; unsigned int drv_data; unsigned int dmabits; /* 32 | 64 */ diff --git a/drivers/staging/crystalhd/crystalhd_misc.c b/drivers/staging/crystalhd/crystalhd_misc.c index c3d024406337..3aabf75b7d97 100644 --- a/drivers/staging/crystalhd/crystalhd_misc.c +++ b/drivers/staging/crystalhd/crystalhd_misc.c @@ -740,7 +740,7 @@ enum BC_STATUS crystalhd_map_dio(struct crystalhd_adp *adp, void *ubuff, dio->fb_size = ubuff_sz & 0x03; if (dio->fb_size) { res = copy_from_user(dio->fb_va, - (void *)(uaddr + count - dio->fb_size), + (void __user *)(uaddr + count - dio->fb_size), dio->fb_size); if (res) { BCMLOG_ERR("failed %d to copy %u fill bytes from %p\n", diff --git a/drivers/staging/crystalhd/crystalhd_misc.h b/drivers/staging/crystalhd/crystalhd_misc.h index 77ab72a2a061..0f63827acfb4 100644 --- a/drivers/staging/crystalhd/crystalhd_misc.h +++ b/drivers/staging/crystalhd/crystalhd_misc.h @@ -225,7 +225,7 @@ do { \ #define BCMLOG_ERR(fmt, args...) \ do { \ if (g_linklog_level & BCMLOG_ERROR) \ - printk(KERN_ERR "*ERR*:%s:%d: "fmt, \ + pr_err("*ERR*:%s:%d: "fmt, \ __FILE__, __LINE__, ##args); \ } while (0) diff --git a/drivers/staging/cxt1e1/Makefile b/drivers/staging/cxt1e1/Makefile index 2f217e9daac1..b879e7b553c2 100644 --- a/drivers/staging/cxt1e1/Makefile +++ b/drivers/staging/cxt1e1/Makefile @@ -4,7 +4,6 @@ ccflags-y := -DSBE_PMCC4_ENABLE ccflags-y += -DSBE_ISR_TASKLET cxt1e1-y := \ - ossiRelease.o \ musycc.o \ pmcc4_drv.o \ comet.o \ diff --git a/drivers/staging/cxt1e1/comet.c b/drivers/staging/cxt1e1/comet.c index c4c8c0f9c959..7005ad022339 100644 --- a/drivers/staging/cxt1e1/comet.c +++ b/drivers/staging/cxt1e1/comet.c @@ -22,18 +22,20 @@ #include "comet.h" #include "comet_tables.h" -extern int cxt1e1_log_level; #define COMET_NUM_SAMPLES 24 /* Number of entries in the waveform table */ #define COMET_NUM_UNITS 5 /* Number of points per entry in table */ /* forward references */ static void SetPwrLevel(struct s_comet_reg *comet); -static void WrtRcvEqualizerTbl(ci_t *ci, struct s_comet_reg *comet, u_int32_t *table); -static void WrtXmtWaveformTbl(ci_t *ci, struct s_comet_reg *comet, u_int8_t table[COMET_NUM_SAMPLES][COMET_NUM_UNITS]); +static void WrtRcvEqualizerTbl(ci_t *ci, struct s_comet_reg *comet, + u_int32_t *table); +static void WrtXmtWaveformTbl(ci_t *ci, struct s_comet_reg *comet, + u_int8_t table[COMET_NUM_SAMPLES] + [COMET_NUM_UNITS]); -void *TWV_table[12] = { +static void *TWV_table[12] = { TWVLongHaul0DB, TWVLongHaul7_5DB, TWVLongHaul15DB, TWVLongHaul22_5DB, TWVShortHaul0, TWVShortHaul1, TWVShortHaul2, TWVShortHaul3, TWVShortHaul4, TWVShortHaul5, @@ -50,6 +52,7 @@ lbo_tbl_lkup(int t1, int lbo) { if (t1) /* default T1 waveform table */ lbo = CFG_LBO_LH0; + else /* default E1 waveform table */ lbo = CFG_LBO_E120; @@ -58,8 +61,8 @@ lbo_tbl_lkup(int t1, int lbo) { return lbo - 1; } -void init_comet(void *ci, struct s_comet_reg *comet, u_int32_t port_mode, int clockmaster, - u_int8_t moreParams) +void init_comet(void *ci, struct s_comet_reg *comet, u_int32_t port_mode, + int clockmaster, u_int8_t moreParams) { u_int8_t isT1mode; /* T1 default */ @@ -146,7 +149,9 @@ void init_comet(void *ci, struct s_comet_reg *comet, u_int32_t port_mode, int cl /* t1RBOC enable(BOC:BitOriented Code) */ pci_write_32((u_int32_t *) &comet->t1_rboc_ena, 0x00); if (isT1mode) { - /* IBCD cfg: aka Inband Code Detection ** loopback code length set to */ + /* IBCD cfg: aka Inband Code Detection ** loopback code length + * set to + */ /* 6 bit down, 5 bit up (assert) */ pci_write_32((u_int32_t *) &comet->ibcd_cfg, 0x04); /* line loopback activate pattern */ @@ -286,7 +291,9 @@ void init_comet(void *ci, struct s_comet_reg *comet, u_int32_t port_mode, int cl /* 0x30: "BRIF cfg"; 0x20 is 'CMODE', 0x03 is (bit) rate */ /* note "rate bits can only be set once after reset" */ if (clockmaster) { - /* CMODE == clockMode, 0=clock master (so all 3 others should be slave) */ + /* CMODE == clockMode, 0=clock master + * (so all 3 others should be slave) + */ /* rate = 1.544 Mb/s */ if (isT1mode) /* Comet 0 Master Mode(CMODE=0) */ @@ -398,7 +405,8 @@ void init_comet(void *ci, struct s_comet_reg *comet, u_int32_t port_mode, int cl ** Returns: Nothing */ static void -WrtXmtWaveform(ci_t *ci, struct s_comet_reg *comet, u_int32_t sample, u_int32_t unit, u_int8_t data) +WrtXmtWaveform(ci_t *ci, struct s_comet_reg *comet, u_int32_t sample, + u_int32_t unit, u_int8_t data) { u_int8_t WaveformAddr; @@ -447,7 +455,7 @@ static void WrtRcvEqualizerTbl(ci_t *ci, struct s_comet_reg *comet, u_int32_t *table) { u_int32_t ramaddr; - volatile u_int32_t value; + u_int32_t value; for (ramaddr = 0; ramaddr < 256; ramaddr++) { /*** the following lines are per Errata 7, 2.5 ***/ @@ -515,7 +523,7 @@ WrtRcvEqualizerTbl(ci_t *ci, struct s_comet_reg *comet, u_int32_t *table) static void SetPwrLevel(struct s_comet_reg *comet) { - volatile u_int32_t temp; + u_int32_t temp; /* ** Algorithm to Balance the Power Distribution of Ttip Tring @@ -557,17 +565,21 @@ SetPwrLevel(struct s_comet_reg *comet) static void SetCometOps(struct s_comet_reg *comet) { - volatile u_int8_t rd_value; + u_int8_t rd_value; if (comet == mConfig.C4Func1Base + (COMET0_OFFSET >> 2)) { /* read the BRIF Configuration */ - rd_value = (u_int8_t) pci_read_32((u_int32_t *) &comet->brif_cfg); + rd_value = (u_int8_t) pci_read_32((u_int32_t *) + &comet->brif_cfg); rd_value &= ~0x20; - pci_write_32((u_int32_t *) &comet->brif_cfg, (u_int32_t) rd_value); + pci_write_32((u_int32_t *) &comet->brif_cfg, + (u_int32_t) rd_value); /* read the BRIF Frame Pulse Configuration */ - rd_value = (u_int8_t) pci_read_32((u_int32_t *) &comet->brif_fpcfg); + rd_value = (u_int8_t) pci_read_32((u_int32_t *) + &comet->brif_fpcfg); rd_value &= ~0x20; - pci_write_32((u_int32_t *) &comet->brif_fpcfg, (u_int8_t) rd_value); + pci_write_32((u_int32_t *) &comet->brif_fpcfg, + (u_int8_t) rd_value); } else { /* read the BRIF Configuration */ rd_value = (u_int8_t) pci_read_32((u_int32_t *) &comet->brif_cfg); diff --git a/drivers/staging/cxt1e1/comet_tables.c b/drivers/staging/cxt1e1/comet_tables.c index 84931117da35..e96665ea3662 100644 --- a/drivers/staging/cxt1e1/comet_tables.c +++ b/drivers/staging/cxt1e1/comet_tables.c @@ -19,6 +19,7 @@ */ #include +#include "comet_tables.h" /***************************************************************************** * diff --git a/drivers/staging/cxt1e1/functions.c b/drivers/staging/cxt1e1/functions.c index 95218e283966..ee9d39bbd251 100644 --- a/drivers/staging/cxt1e1/functions.c +++ b/drivers/staging/cxt1e1/functions.c @@ -25,7 +25,8 @@ #include "pmcc4.h" #if defined(CONFIG_SBE_HDLC_V7) || defined(CONFIG_SBE_WAN256T3_HDLC_V7) || \ - defined(CONFIG_SBE_HDLC_V7_MODULE) || defined(CONFIG_SBE_WAN256T3_HDLC_V7_MODULE) +defined(CONFIG_SBE_HDLC_V7_MODULE) || \ +defined(CONFIG_SBE_WAN256T3_HDLC_V7_MODULE) #define _v7_hdlc_ 1 #else #define _v7_hdlc_ 0 @@ -33,9 +34,9 @@ #if _v7_hdlc_ #define V7(x) (x ## _v7) -extern int hdlc_netif_rx_v7 (hdlc_device *, struct sk_buff *); -extern int register_hdlc_device_v7 (hdlc_device *); -extern int unregister_hdlc_device_v7 (hdlc_device *); +extern int hdlc_netif_rx_v7(hdlc_device *, struct sk_buff *); +extern int register_hdlc_device_v7(hdlc_device *); +extern int unregister_hdlc_device_v7(hdlc_device *); #else #define V7(x) x @@ -47,55 +48,54 @@ static int dummy = 0; #endif -extern int cxt1e1_log_level; extern int drvr_state; #if 1 u_int32_t -pci_read_32 (u_int32_t *p) +pci_read_32(u_int32_t *p) { #ifdef FLOW_DEBUG - u_int32_t v; + u_int32_t v; - FLUSH_PCI_READ (); - v = le32_to_cpu (*p); - if (cxt1e1_log_level >= LOG_DEBUG) - pr_info("pci_read : %x = %x\n", (u_int32_t) p, v); - return v; + FLUSH_PCI_READ(); + v = le32_to_cpu(*p); + if (cxt1e1_log_level >= LOG_DEBUG) + pr_info("pci_read : %x = %x\n", (u_int32_t) p, v); + return v; #else - FLUSH_PCI_READ (); /* */ - return le32_to_cpu (*p); + FLUSH_PCI_READ(); /* */ + return le32_to_cpu(*p); #endif } void -pci_write_32 (u_int32_t *p, u_int32_t v) +pci_write_32(u_int32_t *p, u_int32_t v) { #ifdef FLOW_DEBUG - if (cxt1e1_log_level >= LOG_DEBUG) - pr_info("pci_write: %x = %x\n", (u_int32_t) p, v); + if (cxt1e1_log_level >= LOG_DEBUG) + pr_info("pci_write: %x = %x\n", (u_int32_t) p, v); #endif - *p = cpu_to_le32 (v); - FLUSH_PCI_WRITE (); /* This routine is called from routines - * which do multiple register writes - * which themselves need flushing between - * writes in order to guarantee write - * ordering. It is less code-cumbersome - * to flush here-in then to investigate - * and code the many other register - * writing routines. */ + *p = cpu_to_le32 (v); + FLUSH_PCI_WRITE(); /* This routine is called from routines + * which do multiple register writes + * which themselves need flushing between + * writes in order to guarantee write + * ordering. It is less code-cumbersome + * to flush here-in then to investigate + * and code the many other register + * writing routines. */ } #endif void -pci_flush_write (ci_t *ci) +pci_flush_write(ci_t *ci) { - volatile u_int32_t v; + volatile u_int32_t v; /* issue a PCI read to flush PCI write thru bridge */ - v = *(u_int32_t *) &ci->reg->glcd; /* any address would do */ + v = *(u_int32_t *) &ci->reg->glcd; /* any address would do */ /* * return nothing, this just reads PCI bridge interface to flush @@ -105,55 +105,53 @@ pci_flush_write (ci_t *ci) static void -watchdog_func (unsigned long arg) +watchdog_func(unsigned long arg) { - struct watchdog *wd = (void *) arg; + struct watchdog *wd = (void *) arg; - if (drvr_state != SBE_DRVR_AVAILABLE) - { - if (cxt1e1_log_level >= LOG_MONITOR) - pr_warning("%s: drvr not available (%x)\n", __func__, drvr_state); - return; - } - schedule_work (&wd->work); - mod_timer (&wd->h, jiffies + wd->ticks); + if (drvr_state != SBE_DRVR_AVAILABLE) { + if (cxt1e1_log_level >= LOG_MONITOR) + pr_warning("%s: drvr not available (%x)\n", + __func__, drvr_state); + return; + } + schedule_work(&wd->work); + mod_timer(&wd->h, jiffies + wd->ticks); } -int OS_init_watchdog(struct watchdog *wdp, void (*f) (void *), void *c, int usec) +int OS_init_watchdog(struct watchdog *wdp, void (*f) (void *), + void *c, int usec) { - wdp->func = f; - wdp->softc = c; - wdp->ticks = (HZ) * (usec / 1000) / 1000; - INIT_WORK(&wdp->work, (void *)f); - init_timer (&wdp->h); - { - ci_t *ci = (ci_t *) c; + wdp->func = f; + wdp->softc = c; + wdp->ticks = (HZ) * (usec / 1000) / 1000; + INIT_WORK(&wdp->work, (void *)f); + init_timer(&wdp->h); + { + ci_t *ci = (ci_t *) c; - wdp->h.data = (unsigned long) &ci->wd; - } - wdp->h.function = watchdog_func; - return 0; + wdp->h.data = (unsigned long) &ci->wd; + } + wdp->h.function = watchdog_func; + return 0; } void -OS_uwait (int usec, char *description) +OS_uwait(int usec, char *description) { - int tmp; + int tmp; - if (usec >= 1000) - { - mdelay (usec / 1000); - /* now delay residual */ - tmp = (usec / 1000) * 1000; /* round */ - tmp = usec - tmp; /* residual */ - if (tmp) - { /* wait on residual */ - udelay (tmp); - } - } else - { - udelay (usec); - } + if (usec >= 1000) { + mdelay(usec / 1000); + /* now delay residual */ + tmp = (usec / 1000) * 1000; /* round */ + tmp = usec - tmp; /* residual */ + if (tmp) { /* wait on residual */ + udelay(tmp); + } + } else { + udelay(usec); + } } /* dummy short delay routine called as a subroutine so that compiler @@ -161,96 +159,95 @@ OS_uwait (int usec, char *description) */ void -OS_uwait_dummy (void) +OS_uwait_dummy(void) { #ifndef USE_MAX_INT_DELAY - dummy++; + dummy++; #else - udelay (1); + udelay(1); #endif } void -OS_sem_init (void *sem, int state) +OS_sem_init(void *sem, int state) { - switch (state) - { - case SEM_TAKEN: - sema_init((struct semaphore *) sem, 0); - break; - case SEM_AVAILABLE: + switch (state) { + case SEM_TAKEN: + sema_init((struct semaphore *) sem, 0); + break; + case SEM_AVAILABLE: sema_init((struct semaphore *) sem, 1); - break; - default: /* otherwise, set sem.count to state's - * value */ - sema_init (sem, state); - break; - } + break; + default: /* otherwise, set sem.count to state's + * value */ + sema_init(sem, state); + break; + } } int -sd_line_is_ok (void *user) +sd_line_is_ok(void *user) { - struct net_device *ndev = (struct net_device *) user; + struct net_device *ndev = (struct net_device *) user; - return netif_carrier_ok (ndev); + return netif_carrier_ok(ndev); } void -sd_line_is_up (void *user) +sd_line_is_up(void *user) { - struct net_device *ndev = (struct net_device *) user; + struct net_device *ndev = (struct net_device *) user; - netif_carrier_on (ndev); - return; + netif_carrier_on(ndev); + return; } void -sd_line_is_down (void *user) +sd_line_is_down(void *user) { - struct net_device *ndev = (struct net_device *) user; + struct net_device *ndev = (struct net_device *) user; - netif_carrier_off (ndev); - return; + netif_carrier_off(ndev); + return; } void -sd_disable_xmit (void *user) +sd_disable_xmit(void *user) { - struct net_device *dev = (struct net_device *) user; + struct net_device *dev = (struct net_device *) user; - netif_stop_queue (dev); - return; + netif_stop_queue(dev); + return; } void -sd_enable_xmit (void *user) +sd_enable_xmit(void *user) { - struct net_device *dev = (struct net_device *) user; + struct net_device *dev = (struct net_device *) user; - netif_wake_queue (dev); - return; + netif_wake_queue(dev); + return; } int -sd_queue_stopped (void *user) +sd_queue_stopped(void *user) { - struct net_device *ndev = (struct net_device *) user; + struct net_device *ndev = (struct net_device *) user; - return netif_queue_stopped (ndev); + return netif_queue_stopped(ndev); } void sd_recv_consume(void *token, size_t len, void *user) { - struct net_device *ndev = user; - struct sk_buff *skb = token; + struct net_device *ndev = user; + struct sk_buff *skb = token; - skb->dev = ndev; - skb_put (skb, len); - skb->protocol = hdlc_type_trans(skb, ndev); - netif_rx(skb); + skb->dev = ndev; + skb_put(skb, len); + skb->protocol = hdlc_type_trans(skb, ndev); + netif_rx(skb); } @@ -263,86 +260,76 @@ void sd_recv_consume(void *token, size_t len, void *user) extern ci_t *CI; /* dummy pointer to board ZERO's data */ void -VMETRO_TRACE (void *x) +VMETRO_TRIGGER(ci_t *ci, int x) { - u_int32_t y = (u_int32_t) x; + struct s_comet_reg *comet; + volatile u_int32_t data; - pci_write_32 ((u_int32_t *) &CI->cpldbase->leds, y); -} + comet = ci->port[0].cometbase; /* default to COMET # 0 */ - -void -VMETRO_TRIGGER (ci_t *ci, int x) -{ - struct s_comet_reg *comet; - volatile u_int32_t data; - - comet = ci->port[0].cometbase; /* default to COMET # 0 */ - - switch (x) - { - default: - case 0: - data = pci_read_32 ((u_int32_t *) &comet->__res24); /* 0x90 */ - break; - case 1: - data = pci_read_32 ((u_int32_t *) &comet->__res25); /* 0x94 */ - break; - case 2: - data = pci_read_32 ((u_int32_t *) &comet->__res26); /* 0x98 */ - break; - case 3: - data = pci_read_32 ((u_int32_t *) &comet->__res27); /* 0x9C */ - break; - case 4: - data = pci_read_32 ((u_int32_t *) &comet->__res88); /* 0x220 */ - break; - case 5: - data = pci_read_32 ((u_int32_t *) &comet->__res89); /* 0x224 */ - break; - case 6: - data = pci_read_32 ((u_int32_t *) &comet->__res8A); /* 0x228 */ - break; - case 7: - data = pci_read_32 ((u_int32_t *) &comet->__res8B); /* 0x22C */ - break; - case 8: - data = pci_read_32 ((u_int32_t *) &comet->__resA0); /* 0x280 */ - break; - case 9: - data = pci_read_32 ((u_int32_t *) &comet->__resA1); /* 0x284 */ - break; - case 10: - data = pci_read_32 ((u_int32_t *) &comet->__resA2); /* 0x288 */ - break; - case 11: - data = pci_read_32 ((u_int32_t *) &comet->__resA3); /* 0x28C */ - break; - case 12: - data = pci_read_32 ((u_int32_t *) &comet->__resA4); /* 0x290 */ - break; - case 13: - data = pci_read_32 ((u_int32_t *) &comet->__resA5); /* 0x294 */ - break; - case 14: - data = pci_read_32 ((u_int32_t *) &comet->__resA6); /* 0x298 */ - break; - case 15: - data = pci_read_32 ((u_int32_t *) &comet->__resA7); /* 0x29C */ - break; - case 16: - data = pci_read_32 ((u_int32_t *) &comet->__res74); /* 0x1D0 */ - break; - case 17: - data = pci_read_32 ((u_int32_t *) &comet->__res75); /* 0x1D4 */ - break; - case 18: - data = pci_read_32 ((u_int32_t *) &comet->__res76); /* 0x1D8 */ - break; - case 19: - data = pci_read_32 ((u_int32_t *) &comet->__res77); /* 0x1DC */ - break; - } + switch (x) { + default: + case 0: + data = pci_read_32((u_int32_t *) &comet->__res24); /* 0x90 */ + break; + case 1: + data = pci_read_32((u_int32_t *) &comet->__res25); /* 0x94 */ + break; + case 2: + data = pci_read_32((u_int32_t *) &comet->__res26); /* 0x98 */ + break; + case 3: + data = pci_read_32((u_int32_t *) &comet->__res27); /* 0x9C */ + break; + case 4: + data = pci_read_32((u_int32_t *) &comet->__res88); /* 0x220 */ + break; + case 5: + data = pci_read_32((u_int32_t *) &comet->__res89); /* 0x224 */ + break; + case 6: + data = pci_read_32((u_int32_t *) &comet->__res8A); /* 0x228 */ + break; + case 7: + data = pci_read_32((u_int32_t *) &comet->__res8B); /* 0x22C */ + break; + case 8: + data = pci_read_32((u_int32_t *) &comet->__resA0); /* 0x280 */ + break; + case 9: + data = pci_read_32((u_int32_t *) &comet->__resA1); /* 0x284 */ + break; + case 10: + data = pci_read_32((u_int32_t *) &comet->__resA2); /* 0x288 */ + break; + case 11: + data = pci_read_32((u_int32_t *) &comet->__resA3); /* 0x28C */ + break; + case 12: + data = pci_read_32((u_int32_t *) &comet->__resA4); /* 0x290 */ + break; + case 13: + data = pci_read_32((u_int32_t *) &comet->__resA5); /* 0x294 */ + break; + case 14: + data = pci_read_32((u_int32_t *) &comet->__resA6); /* 0x298 */ + break; + case 15: + data = pci_read_32((u_int32_t *) &comet->__resA7); /* 0x29C */ + break; + case 16: + data = pci_read_32((u_int32_t *) &comet->__res74); /* 0x1D0 */ + break; + case 17: + data = pci_read_32((u_int32_t *) &comet->__res75); /* 0x1D4 */ + break; + case 18: + data = pci_read_32((u_int32_t *) &comet->__res76); /* 0x1D8 */ + break; + case 19: + data = pci_read_32((u_int32_t *) &comet->__res77); /* 0x1DC */ + break; + } } diff --git a/drivers/staging/cxt1e1/hwprobe.c b/drivers/staging/cxt1e1/hwprobe.c index 02b4f8f1aca5..9b4198b1e634 100644 --- a/drivers/staging/cxt1e1/hwprobe.c +++ b/drivers/staging/cxt1e1/hwprobe.c @@ -31,360 +31,352 @@ #include "sbeproc.h" #endif -extern int cxt1e1_log_level; extern int error_flag; extern int drvr_state; /* forward references */ -void c4_stopwd (ci_t *); -struct net_device * __init c4_add_dev (hdw_info_t *, int, unsigned long, unsigned long, int, int); +void c4_stopwd(ci_t *); +struct net_device * __init c4_add_dev(hdw_info_t *, int, unsigned long, + unsigned long, int, int); struct s_hdw_info hdw_info[MAX_BOARDS]; -void __init -show_two (hdw_info_t *hi, int brdno) +void __init +show_two(hdw_info_t *hi, int brdno) { - ci_t *ci; - struct pci_dev *pdev; - char *bid; - char *bp, banner[80]; - char sn[6]; + ci_t *ci; + struct pci_dev *pdev; + char *bid; + char banner[80]; + char sn[6] = {0,}; - bp = banner; - memset (banner, 0, 80); /* clear print buffer */ + ci = (ci_t *)(netdev_priv(hi->ndev)); + bid = sbeid_get_bdname(ci); + switch (hi->promfmt) { + case PROM_FORMAT_TYPE1: + memcpy(sn, hi->mfg_info.pft1.Serial, 6); + break; + case PROM_FORMAT_TYPE2: + memcpy(sn, hi->mfg_info.pft2.Serial, 6); + break; + } - ci = (ci_t *)(netdev_priv(hi->ndev)); - bid = sbeid_get_bdname (ci); - switch (hi->promfmt) - { - case PROM_FORMAT_TYPE1: - memcpy (sn, (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); - break; - case PROM_FORMAT_TYPE2: - memcpy (sn, (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); - break; - default: - memset (sn, 0, 6); - break; - } + sprintf(banner, "%s: %s S/N %06X, MUSYCC Rev %02X", + hi->devname, bid, + ((sn[3] << 16) & 0xff0000) | + ((sn[4] << 8) & 0x00ff00) | + (sn[5] & 0x0000ff), + (u_int8_t) hi->revid[0]); - sprintf (banner, "%s: %s S/N %06X, MUSYCC Rev %02X", - hi->devname, bid, - ((sn[3] << 16) & 0xff0000) | - ((sn[4] << 8) & 0x00ff00) | - (sn[5] & 0x0000ff), - (u_int8_t) hi->revid[0]); + pr_info("%s\n", banner); - pr_info("%s\n", banner); + pdev = hi->pdev[0]; + pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n", + hi->devname, "MUSYCC", + (unsigned long) hi->addr_mapped[0], hi->addr[0], + hi->pci_busno, (u_int8_t) PCI_SLOT(pdev->devfn), + (u_int8_t) PCI_FUNC(pdev->devfn), pdev->irq); - pdev = hi->pdev[0]; - pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n", - hi->devname, "MUSYCC", - (unsigned long) hi->addr_mapped[0], hi->addr[0], - hi->pci_busno, (u_int8_t) PCI_SLOT (pdev->devfn), - (u_int8_t) PCI_FUNC (pdev->devfn), pdev->irq); - - pdev = hi->pdev[1]; - pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n", - hi->devname, "EBUS ", - (unsigned long) hi->addr_mapped[1], hi->addr[1], - hi->pci_busno, (u_int8_t) PCI_SLOT (pdev->devfn), - (u_int8_t) PCI_FUNC (pdev->devfn), pdev->irq); + pdev = hi->pdev[1]; + pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n", + hi->devname, "EBUS ", + (unsigned long) hi->addr_mapped[1], hi->addr[1], + hi->pci_busno, (u_int8_t) PCI_SLOT(pdev->devfn), + (u_int8_t) PCI_FUNC(pdev->devfn), pdev->irq); } -void __init -hdw_sn_get (hdw_info_t *hi, int brdno) +void __init +hdw_sn_get(hdw_info_t *hi, int brdno) { - /* obtain hardware EEPROM information */ - long addr; + /* obtain hardware EEPROM information */ + long addr; - addr = (long) hi->addr_mapped[1] + EEPROM_OFFSET; + addr = (long) hi->addr_mapped[1] + EEPROM_OFFSET; - /* read EEPROM with largest known format size... */ - pmc_eeprom_read_buffer (addr, 0, (char *) hi->mfg_info.data, sizeof (FLD_TYPE2)); + /* read EEPROM with largest known format size... */ + pmc_eeprom_read_buffer(addr, 0, (char *)hi->mfg_info.data, + sizeof(FLD_TYPE2)); #if 0 - { - unsigned char *ucp = (unsigned char *) &hi->mfg_info.data; + { + unsigned char *ucp = (unsigned char *) &hi->mfg_info.data; - pr_info("eeprom[00]: %02x %02x %02x %02x %02x %02x %02x %02x\n", - *(ucp + 0), *(ucp + 1), *(ucp + 2), *(ucp + 3), *(ucp + 4), *(ucp + 5), *(ucp + 6), *(ucp + 7)); - pr_info("eeprom[08]: %02x %02x %02x %02x %02x %02x %02x %02x\n", - *(ucp + 8), *(ucp + 9), *(ucp + 10), *(ucp + 11), *(ucp + 12), *(ucp + 13), *(ucp + 14), *(ucp + 15)); - pr_info("eeprom[16]: %02x %02x %02x %02x %02x %02x %02x %02x\n", - *(ucp + 16), *(ucp + 17), *(ucp + 18), *(ucp + 19), *(ucp + 20), *(ucp + 21), *(ucp + 22), *(ucp + 23)); - pr_info("eeprom[24]: %02x %02x %02x %02x %02x %02x %02x %02x\n", - *(ucp + 24), *(ucp + 25), *(ucp + 26), *(ucp + 27), *(ucp + 28), *(ucp + 29), *(ucp + 30), *(ucp + 31)); - pr_info("eeprom[32]: %02x %02x %02x %02x %02x %02x %02x %02x\n", - *(ucp + 32), *(ucp + 33), *(ucp + 34), *(ucp + 35), *(ucp + 36), *(ucp + 37), *(ucp + 38), *(ucp + 39)); - pr_info("eeprom[40]: %02x %02x %02x %02x %02x %02x %02x %02x\n", - *(ucp + 40), *(ucp + 41), *(ucp + 42), *(ucp + 43), *(ucp + 44), *(ucp + 45), *(ucp + 46), *(ucp + 47)); - } + pr_info("eeprom[00]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 0), *(ucp + 1), *(ucp + 2), *(ucp + 3), + *(ucp + 4), *(ucp + 5), *(ucp + 6), *(ucp + 7)); + pr_info("eeprom[08]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 8), *(ucp + 9), *(ucp + 10), *(ucp + 11), + *(ucp + 12), *(ucp + 13), *(ucp + 14), *(ucp + 15)); + pr_info("eeprom[16]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 16), *(ucp + 17), *(ucp + 18), *(ucp + 19), + *(ucp + 20), *(ucp + 21), *(ucp + 22), *(ucp + 23)); + pr_info("eeprom[24]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 24), *(ucp + 25), *(ucp + 26), *(ucp + 27), + *(ucp + 28), *(ucp + 29), *(ucp + 30), *(ucp + 31)); + pr_info("eeprom[32]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 32), *(ucp + 33), *(ucp + 34), *(ucp + 35), + *(ucp + 36), *(ucp + 37), *(ucp + 38), *(ucp + 39)); + pr_info("eeprom[40]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 40), *(ucp + 41), *(ucp + 42), *(ucp + 43), + *(ucp + 44), *(ucp + 45), *(ucp + 46), *(ucp + 47)); + } #endif #if 0 - pr_info("sn: %x %x %x %x %x %x\n", - hi->mfg_info.Serial[0], - hi->mfg_info.Serial[1], - hi->mfg_info.Serial[2], - hi->mfg_info.Serial[3], - hi->mfg_info.Serial[4], - hi->mfg_info.Serial[5]); + pr_info("sn: %x %x %x %x %x %x\n", + hi->mfg_info.Serial[0], + hi->mfg_info.Serial[1], + hi->mfg_info.Serial[2], + hi->mfg_info.Serial[3], + hi->mfg_info.Serial[4], + hi->mfg_info.Serial[5]); #endif - if ((hi->promfmt = pmc_verify_cksum (&hi->mfg_info.data)) == PROM_FORMAT_Unk) - { - /* bad crc, data is suspect */ - if (cxt1e1_log_level >= LOG_WARN) - pr_info("%s: EEPROM cksum error\n", hi->devname); - hi->mfg_info_sts = EEPROM_CRCERR; - } else - hi->mfg_info_sts = EEPROM_OK; + hi->promfmt = pmc_verify_cksum(&hi->mfg_info.data); + if (hi->promfmt == PROM_FORMAT_Unk) { + /* bad crc, data is suspect */ + if (cxt1e1_log_level >= LOG_WARN) + pr_info("%s: EEPROM cksum error\n", hi->devname); + hi->mfg_info_sts = EEPROM_CRCERR; + } else + hi->mfg_info_sts = EEPROM_OK; } -void __init -prep_hdw_info (void) + void __init +prep_hdw_info(void) { - hdw_info_t *hi; - int i; + hdw_info_t *hi; + int i; - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) - { - hi->pci_busno = 0xff; - hi->pci_slot = 0xff; - hi->pci_pin[0] = 0; - hi->pci_pin[1] = 0; - hi->ndev = NULL; - hi->addr[0] = 0L; - hi->addr[1] = 0L; - hi->addr_mapped[0] = 0L; - hi->addr_mapped[1] = 0L; - } + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + hi->pci_busno = 0xff; + hi->pci_slot = 0xff; + hi->pci_pin[0] = 0; + hi->pci_pin[1] = 0; + hi->ndev = NULL; + hi->addr[0] = 0L; + hi->addr[1] = 0L; + hi->addr_mapped[0] = 0L; + hi->addr_mapped[1] = 0L; + } } void -cleanup_ioremap (void) +cleanup_ioremap(void) { - hdw_info_t *hi; - int i; + hdw_info_t *hi; + int i; - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) - { - if (hi->pci_slot == 0xff) - break; - if (hi->addr_mapped[0]) - { - iounmap ((void *) (hi->addr_mapped[0])); - release_mem_region ((long) hi->addr[0], hi->len[0]); - hi->addr_mapped[0] = 0; - } - if (hi->addr_mapped[1]) - { - iounmap ((void *) (hi->addr_mapped[1])); - release_mem_region ((long) hi->addr[1], hi->len[1]); - hi->addr_mapped[1] = 0; - } - } + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->pci_slot == 0xff) + break; + if (hi->addr_mapped[0]) { + iounmap((void *)(hi->addr_mapped[0])); + release_mem_region((long) hi->addr[0], hi->len[0]); + hi->addr_mapped[0] = 0; + } + if (hi->addr_mapped[1]) { + iounmap((void *)(hi->addr_mapped[1])); + release_mem_region((long) hi->addr[1], hi->len[1]); + hi->addr_mapped[1] = 0; + } + } } void -cleanup_devs (void) +cleanup_devs(void) { - hdw_info_t *hi; - int i; + hdw_info_t *hi; + int i; - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) - { - if (hi->pci_slot == 0xff || !hi->ndev) - break; - c4_stopwd(netdev_priv(hi->ndev)); + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->pci_slot == 0xff || !hi->ndev) + break; + c4_stopwd(netdev_priv(hi->ndev)); #ifdef CONFIG_PROC_FS - sbecom_proc_brd_cleanup(netdev_priv(hi->ndev)); + sbecom_proc_brd_cleanup(netdev_priv(hi->ndev)); #endif - unregister_netdev (hi->ndev); - free_irq (hi->pdev[0]->irq, hi->ndev); + unregister_netdev(hi->ndev); + free_irq(hi->pdev[0]->irq, hi->ndev); #ifdef CONFIG_SBE_PMCC4_NCOMM - free_irq (hi->pdev[1]->irq, hi->ndev); + free_irq(hi->pdev[1]->irq, hi->ndev); #endif - OS_kfree (hi->ndev); - } + OS_kfree(hi->ndev); + } } static int __init -c4_hdw_init (struct pci_dev *pdev, int found) +c4_hdw_init(struct pci_dev *pdev, int found) { - hdw_info_t *hi; - int i; - int fun, slot; - unsigned char busno = 0xff; + hdw_info_t *hi; + int i; + int fun, slot; + unsigned char busno = 0xff; - /* our MUSYCC chip supports two functions, 0 & 1 */ - if ((fun = PCI_FUNC (pdev->devfn)) > 1) - { - pr_warning("unexpected devfun: 0x%x\n", pdev->devfn); - return 0; - } - if (pdev->bus) /* obtain bus number */ - busno = pdev->bus->number; - else - busno = 0; /* default for system PCI inconsistency */ - slot = pdev->devfn & ~0x07; + /* our MUSYCC chip supports two functions, 0 & 1 */ + fun = PCI_FUNC(pdev->devfn); + if (fun > 1) { + pr_warning("unexpected devfun: 0x%x\n", pdev->devfn); + return 0; + } - /* - * Functions 0 & 1 for a given board (identified by same bus(busno) and - * slot(slot)) are placed into the same 'hardware' structure. The first - * part of the board's functionality will be placed into an unpopulated - * element, identified by "slot==(0xff)". The second part of a board's - * functionality will match the previously loaded slot/busno. - */ - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) - { - /* - * match with board's first found interface, otherwise this is first - * found - */ - if ((hi->pci_slot == 0xff) || /* new board */ - ((hi->pci_slot == slot) && (hi->bus == pdev->bus))) - break; /* found for-loop exit */ - } - if (i == MAX_BOARDS) /* no match in above loop means MAX - * exceeded */ - { - pr_warning("exceeded number of allowed devices (>%d)?\n", MAX_BOARDS); - return 0; - } - if (pdev->bus) - hi->pci_busno = pdev->bus->number; - else - hi->pci_busno = 0; /* default for system PCI inconsistency */ - hi->pci_slot = slot; - pci_read_config_byte (pdev, PCI_INTERRUPT_PIN, &hi->pci_pin[fun]); - pci_read_config_byte (pdev, PCI_REVISION_ID, &hi->revid[fun]); - hi->bus = pdev->bus; - hi->addr[fun] = pci_resource_start (pdev, 0); - hi->len[fun] = pci_resource_end (pdev, 0) - hi->addr[fun] + 1; - hi->pdev[fun] = pdev; + /* obtain bus number */ + if (pdev->bus) + busno = pdev->bus->number; + else + busno = 0; /* default for system PCI inconsistency */ + slot = pdev->devfn & ~0x07; - { - /* - * create device name from module name, plus add the appropriate - * board number - */ - char *cp = hi->devname; + /* + * Functions 0 & 1 for a given board (identified by same bus(busno) and + * slot(slot)) are placed into the same 'hardware' structure. The first + * part of the board's functionality will be placed into an unpopulated + * element, identified by "slot==(0xff)". The second part of a board's + * functionality will match the previously loaded slot/busno. + */ + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + /* + * match with board's first found interface, otherwise this is + * fisrt found + */ + if ((hi->pci_slot == 0xff) || /* new board */ + ((hi->pci_slot == slot) && (hi->bus == pdev->bus))) + break; /* found for-loop exit */ + } - strcpy (cp, KBUILD_MODNAME); - cp += strlen (cp); /* reposition */ - *cp++ = '-'; - *cp++ = '0' + (found / 2); /* there are two found interfaces per - * board */ - *cp = 0; /* termination */ - } + /* no match in above loop means MAX exceeded */ + if (i == MAX_BOARDS) { + pr_warning("exceeded number of allowed devices (>%d)?\n", + MAX_BOARDS); + return 0; + } - return 1; + if (pdev->bus) + hi->pci_busno = pdev->bus->number; + else + hi->pci_busno = 0; /* default for system PCI inconsistency */ + + hi->pci_slot = slot; + pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &hi->pci_pin[fun]); + pci_read_config_byte(pdev, PCI_REVISION_ID, &hi->revid[fun]); + hi->bus = pdev->bus; + hi->addr[fun] = pci_resource_start(pdev, 0); + hi->len[fun] = pci_resource_end(pdev, 0) - hi->addr[fun] + 1; + hi->pdev[fun] = pdev; + + { + /* + * create device name from module name, plus add the appropriate + * board number + */ + char *cp = hi->devname; + + strcpy(cp, KBUILD_MODNAME); + cp += strlen(cp); /* reposition */ + *cp++ = '-'; + *cp++ = '0' + (found / 2); /* there are two found interfaces per + * board */ + *cp = 0; /* termination */ + } + + return 1; } - -status_t __init -c4hw_attach_all (void) +status_t __init +c4hw_attach_all(void) { - hdw_info_t *hi; - struct pci_dev *pdev = NULL; - int found = 0, i, j; + hdw_info_t *hi; + struct pci_dev *pdev = NULL; + int found = 0, i, j; - error_flag = 0; - prep_hdw_info (); - /*** scan PCI bus for all possible boards */ - while ((pdev = pci_get_device (PCI_VENDOR_ID_CONEXANT, - PCI_DEVICE_ID_CN8474, - pdev))) - { - if (c4_hdw_init (pdev, found)) - found++; - } - if (!found) - { - pr_warning("No boards found\n"); - return -ENODEV; - } - /* sanity check for consistent hardware found */ - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) - { - if (hi->pci_slot != 0xff && (!hi->addr[0] || !hi->addr[1])) - { - pr_warning("%s: something very wrong with pci_get_device\n", - hi->devname); - return -EIO; - } - } - /* bring board's memory regions on/line */ - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) - { - if (hi->pci_slot == 0xff) - break; - for (j = 0; j < 2; j++) - { - if (!request_mem_region (hi->addr[j], hi->len[j], hi->devname)) - { - pr_warning("%s: memory in use, addr=0x%lx, len=0x%lx ?\n", - hi->devname, hi->addr[j], hi->len[j]); - cleanup_ioremap (); - return -ENOMEM; - } - hi->addr_mapped[j] = (unsigned long) ioremap (hi->addr[j], hi->len[j]); - if (!hi->addr_mapped[j]) - { - pr_warning("%s: ioremap fails, addr=0x%lx, len=0x%lx ?\n", - hi->devname, hi->addr[j], hi->len[j]); - cleanup_ioremap (); - return -ENOMEM; - } + error_flag = 0; + prep_hdw_info(); + /*** scan PCI bus for all possible boards */ + while ((pdev = pci_get_device(PCI_VENDOR_ID_CONEXANT, + PCI_DEVICE_ID_CN8474, + pdev))) { + if (c4_hdw_init(pdev, found)) + found++; + } + + if (!found) { + pr_warning("No boards found\n"); + return -ENODEV; + } + + /* sanity check for consistent hardware found */ + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->pci_slot != 0xff && (!hi->addr[0] || !hi->addr[1])) { + pr_warning("%s: something very wrong with pci_get_device\n", + hi->devname); + return -EIO; + } + } + /* bring board's memory regions on/line */ + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->pci_slot == 0xff) + break; + for (j = 0; j < 2; j++) { + if (!request_mem_region(hi->addr[j], hi->len[j], hi->devname)) { + pr_warning("%s: memory in use, addr=0x%lx, len=0x%lx ?\n", + hi->devname, hi->addr[j], hi->len[j]); + cleanup_ioremap(); + return -ENOMEM; + } + + hi->addr_mapped[j] = (unsigned long)ioremap(hi->addr[j], hi->len[j]); + if (!hi->addr_mapped[j]) { + pr_warning("%s: ioremap fails, addr=0x%lx, len=0x%lx ?\n", + hi->devname, hi->addr[j], hi->len[j]); + cleanup_ioremap(); + return -ENOMEM; + } #ifdef SBE_MAP_DEBUG - pr_warning("%s: io remapped from phys %x to virt %x\n", - hi->devname, (u_int32_t) hi->addr[j], (u_int32_t) hi->addr_mapped[j]); + pr_warning("%s: io remapped from phys %x to virt %x\n", + hi->devname, (u_int32_t) hi->addr[j], + (u_int32_t) hi->addr_mapped[j]); #endif - } - } + } + } - drvr_state = SBE_DRVR_AVAILABLE; + drvr_state = SBE_DRVR_AVAILABLE; - /* Have now memory mapped all boards. Now allow board's access to system */ - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) - { - if (hi->pci_slot == 0xff) - break; - if (pci_enable_device (hi->pdev[0]) || - pci_enable_device (hi->pdev[1])) - { - drvr_state = SBE_DRVR_DOWN; - pr_warning("%s: failed to enable card %d slot %d\n", - hi->devname, i, hi->pci_slot); - cleanup_devs (); - cleanup_ioremap (); - return -EIO; - } - pci_set_master (hi->pdev[0]); - pci_set_master (hi->pdev[1]); - if (!(hi->ndev = c4_add_dev (hi, i, (long) hi->addr_mapped[0], - (long) hi->addr_mapped[1], - hi->pdev[0]->irq, - hi->pdev[1]->irq))) - { - drvr_state = SBE_DRVR_DOWN; - cleanup_ioremap (); - /* NOTE: c4_add_dev() does its own device cleanup */ + /* Have now memory mapped all boards. Now allow board's access to system */ + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->pci_slot == 0xff) + break; + if (pci_enable_device(hi->pdev[0]) || + pci_enable_device(hi->pdev[1])) { + drvr_state = SBE_DRVR_DOWN; + pr_warning("%s: failed to enable card %d slot %d\n", + hi->devname, i, hi->pci_slot); + cleanup_devs(); + cleanup_ioremap(); + return -EIO; + } + pci_set_master(hi->pdev[0]); + pci_set_master(hi->pdev[1]); + hi->ndev = c4_add_dev(hi, i, (long) hi->addr_mapped[0], + (long) hi->addr_mapped[1], + hi->pdev[0]->irq, + hi->pdev[1]->irq); + if (!hi->ndev) { + drvr_state = SBE_DRVR_DOWN; + cleanup_ioremap(); + /* NOTE: c4_add_dev() does its own device cleanup */ #if 0 - cleanup_devs (); + cleanup_devs(); #endif - return error_flag; /* error_flag set w/in add_dev() */ - } - show_two (hi, i); /* displays found information */ - } - return 0; + return error_flag; /* error_flag set w/in add_dev() */ + } + show_two(hi, i); /* displays found information */ + } + return 0; } /*** End-of-File ***/ diff --git a/drivers/staging/cxt1e1/libsbew.h b/drivers/staging/cxt1e1/libsbew.h index 4254c0426db9..bd2bfba604b3 100644 --- a/drivers/staging/cxt1e1/libsbew.h +++ b/drivers/staging/cxt1e1/libsbew.h @@ -514,36 +514,36 @@ struct sbecom_port_param }; typedef struct wancfg wcfg_t; - extern wcfg_t *wancfg_init (char *, char *); - extern int wancfg_card_blink (wcfg_t *, int); - extern int wancfg_ctl (wcfg_t *, int, void *, int, void *, int); - extern int wancfg_del_card_stats (wcfg_t *); - extern int wancfg_del_chan_stats (wcfg_t *, int); - extern int wancfg_enable_ports (wcfg_t *, int); - extern int wancfg_free (wcfg_t *); - extern int wancfg_get_brdaddr (wcfg_t *, struct sbe_brd_addr *); - extern int wancfg_get_brdinfo (wcfg_t *, struct sbe_brd_info *); - extern int wancfg_get_card (wcfg_t *, struct sbecom_card_param *); - extern int wancfg_get_card_chan_stats (wcfg_t *, struct sbecom_chan_stats *); - extern int wancfg_get_card_sn (wcfg_t *); - extern int wancfg_get_card_stats (wcfg_t *, struct temux_card_stats *); - extern int wancfg_get_chan (wcfg_t *, int, struct sbecom_chan_param *); - extern int wancfg_get_chan_stats (wcfg_t *, int, struct sbecom_chan_stats *); - extern int wancfg_get_drvinfo (wcfg_t *, int, struct sbe_drv_info *); - extern int wancfg_get_framer (wcfg_t *, int, struct sbecom_framer_param *); - extern int wancfg_get_iid (wcfg_t *, int, struct sbe_iid_info *); - extern int wancfg_get_sn (wcfg_t *, unsigned int *); - extern int wancfg_read (wcfg_t *, int, struct sbecom_wrt_vec *); - extern int wancfg_reset_device (wcfg_t *, int); - extern int wancfg_set_card (wcfg_t *, struct sbecom_card_param *); - extern int wancfg_set_chan (wcfg_t *, int, struct sbecom_chan_param *); - extern int wancfg_set_framer (wcfg_t *, int, struct sbecom_framer_param *); - extern int wancfg_set_loglevel (wcfg_t *, uint); - extern int wancfg_write (wcfg_t *, int, struct sbecom_wrt_vec *); + extern wcfg_t *wancfg_init(char *, char *); + extern int wancfg_card_blink(wcfg_t *, int); + extern int wancfg_ctl(wcfg_t *, int, void *, int, void *, int); + extern int wancfg_del_card_stats(wcfg_t *); + extern int wancfg_del_chan_stats(wcfg_t *, int); + extern int wancfg_enable_ports(wcfg_t *, int); + extern int wancfg_free(wcfg_t *); + extern int wancfg_get_brdaddr(wcfg_t *, struct sbe_brd_addr *); + extern int wancfg_get_brdinfo(wcfg_t *, struct sbe_brd_info *); + extern int wancfg_get_card(wcfg_t *, struct sbecom_card_param *); + extern int wancfg_get_card_chan_stats(wcfg_t *, struct sbecom_chan_stats *); + extern int wancfg_get_card_sn(wcfg_t *); + extern int wancfg_get_card_stats(wcfg_t *, struct temux_card_stats *); + extern int wancfg_get_chan(wcfg_t *, int, struct sbecom_chan_param *); + extern int wancfg_get_chan_stats(wcfg_t *, int, struct sbecom_chan_stats *); + extern int wancfg_get_drvinfo(wcfg_t *, int, struct sbe_drv_info *); + extern int wancfg_get_framer(wcfg_t *, int, struct sbecom_framer_param *); + extern int wancfg_get_iid(wcfg_t *, int, struct sbe_iid_info *); + extern int wancfg_get_sn(wcfg_t *, unsigned int *); + extern int wancfg_read(wcfg_t *, int, struct sbecom_wrt_vec *); + extern int wancfg_reset_device(wcfg_t *, int); + extern int wancfg_set_card(wcfg_t *, struct sbecom_card_param *); + extern int wancfg_set_chan(wcfg_t *, int, struct sbecom_chan_param *); + extern int wancfg_set_framer(wcfg_t *, int, struct sbecom_framer_param *); + extern int wancfg_set_loglevel(wcfg_t *, uint); + extern int wancfg_write(wcfg_t *, int, struct sbecom_wrt_vec *); #ifdef NOT_YET_COMMON - extern int wancfg_get_tsioc (wcfg_t *, struct wanc1t3_ts_hdr *, struct wanc1t3_ts_param *); - extern int wancfg_set_tsioc (wcfg_t *, struct wanc1t3_ts_param *); + extern int wancfg_get_tsioc(wcfg_t *, struct wanc1t3_ts_hdr *, struct wanc1t3_ts_param *); + extern int wancfg_set_tsioc(wcfg_t *, struct wanc1t3_ts_param *); #endif #endif /*** _INC_LIBSBEW_H_ ***/ diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c index 79206cb3fb94..b02f5ade6661 100644 --- a/drivers/staging/cxt1e1/linux.c +++ b/drivers/staging/cxt1e1/linux.c @@ -31,7 +31,7 @@ #include "pmcc4_private.h" #include "sbeproc.h" -/***************************************************************************************** +/******************************************************************************* * Error out early if we have compiler trouble. * * (This section is included from the kernel's init/main.c as a friendly @@ -50,43 +50,42 @@ #warning gcc-4.1.0 is known to miscompile the kernel. A different compiler version is recommended. #endif -/*****************************************************************************************/ +/*******************************************************************************/ #define CHANNAME "hdlc" /*******************************************************************/ /* forward references */ -status_t c4_chan_work_init (mpi_t *, mch_t *); -void musycc_wq_chan_restart (void *); -status_t __init c4_init (ci_t *, u_char *, u_char *); -status_t __init c4_init2 (ci_t *); -ci_t *__init c4_new (void *); -int __init c4hw_attach_all (void); -void __init hdw_sn_get (hdw_info_t *, int); +status_t c4_chan_work_init(mpi_t *, mch_t *); +void musycc_wq_chan_restart(void *); +status_t __init c4_init(ci_t *, u_char *, u_char *); +status_t __init c4_init2(ci_t *); +ci_t *__init c4_new(void *); +int __init c4hw_attach_all(void); +void __init hdw_sn_get(hdw_info_t *, int); #ifdef CONFIG_SBE_PMCC4_NCOMM -irqreturn_t c4_ebus_intr_th_handler (void *); +irqreturn_t c4_ebus_intr_th_handler(void *); #endif -int c4_frame_rw (ci_t *, struct sbecom_port_param *); -status_t c4_get_port (ci_t *, int); -int c4_loop_port (ci_t *, int, u_int8_t); -int c4_musycc_rw (ci_t *, struct c4_musycc_param *); -int c4_new_chan (ci_t *, int, int, void *); -status_t c4_set_port (ci_t *, int); -int c4_pld_rw (ci_t *, struct sbecom_port_param *); -void cleanup_devs (void); -void cleanup_ioremap (void); -status_t musycc_chan_down (ci_t *, int); -irqreturn_t musycc_intr_th_handler (void *); -int musycc_start_xmit (ci_t *, int, void *); +int c4_frame_rw(ci_t *, struct sbecom_port_param *); +status_t c4_get_port(ci_t *, int); +int c4_loop_port(ci_t *, int, u_int8_t); +int c4_musycc_rw(ci_t *, struct c4_musycc_param *); +int c4_new_chan(ci_t *, int, int, void *); +status_t c4_set_port(ci_t *, int); +int c4_pld_rw(ci_t *, struct sbecom_port_param *); +void cleanup_devs(void); +void cleanup_ioremap(void); +status_t musycc_chan_down(ci_t *, int); +irqreturn_t musycc_intr_th_handler(void *); +int musycc_start_xmit(ci_t *, int, void *); -extern char pmcc4_OSSI_release[]; extern ci_t *CI; extern struct s_hdw_info hdw_info[]; #if defined(CONFIG_SBE_HDLC_V7) || defined(CONFIG_SBE_WAN256T3_HDLC_V7) || \ - defined(CONFIG_SBE_HDLC_V7_MODULE) || defined(CONFIG_SBE_WAN256T3_HDLC_V7_MODULE) + defined(CONFIG_SBE_HDLC_V7_MODULE) || defined(CONFIG_SBE_WAN256T3_HDLC_V7_MODULE) #define _v7_hdlc_ 1 #else #define _v7_hdlc_ 0 @@ -94,9 +93,9 @@ extern struct s_hdw_info hdw_info[]; #if _v7_hdlc_ #define V7(x) (x ## _v7) -extern int hdlc_netif_rx_v7 (hdlc_device *, struct sk_buff *); -extern int register_hdlc_device_v7 (hdlc_device *); -extern int unregister_hdlc_device_v7 (hdlc_device *); +extern int hdlc_netif_rx_v7(hdlc_device *, struct sk_buff *); +extern int register_hdlc_device_v7(hdlc_device *); +extern int unregister_hdlc_device_v7(hdlc_device *); #else #define V7(x) x @@ -104,11 +103,11 @@ extern int unregister_hdlc_device_v7 (hdlc_device *); int error_flag; /* module load error reporting */ int cxt1e1_log_level = LOG_ERROR; -int log_level_default = LOG_ERROR; +static int log_level_default = LOG_ERROR; module_param(cxt1e1_log_level, int, 0444); int cxt1e1_max_mru = MUSYCC_MRU; -int max_mru_default = MUSYCC_MRU; +static int max_mru_default = MUSYCC_MRU; module_param(cxt1e1_max_mru, int, 0444); int cxt1e1_max_mtu = MUSYCC_MTU; @@ -127,33 +126,23 @@ module_param(max_rxdesc_used, int, 0444); /****************************************************************************/ /****************************************************************************/ -void * -getuserbychan (int channum) +void * +getuserbychan(int channum) { - mch_t *ch; + mch_t *ch; - ch = c4_find_chan (channum); - return ch ? ch->user : NULL; + ch = c4_find_chan(channum); + return ch ? ch->user : NULL; } -char * -get_hdlc_name (hdlc_device *hdlc) +char * +get_hdlc_name(hdlc_device *hdlc) { - struct c4_priv *priv = hdlc->priv; - struct net_device *dev = getuserbychan (priv->channum); + struct c4_priv *priv = hdlc->priv; + struct net_device *dev = getuserbychan(priv->channum); - return dev->name; -} - - -static status_t -mkret (int bsd) -{ - if (bsd > 0) - return -bsd; - else - return bsd; + return dev->name; } /***************************************************************************/ @@ -179,958 +168,946 @@ mkret (int bsd) * within a port's group. */ void -c4_wk_chan_restart (mch_t *ch) +c4_wk_chan_restart(mch_t *ch) { - mpi_t *pi = ch->up; + mpi_t *pi = ch->up; #ifdef RLD_RESTART_DEBUG - pr_info(">> %s: queueing Port %d Chan %d, mch_t @ %p\n", - __func__, pi->portnum, ch->channum, ch); + pr_info(">> %s: queueing Port %d Chan %d, mch_t @ %p\n", + __func__, pi->portnum, ch->channum, ch); #endif - /* create new entry w/in workqueue for this channel and let'er rip */ + /* create new entry w/in workqueue for this channel and let'er rip */ - /** queue_work (struct workqueue_struct *queue, - ** struct work_struct *work); - **/ - queue_work (pi->wq_port, &ch->ch_work); + /** queue_work(struct workqueue_struct *queue, + ** struct work_struct *work); + **/ + queue_work(pi->wq_port, &ch->ch_work); } status_t -c4_wk_chan_init (mpi_t *pi, mch_t *ch) +c4_wk_chan_init(mpi_t *pi, mch_t *ch) { - /* - * this will be used to restart a stopped channel - */ + /* + * this will be used to restart a stopped channel + */ - /** INIT_WORK (struct work_struct *work, - ** void (*function)(void *), - ** void *data); - **/ - INIT_WORK(&ch->ch_work, (void *)musycc_wq_chan_restart); - return 0; /* success */ + /** INIT_WORK(struct work_struct *work, + ** void (*function)(void *), + ** void *data); + **/ + INIT_WORK(&ch->ch_work, (void *)musycc_wq_chan_restart); + return 0; /* success */ } status_t -c4_wq_port_init (mpi_t *pi) +c4_wq_port_init(mpi_t *pi) { - char name[16], *np; /* NOTE: name of the queue limited by system - * to 10 characters */ + char name[16]; /* NOTE: name of the queue limited by system + * to 10 characters */ + if (pi->wq_port) + return 0; /* already initialized */ - if (pi->wq_port) - return 0; /* already initialized */ - - np = name; - memset (name, 0, 16); - sprintf (np, "%s%d", pi->up->devname, pi->portnum); /* IE pmcc4-01) */ + /* IE pmcc4-01 */ + snprintf(name, sizeof(name), "%s%d", pi->up->devname, pi->portnum); #ifdef RLD_RESTART_DEBUG - pr_info(">> %s: creating workqueue <%s> for Port %d.\n", - __func__, name, pi->portnum); /* RLD DEBUG */ + pr_info(">> %s: creating workqueue <%s> for Port %d.\n", + __func__, name, pi->portnum); /* RLD DEBUG */ #endif - if (!(pi->wq_port = create_singlethread_workqueue (name))) - return -ENOMEM; - return 0; /* success */ + pi->wq_port = create_singlethread_workqueue(name); + if (!pi->wq_port) + return -ENOMEM; + return 0; /* success */ } void -c4_wq_port_cleanup (mpi_t *pi) +c4_wq_port_cleanup(mpi_t *pi) { - /* - * PORT POINT: cannot call this if WQ is statically allocated w/in - * structure since it calls kfree(wq); - */ - if (pi->wq_port) - { - destroy_workqueue (pi->wq_port); /* this also calls - * flush_workqueue() */ - pi->wq_port = NULL; - } + /* + * PORT POINT: cannot call this if WQ is statically allocated w/in + * structure since it calls kfree(wq); + */ + if (pi->wq_port) { + destroy_workqueue(pi->wq_port); /* this also calls + * flush_workqueue() */ + pi->wq_port = NULL; + } } /***************************************************************************/ -irqreturn_t -c4_linux_interrupt (int irq, void *dev_instance) +static irqreturn_t +c4_linux_interrupt(int irq, void *dev_instance) { - struct net_device *ndev = dev_instance; + struct net_device *ndev = dev_instance; - return musycc_intr_th_handler(netdev_priv(ndev)); + return musycc_intr_th_handler(netdev_priv(ndev)); } #ifdef CONFIG_SBE_PMCC4_NCOMM -irqreturn_t -c4_ebus_interrupt (int irq, void *dev_instance) +static irqreturn_t +c4_ebus_interrupt(int irq, void *dev_instance) { - struct net_device *ndev = dev_instance; + struct net_device *ndev = dev_instance; - return c4_ebus_intr_th_handler(netdev_priv(ndev)); + return c4_ebus_intr_th_handler(netdev_priv(ndev)); } #endif static int -void_open (struct net_device *ndev) +void_open(struct net_device *ndev) { - pr_info("%s: trying to open master device !\n", ndev->name); - return -1; + pr_info("%s: trying to open master device !\n", ndev->name); + return -1; } static int -chan_open (struct net_device *ndev) +chan_open(struct net_device *ndev) { - hdlc_device *hdlc = dev_to_hdlc (ndev); - const struct c4_priv *priv = hdlc->priv; - int ret; + hdlc_device *hdlc = dev_to_hdlc(ndev); + const struct c4_priv *priv = hdlc->priv; + int ret; - if ((ret = hdlc_open (ndev))) - { - pr_info("hdlc_open failure, err %d.\n", ret); - return ret; - } - if ((ret = c4_chan_up (priv->ci, priv->channum))) - return -ret; - try_module_get (THIS_MODULE); - netif_start_queue (ndev); - return 0; /* no error = success */ + ret = hdlc_open(ndev); + if (ret) { + pr_info("hdlc_open failure, err %d.\n", ret); + return ret; + } + + ret = c4_chan_up(priv->ci, priv->channum); + if (ret < 0) + return ret; + try_module_get(THIS_MODULE); + netif_start_queue(ndev); + return 0; /* no error = success */ } static int -chan_close (struct net_device *ndev) +chan_close(struct net_device *ndev) { - hdlc_device *hdlc = dev_to_hdlc (ndev); - const struct c4_priv *priv = hdlc->priv; + hdlc_device *hdlc = dev_to_hdlc(ndev); + const struct c4_priv *priv = hdlc->priv; - netif_stop_queue (ndev); - musycc_chan_down ((ci_t *) 0, priv->channum); - hdlc_close (ndev); - module_put (THIS_MODULE); - return 0; + netif_stop_queue(ndev); + musycc_chan_down((ci_t *) 0, priv->channum); + hdlc_close(ndev); + module_put(THIS_MODULE); + return 0; } static int -chan_dev_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) +chan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - return hdlc_ioctl (dev, ifr, cmd); + return hdlc_ioctl(dev, ifr, cmd); } static int -chan_attach_noop (struct net_device *ndev, unsigned short foo_1, unsigned short foo_2) +chan_attach_noop(struct net_device *ndev, unsigned short foo_1, + unsigned short foo_2) { - return 0; /* our driver has nothing to do here, show's - * over, go home */ + /* our driver has nothing to do here, show's + * over, go home + */ + return 0; } static struct net_device_stats * -chan_get_stats (struct net_device *ndev) +chan_get_stats(struct net_device *ndev) { - mch_t *ch; - struct net_device_stats *nstats; - struct sbecom_chan_stats *stats; - int channum; + mch_t *ch; + struct net_device_stats *nstats; + struct sbecom_chan_stats *stats; + int channum; - { - struct c4_priv *priv; + { + struct c4_priv *priv; - priv = (struct c4_priv *) dev_to_hdlc (ndev)->priv; - channum = priv->channum; - } + priv = (struct c4_priv *)dev_to_hdlc(ndev)->priv; + channum = priv->channum; + } - ch = c4_find_chan (channum); - if (ch == NULL) - return NULL; + ch = c4_find_chan(channum); + if (ch == NULL) + return NULL; - nstats = &ndev->stats; - stats = &ch->s; + nstats = &ndev->stats; + stats = &ch->s; - memset (nstats, 0, sizeof (struct net_device_stats)); - nstats->rx_packets = stats->rx_packets; - nstats->tx_packets = stats->tx_packets; - nstats->rx_bytes = stats->rx_bytes; - nstats->tx_bytes = stats->tx_bytes; - nstats->rx_errors = stats->rx_length_errors + - stats->rx_over_errors + - stats->rx_crc_errors + - stats->rx_frame_errors + - stats->rx_fifo_errors + - stats->rx_missed_errors; - nstats->tx_errors = stats->tx_dropped + - stats->tx_aborted_errors + - stats->tx_fifo_errors; - nstats->rx_dropped = stats->rx_dropped; - nstats->tx_dropped = stats->tx_dropped; + memset(nstats, 0, sizeof(struct net_device_stats)); + nstats->rx_packets = stats->rx_packets; + nstats->tx_packets = stats->tx_packets; + nstats->rx_bytes = stats->rx_bytes; + nstats->tx_bytes = stats->tx_bytes; + nstats->rx_errors = stats->rx_length_errors + + stats->rx_over_errors + + stats->rx_crc_errors + + stats->rx_frame_errors + + stats->rx_fifo_errors + + stats->rx_missed_errors; + nstats->tx_errors = stats->tx_dropped + + stats->tx_aborted_errors + + stats->tx_fifo_errors; + nstats->rx_dropped = stats->rx_dropped; + nstats->tx_dropped = stats->tx_dropped; - nstats->rx_length_errors = stats->rx_length_errors; - nstats->rx_over_errors = stats->rx_over_errors; - nstats->rx_crc_errors = stats->rx_crc_errors; - nstats->rx_frame_errors = stats->rx_frame_errors; - nstats->rx_fifo_errors = stats->rx_fifo_errors; - nstats->rx_missed_errors = stats->rx_missed_errors; + nstats->rx_length_errors = stats->rx_length_errors; + nstats->rx_over_errors = stats->rx_over_errors; + nstats->rx_crc_errors = stats->rx_crc_errors; + nstats->rx_frame_errors = stats->rx_frame_errors; + nstats->rx_fifo_errors = stats->rx_fifo_errors; + nstats->rx_missed_errors = stats->rx_missed_errors; - nstats->tx_aborted_errors = stats->tx_aborted_errors; - nstats->tx_fifo_errors = stats->tx_fifo_errors; + nstats->tx_aborted_errors = stats->tx_aborted_errors; + nstats->tx_fifo_errors = stats->tx_fifo_errors; - return nstats; + return nstats; } static ci_t * -get_ci_by_dev (struct net_device *ndev) +get_ci_by_dev(struct net_device *ndev) { - return (ci_t *)(netdev_priv(ndev)); + return (ci_t *)(netdev_priv(ndev)); } static int -c4_linux_xmit (struct sk_buff *skb, struct net_device *ndev) +c4_linux_xmit(struct sk_buff *skb, struct net_device *ndev) { - const struct c4_priv *priv; - int rval; + const struct c4_priv *priv; + int rval; - hdlc_device *hdlc = dev_to_hdlc (ndev); + hdlc_device *hdlc = dev_to_hdlc(ndev); - priv = hdlc->priv; + priv = hdlc->priv; - rval = musycc_start_xmit (priv->ci, priv->channum, skb); - return rval; + rval = musycc_start_xmit(priv->ci, priv->channum, skb); + return rval; } static const struct net_device_ops chan_ops = { - .ndo_open = chan_open, - .ndo_stop = chan_close, - .ndo_start_xmit = c4_linux_xmit, - .ndo_do_ioctl = chan_dev_ioctl, - .ndo_get_stats = chan_get_stats, + .ndo_open = chan_open, + .ndo_stop = chan_close, + .ndo_start_xmit = c4_linux_xmit, + .ndo_do_ioctl = chan_dev_ioctl, + .ndo_get_stats = chan_get_stats, }; static struct net_device * -create_chan (struct net_device *ndev, ci_t *ci, - struct sbecom_chan_param *cp) +create_chan(struct net_device *ndev, ci_t *ci, + struct sbecom_chan_param *cp) { - hdlc_device *hdlc; - struct net_device *dev; - hdw_info_t *hi; - int ret; + hdlc_device *hdlc; + struct net_device *dev; + hdw_info_t *hi; + int ret; - if (c4_find_chan (cp->channum)) - return NULL; /* channel already exists */ + if (c4_find_chan(cp->channum)) + return NULL; /* channel already exists */ - { - struct c4_priv *priv; + { + struct c4_priv *priv; - /* allocate then fill in private data structure */ - priv = OS_kmalloc (sizeof (struct c4_priv)); - if (!priv) - { - pr_warning("%s: no memory for net_device !\n", ci->devname); - return NULL; - } - dev = alloc_hdlcdev (priv); - if (!dev) - { - pr_warning("%s: no memory for hdlc_device !\n", ci->devname); - OS_kfree (priv); - return NULL; - } - priv->ci = ci; - priv->channum = cp->channum; - } + /* allocate then fill in private data structure */ + priv = OS_kmalloc(sizeof(struct c4_priv)); + if (!priv) { + pr_warning("%s: no memory for net_device !\n", + ci->devname); + return NULL; + } + dev = alloc_hdlcdev(priv); + if (!dev) { + pr_warning("%s: no memory for hdlc_device !\n", + ci->devname); + OS_kfree(priv); + return NULL; + } + priv->ci = ci; + priv->channum = cp->channum; + } - hdlc = dev_to_hdlc (dev); + hdlc = dev_to_hdlc(dev); - dev->base_addr = 0; /* not I/O mapped */ - dev->irq = ndev->irq; - dev->type = ARPHRD_RAWHDLC; - *dev->name = 0; /* default ifconfig name = "hdlc" */ + dev->base_addr = 0; /* not I/O mapped */ + dev->irq = ndev->irq; + dev->type = ARPHRD_RAWHDLC; + *dev->name = 0; /* default ifconfig name = "hdlc" */ - hi = (hdw_info_t *) ci->hdw_info; - if (hi->mfg_info_sts == EEPROM_OK) - { - switch (hi->promfmt) - { - case PROM_FORMAT_TYPE1: - memcpy (dev->dev_addr, (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); - break; - case PROM_FORMAT_TYPE2: - memcpy (dev->dev_addr, (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); - break; - default: - memset (dev->dev_addr, 0, 6); - break; - } - } else - { - memset (dev->dev_addr, 0, 6); - } + hi = (hdw_info_t *)ci->hdw_info; + if (hi->mfg_info_sts == EEPROM_OK) { + switch (hi->promfmt) { + case PROM_FORMAT_TYPE1: + memcpy(dev->dev_addr, + (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); + break; + case PROM_FORMAT_TYPE2: + memcpy(dev->dev_addr, + (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); + break; + default: + memset(dev->dev_addr, 0, 6); + break; + } + } else + memset(dev->dev_addr, 0, 6); - hdlc->xmit = c4_linux_xmit; + hdlc->xmit = c4_linux_xmit; - dev->netdev_ops = &chan_ops; - /* - * The native hdlc stack calls this 'attach' routine during - * hdlc_raw_ioctl(), passing parameters for line encoding and parity. - * Since hdlc_raw_ioctl() stack does not interrogate whether an 'attach' - * routine is actually registered or not, we supply a dummy routine which - * does nothing (since encoding and parity are setup for our driver via a - * special configuration application). - */ + dev->netdev_ops = &chan_ops; + /* + * The native hdlc stack calls this 'attach' routine during + * hdlc_raw_ioctl(), passing parameters for line encoding and parity. + * Since hdlc_raw_ioctl() stack does not interrogate whether an 'attach' + * routine is actually registered or not, we supply a dummy routine which + * does nothing (since encoding and parity are setup for our driver via a + * special configuration application). + */ - hdlc->attach = chan_attach_noop; + hdlc->attach = chan_attach_noop; - rtnl_unlock (); /* needed due to Ioctl calling sequence */ - ret = register_hdlc_device (dev); - /* NOTE: setting must occur AFTER registration in order to "take" */ - dev->tx_queue_len = MAX_DEFAULT_IFQLEN; + /* needed due to Ioctl calling sequence */ + rtnl_unlock(); + ret = register_hdlc_device(dev); + /* NOTE: setting must occur AFTER registration in order to "take" */ + dev->tx_queue_len = MAX_DEFAULT_IFQLEN; - rtnl_lock (); /* needed due to Ioctl calling sequence */ - if (ret) - { - if (cxt1e1_log_level >= LOG_WARN) - pr_info("%s: create_chan[%d] registration error = %d.\n", - ci->devname, cp->channum, ret); - free_netdev (dev); /* cleanup */ - return NULL; /* failed to register */ - } - return dev; + /* needed due to Ioctl calling sequence */ + rtnl_lock(); + if (ret) { + if (cxt1e1_log_level >= LOG_WARN) + pr_info("%s: create_chan[%d] registration error = %d.\n", + ci->devname, cp->channum, ret); + /* cleanup */ + free_netdev(dev); + /* failed to register */ + return NULL; + } + return dev; } /* the idea here is to get port information and pass it back (using pointer) */ -static status_t -do_get_port (struct net_device *ndev, void *data) +static status_t +do_get_port(struct net_device *ndev, void *data) { - int ret; - ci_t *ci; /* ci stands for card information */ - struct sbecom_port_param pp;/* copy data to kernel land */ + int ret; + ci_t *ci; /* ci stands for card information */ + struct sbecom_port_param pp;/* copy data to kernel land */ - if (copy_from_user (&pp, data, sizeof (struct sbecom_port_param))) - return -EFAULT; - if (pp.portnum >= MUSYCC_NPORTS) - return -EFAULT; - ci = get_ci_by_dev (ndev); - if (!ci) - return -EINVAL; /* get card info */ + if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) + return -EFAULT; + if (pp.portnum >= MUSYCC_NPORTS) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; /* get card info */ - ret = mkret (c4_get_port (ci, pp.portnum)); - if (ret) - return ret; - if (copy_to_user (data, &ci->port[pp.portnum].p, - sizeof (struct sbecom_port_param))) - return -EFAULT; - return 0; + ret = c4_get_port(ci, pp.portnum); + if (ret < 0) + return ret; + if (copy_to_user(data, &ci->port[pp.portnum].p, + sizeof(struct sbecom_port_param))) + return -EFAULT; + return 0; } /* this function copys the user data and then calls the real action function */ -static status_t -do_set_port (struct net_device *ndev, void *data) +static status_t +do_set_port(struct net_device *ndev, void *data) { - ci_t *ci; /* ci stands for card information */ - struct sbecom_port_param pp;/* copy data to kernel land */ + ci_t *ci; /* ci stands for card information */ + struct sbecom_port_param pp;/* copy data to kernel land */ - if (copy_from_user (&pp, data, sizeof (struct sbecom_port_param))) - return -EFAULT; - if (pp.portnum >= MUSYCC_NPORTS) - return -EFAULT; - ci = get_ci_by_dev (ndev); - if (!ci) - return -EINVAL; /* get card info */ + if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) + return -EFAULT; + if (pp.portnum >= MUSYCC_NPORTS) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; /* get card info */ - if (pp.portnum >= ci->max_port) /* sanity check */ - return -ENXIO; + if (pp.portnum >= ci->max_port) /* sanity check */ + return -ENXIO; - memcpy (&ci->port[pp.portnum].p, &pp, sizeof (struct sbecom_port_param)); - return mkret (c4_set_port (ci, pp.portnum)); + memcpy(&ci->port[pp.portnum].p, &pp, sizeof(struct sbecom_port_param)); + return c4_set_port(ci, pp.portnum); } /* work the port loopback mode as per directed */ -static status_t -do_port_loop (struct net_device *ndev, void *data) +static status_t +do_port_loop(struct net_device *ndev, void *data) { - struct sbecom_port_param pp; - ci_t *ci; + struct sbecom_port_param pp; + ci_t *ci; - if (copy_from_user (&pp, data, sizeof (struct sbecom_port_param))) - return -EFAULT; - ci = get_ci_by_dev (ndev); - if (!ci) - return -EINVAL; - return mkret (c4_loop_port (ci, pp.portnum, pp.port_mode)); + if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + return c4_loop_port(ci, pp.portnum, pp.port_mode); } /* set the specified register with the given value / or just read it */ -static status_t -do_framer_rw (struct net_device *ndev, void *data) +static status_t +do_framer_rw(struct net_device *ndev, void *data) { - struct sbecom_port_param pp; - ci_t *ci; - int ret; + struct sbecom_port_param pp; + ci_t *ci; + int ret; - if (copy_from_user (&pp, data, sizeof (struct sbecom_port_param))) - return -EFAULT; - ci = get_ci_by_dev (ndev); - if (!ci) - return -EINVAL; - ret = mkret (c4_frame_rw (ci, &pp)); - if (ret) - return ret; - if (copy_to_user (data, &pp, sizeof (struct sbecom_port_param))) - return -EFAULT; - return 0; + if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + ret = c4_frame_rw(ci, &pp); + if (ret < 0) + return ret; + if (copy_to_user(data, &pp, sizeof(struct sbecom_port_param))) + return -EFAULT; + return 0; } /* set the specified register with the given value / or just read it */ -static status_t -do_pld_rw (struct net_device *ndev, void *data) +static status_t +do_pld_rw(struct net_device *ndev, void *data) { - struct sbecom_port_param pp; - ci_t *ci; - int ret; + struct sbecom_port_param pp; + ci_t *ci; + int ret; - if (copy_from_user (&pp, data, sizeof (struct sbecom_port_param))) - return -EFAULT; - ci = get_ci_by_dev (ndev); - if (!ci) - return -EINVAL; - ret = mkret (c4_pld_rw (ci, &pp)); - if (ret) - return ret; - if (copy_to_user (data, &pp, sizeof (struct sbecom_port_param))) - return -EFAULT; - return 0; + if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + + ret = c4_pld_rw(ci, &pp); + if (ret) + return ret; + if (copy_to_user(data, &pp, sizeof(struct sbecom_port_param))) + return -EFAULT; + return 0; } /* set the specified register with the given value / or just read it */ -static status_t -do_musycc_rw (struct net_device *ndev, void *data) +static status_t +do_musycc_rw(struct net_device *ndev, void *data) { - struct c4_musycc_param mp; - ci_t *ci; - int ret; + struct c4_musycc_param mp; + ci_t *ci; + int ret; - if (copy_from_user (&mp, data, sizeof (struct c4_musycc_param))) - return -EFAULT; - ci = get_ci_by_dev (ndev); - if (!ci) - return -EINVAL; - ret = mkret (c4_musycc_rw (ci, &mp)); - if (ret) - return ret; - if (copy_to_user (data, &mp, sizeof (struct c4_musycc_param))) - return -EFAULT; - return 0; + if (copy_from_user(&mp, data, sizeof(struct c4_musycc_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + ret = c4_musycc_rw(ci, &mp); + if (ret < 0) + return ret; + if (copy_to_user(data, &mp, sizeof(struct c4_musycc_param))) + return -EFAULT; + return 0; } -static status_t -do_get_chan (struct net_device *ndev, void *data) +static status_t +do_get_chan(struct net_device *ndev, void *data) { - struct sbecom_chan_param cp; - int ret; + struct sbecom_chan_param cp; + int ret; - if (copy_from_user (&cp, data, - sizeof (struct sbecom_chan_param))) - return -EFAULT; + if (copy_from_user(&cp, data, + sizeof(struct sbecom_chan_param))) + return -EFAULT; - if ((ret = mkret (c4_get_chan (cp.channum, &cp)))) - return ret; + ret = c4_get_chan(cp.channum, &cp); + if (ret < 0) + return ret; - if (copy_to_user (data, &cp, sizeof (struct sbecom_chan_param))) - return -EFAULT; - return 0; + if (copy_to_user(data, &cp, sizeof(struct sbecom_chan_param))) + return -EFAULT; + return 0; } -static status_t -do_set_chan (struct net_device *ndev, void *data) +static status_t +do_set_chan(struct net_device *ndev, void *data) { - struct sbecom_chan_param cp; - int ret; - ci_t *ci; + struct sbecom_chan_param cp; + ci_t *ci; - if (copy_from_user (&cp, data, sizeof (struct sbecom_chan_param))) - return -EFAULT; - ci = get_ci_by_dev (ndev); - if (!ci) - return -EINVAL; - switch (ret = mkret (c4_set_chan (cp.channum, &cp))) - { - case 0: - return 0; - default: - return ret; - } + if (copy_from_user(&cp, data, sizeof(struct sbecom_chan_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + return c4_set_chan(cp.channum, &cp); } -static status_t -do_create_chan (struct net_device *ndev, void *data) +static status_t +do_create_chan(struct net_device *ndev, void *data) { - ci_t *ci; - struct net_device *dev; - struct sbecom_chan_param cp; - int ret; + ci_t *ci; + struct net_device *dev; + struct sbecom_chan_param cp; + int ret; - if (copy_from_user (&cp, data, sizeof (struct sbecom_chan_param))) - return -EFAULT; - ci = get_ci_by_dev (ndev); - if (!ci) - return -EINVAL; - dev = create_chan (ndev, ci, &cp); - if (!dev) - return -EBUSY; - ret = mkret (c4_new_chan (ci, cp.port, cp.channum, dev)); - if (ret) - { - rtnl_unlock (); /* needed due to Ioctl calling sequence */ - unregister_hdlc_device (dev); - rtnl_lock (); /* needed due to Ioctl calling sequence */ - free_netdev (dev); - } - return ret; + if (copy_from_user(&cp, data, sizeof(struct sbecom_chan_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + dev = create_chan(ndev, ci, &cp); + if (!dev) + return -EBUSY; + ret = c4_new_chan(ci, cp.port, cp.channum, dev); + if (ret < 0) { + /* needed due to Ioctl calling sequence */ + rtnl_unlock(); + unregister_hdlc_device(dev); + /* needed due to Ioctl calling sequence */ + rtnl_lock(); + free_netdev(dev); + } + return ret; } -static status_t -do_get_chan_stats (struct net_device *ndev, void *data) +static status_t +do_get_chan_stats(struct net_device *ndev, void *data) { - struct c4_chan_stats_wrap ccs; - int ret; + struct c4_chan_stats_wrap ccs; + int ret; - if (copy_from_user (&ccs, data, - sizeof (struct c4_chan_stats_wrap))) - return -EFAULT; - switch (ret = mkret (c4_get_chan_stats (ccs.channum, &ccs.stats))) - { - case 0: - break; - default: - return ret; - } - if (copy_to_user (data, &ccs, - sizeof (struct c4_chan_stats_wrap))) - return -EFAULT; - return 0; + if (copy_from_user(&ccs, data, + sizeof(struct c4_chan_stats_wrap))) + return -EFAULT; + + ret = c4_get_chan_stats(ccs.channum, &ccs.stats); + if (ret < 0) + return ret; + + if (copy_to_user(data, &ccs, + sizeof(struct c4_chan_stats_wrap))) + return -EFAULT; + return 0; } -static status_t -do_set_loglevel (struct net_device *ndev, void *data) +static status_t +do_set_loglevel(struct net_device *ndev, void *data) { - unsigned int cxt1e1_log_level; + unsigned int cxt1e1_log_level; - if (copy_from_user (&cxt1e1_log_level, data, sizeof (int))) - return -EFAULT; - sbecom_set_loglevel (cxt1e1_log_level); - return 0; + if (copy_from_user(&cxt1e1_log_level, data, sizeof(int))) + return -EFAULT; + sbecom_set_loglevel(cxt1e1_log_level); + return 0; } -static status_t -do_deluser (struct net_device *ndev, int lockit) +static status_t +do_deluser(struct net_device *ndev, int lockit) { - if (ndev->flags & IFF_UP) - return -EBUSY; + if (ndev->flags & IFF_UP) + return -EBUSY; - { - ci_t *ci; - mch_t *ch; - const struct c4_priv *priv; - int channum; + { + ci_t *ci; + mch_t *ch; + const struct c4_priv *priv; + int channum; - priv = (struct c4_priv *) dev_to_hdlc (ndev)->priv; - ci = priv->ci; - channum = priv->channum; + priv = (struct c4_priv *)dev_to_hdlc(ndev)->priv; + ci = priv->ci; + channum = priv->channum; - ch = c4_find_chan (channum); - if (ch == NULL) - return -ENOENT; - ch->user = NULL; /* will be freed, below */ - } + ch = c4_find_chan(channum); + if (ch == NULL) + return -ENOENT; + ch->user = NULL; /* will be freed, below */ + } - if (lockit) - rtnl_unlock (); /* needed if Ioctl calling sequence */ - unregister_hdlc_device (ndev); - if (lockit) - rtnl_lock (); /* needed if Ioctl calling sequence */ - free_netdev (ndev); - return 0; + /* needed if Ioctl calling sequence */ + if (lockit) + rtnl_unlock(); + unregister_hdlc_device(ndev); + /* needed if Ioctl calling sequence */ + if (lockit) + rtnl_lock(); + free_netdev(ndev); + return 0; } int -do_del_chan (struct net_device *musycc_dev, void *data) +do_del_chan(struct net_device *musycc_dev, void *data) { - struct sbecom_chan_param cp; - char buf[sizeof (CHANNAME) + 3]; - struct net_device *dev; - int ret; + struct sbecom_chan_param cp; + char buf[sizeof(CHANNAME) + 3]; + struct net_device *dev; + int ret; - if (copy_from_user (&cp, data, - sizeof (struct sbecom_chan_param))) - return -EFAULT; - if (cp.channum > 999) - return -EINVAL; - snprintf (buf, sizeof(buf), CHANNAME "%d", cp.channum); + if (copy_from_user(&cp, data, + sizeof(struct sbecom_chan_param))) + return -EFAULT; + if (cp.channum > 999) + return -EINVAL; + snprintf(buf, sizeof(buf), CHANNAME "%d", cp.channum); dev = __dev_get_by_name(&init_net, buf); if (!dev) return -ENODEV; - ret = do_deluser (dev, 1); - if (ret) - return ret; - return c4_del_chan (cp.channum); + ret = do_deluser(dev, 1); + if (ret) + return ret; + return c4_del_chan(cp.channum); } -int c4_reset_board (void *); +int c4_reset_board(void *); int -do_reset (struct net_device *musycc_dev, void *data) +do_reset(struct net_device *musycc_dev, void *data) { - const struct c4_priv *priv; - int i; + const struct c4_priv *priv; + int i; - for (i = 0; i < 128; i++) - { - struct net_device *ndev; - char buf[sizeof (CHANNAME) + 3]; + for (i = 0; i < 128; i++) { + struct net_device *ndev; + char buf[sizeof(CHANNAME) + 3]; - sprintf (buf, CHANNAME "%d", i); - ndev = __dev_get_by_name(&init_net, buf); - if (!ndev) - continue; - priv = dev_to_hdlc (ndev)->priv; + sprintf(buf, CHANNAME "%d", i); + ndev = __dev_get_by_name(&init_net, buf); + if (!ndev) + continue; + priv = dev_to_hdlc(ndev)->priv; - if ((unsigned long) (priv->ci) == - (unsigned long) (netdev_priv(musycc_dev))) - { - ndev->flags &= ~IFF_UP; - netif_stop_queue (ndev); - do_deluser (ndev, 1); + if ((unsigned long) (priv->ci) == + (unsigned long) (netdev_priv(musycc_dev))) { + ndev->flags &= ~IFF_UP; + netif_stop_queue(ndev); + do_deluser(ndev, 1); + } } - } - return 0; + return 0; } int -do_reset_chan_stats (struct net_device *musycc_dev, void *data) +do_reset_chan_stats(struct net_device *musycc_dev, void *data) { - struct sbecom_chan_param cp; + struct sbecom_chan_param cp; - if (copy_from_user (&cp, data, - sizeof (struct sbecom_chan_param))) - return -EFAULT; - return mkret (c4_del_chan_stats (cp.channum)); + if (copy_from_user(&cp, data, + sizeof(struct sbecom_chan_param))) + return -EFAULT; + return c4_del_chan_stats(cp.channum); } -static status_t -c4_ioctl (struct net_device *ndev, struct ifreq *ifr, int cmd) +static status_t +c4_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) { - ci_t *ci; - void *data; - int iocmd, iolen; - status_t ret; - static struct data - { - union - { - u_int8_t c; - u_int32_t i; - struct sbe_brd_info bip; - struct sbe_drv_info dip; - struct sbe_iid_info iip; - struct sbe_brd_addr bap; - struct sbecom_chan_stats stats; - struct sbecom_chan_param param; - struct temux_card_stats cards; - struct sbecom_card_param cardp; - struct sbecom_framer_param frp; - } u; - } arg; + ci_t *ci; + void *data; + int iocmd, iolen; + status_t ret; + static struct data { + union { + u_int8_t c; + u_int32_t i; + struct sbe_brd_info bip; + struct sbe_drv_info dip; + struct sbe_iid_info iip; + struct sbe_brd_addr bap; + struct sbecom_chan_stats stats; + struct sbecom_chan_param param; + struct temux_card_stats cards; + struct sbecom_card_param cardp; + struct sbecom_framer_param frp; + } u; + } arg; - if (!capable (CAP_SYS_ADMIN)) - return -EPERM; - if (cmd != SIOCDEVPRIVATE + 15) - return -EINVAL; - if (!(ci = get_ci_by_dev (ndev))) - return -EINVAL; - if (ci->state != C_RUNNING) - return -ENODEV; - if (copy_from_user (&iocmd, ifr->ifr_data, sizeof (iocmd))) - return -EFAULT; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (cmd != SIOCDEVPRIVATE + 15) + return -EINVAL; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + if (ci->state != C_RUNNING) + return -ENODEV; + if (copy_from_user(&iocmd, ifr->ifr_data, sizeof(iocmd))) + return -EFAULT; #if 0 - if (copy_from_user (&len, ifr->ifr_data + sizeof (iocmd), sizeof (len))) - return -EFAULT; + if (copy_from_user(&len, ifr->ifr_data + sizeof(iocmd), sizeof(len))) + return -EFAULT; #endif #if 0 - pr_info("c4_ioctl: iocmd %x, dir %x type %x nr %x iolen %d.\n", iocmd, - _IOC_DIR (iocmd), _IOC_TYPE (iocmd), _IOC_NR (iocmd), - _IOC_SIZE (iocmd)); + pr_info("c4_ioctl: iocmd %x, dir %x type %x nr %x iolen %d.\n", iocmd, + _IOC_DIR(iocmd), _IOC_TYPE(iocmd), _IOC_NR(iocmd), + _IOC_SIZE(iocmd)); #endif - iolen = _IOC_SIZE (iocmd); - if (iolen > sizeof(arg)) - return -EFAULT; - data = ifr->ifr_data + sizeof (iocmd); - if (copy_from_user (&arg, data, iolen)) - return -EFAULT; + iolen = _IOC_SIZE(iocmd); + if (iolen > sizeof(arg)) + return -EFAULT; + data = ifr->ifr_data + sizeof(iocmd); + if (copy_from_user(&arg, data, iolen)) + return -EFAULT; - ret = 0; - switch (iocmd) - { - case SBE_IOC_PORT_GET: - //pr_info(">> SBE_IOC_PORT_GET Ioctl...\n"); - ret = do_get_port (ndev, data); - break; - case SBE_IOC_PORT_SET: - //pr_info(">> SBE_IOC_PORT_SET Ioctl...\n"); - ret = do_set_port (ndev, data); - break; - case SBE_IOC_CHAN_GET: - //pr_info(">> SBE_IOC_CHAN_GET Ioctl...\n"); - ret = do_get_chan (ndev, data); - break; - case SBE_IOC_CHAN_SET: - //pr_info(">> SBE_IOC_CHAN_SET Ioctl...\n"); - ret = do_set_chan (ndev, data); - break; - case C4_DEL_CHAN: - //pr_info(">> C4_DEL_CHAN Ioctl...\n"); - ret = do_del_chan (ndev, data); - break; - case SBE_IOC_CHAN_NEW: - ret = do_create_chan (ndev, data); - break; - case SBE_IOC_CHAN_GET_STAT: - ret = do_get_chan_stats (ndev, data); - break; - case SBE_IOC_LOGLEVEL: - ret = do_set_loglevel (ndev, data); - break; - case SBE_IOC_RESET_DEV: - ret = do_reset (ndev, data); - break; - case SBE_IOC_CHAN_DEL_STAT: - ret = do_reset_chan_stats (ndev, data); - break; - case C4_LOOP_PORT: - ret = do_port_loop (ndev, data); - break; - case C4_RW_FRMR: - ret = do_framer_rw (ndev, data); - break; - case C4_RW_MSYC: - ret = do_musycc_rw (ndev, data); - break; - case C4_RW_PLD: - ret = do_pld_rw (ndev, data); - break; - case SBE_IOC_IID_GET: - ret = (iolen == sizeof (struct sbe_iid_info)) ? c4_get_iidinfo (ci, &arg.u.iip) : -EFAULT; - if (ret == 0) /* no error, copy data */ - if (copy_to_user (data, &arg, iolen)) - return -EFAULT; - break; - default: - //pr_info(">> c4_ioctl: EINVAL - unknown iocmd <%x>\n", iocmd); - ret = -EINVAL; - break; - } - return mkret (ret); + ret = 0; + switch (iocmd) { + case SBE_IOC_PORT_GET: + ret = do_get_port(ndev, data); + break; + case SBE_IOC_PORT_SET: + ret = do_set_port(ndev, data); + break; + case SBE_IOC_CHAN_GET: + ret = do_get_chan(ndev, data); + break; + case SBE_IOC_CHAN_SET: + ret = do_set_chan(ndev, data); + break; + case C4_DEL_CHAN: + ret = do_del_chan(ndev, data); + break; + case SBE_IOC_CHAN_NEW: + ret = do_create_chan(ndev, data); + break; + case SBE_IOC_CHAN_GET_STAT: + ret = do_get_chan_stats(ndev, data); + break; + case SBE_IOC_LOGLEVEL: + ret = do_set_loglevel(ndev, data); + break; + case SBE_IOC_RESET_DEV: + ret = do_reset(ndev, data); + break; + case SBE_IOC_CHAN_DEL_STAT: + ret = do_reset_chan_stats(ndev, data); + break; + case C4_LOOP_PORT: + ret = do_port_loop(ndev, data); + break; + case C4_RW_FRMR: + ret = do_framer_rw(ndev, data); + break; + case C4_RW_MSYC: + ret = do_musycc_rw(ndev, data); + break; + case C4_RW_PLD: + ret = do_pld_rw(ndev, data); + break; + case SBE_IOC_IID_GET: + ret = (iolen == sizeof(struct sbe_iid_info)) ? + c4_get_iidinfo(ci, &arg.u.iip) : -EFAULT; + if (ret == 0) /* no error, copy data */ + if (copy_to_user(data, &arg, iolen)) + return -EFAULT; + break; + default: + ret = -EINVAL; + break; + } + return ret; } static const struct net_device_ops c4_ops = { - .ndo_open = void_open, - .ndo_start_xmit = c4_linux_xmit, - .ndo_do_ioctl = c4_ioctl, + .ndo_open = void_open, + .ndo_start_xmit = c4_linux_xmit, + .ndo_do_ioctl = c4_ioctl, }; static void c4_setup(struct net_device *dev) { - dev->type = ARPHRD_VOID; - dev->netdev_ops = &c4_ops; + dev->type = ARPHRD_VOID; + dev->netdev_ops = &c4_ops; } struct net_device *__init -c4_add_dev (hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, - int irq0, int irq1) +c4_add_dev(hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, + int irq0, int irq1) { - struct net_device *ndev; - ci_t *ci; + struct net_device *ndev; + ci_t *ci; - ndev = alloc_netdev(sizeof(ci_t), SBE_IFACETMPL, c4_setup); - if (!ndev) - { - pr_warning("%s: no memory for struct net_device !\n", hi->devname); - error_flag = ENOMEM; - return NULL; - } - ci = (ci_t *)(netdev_priv(ndev)); - ndev->irq = irq0; + ndev = alloc_netdev(sizeof(ci_t), SBE_IFACETMPL, c4_setup); + if (!ndev) { + pr_warning("%s: no memory for struct net_device !\n", + hi->devname); + error_flag = -ENOMEM; + return NULL; + } + ci = (ci_t *)(netdev_priv(ndev)); + ndev->irq = irq0; - ci->hdw_info = hi; - ci->state = C_INIT; /* mark as hardware not available */ - ci->next = c4_list; - c4_list = ci; - ci->brdno = ci->next ? ci->next->brdno + 1 : 0; + ci->hdw_info = hi; + ci->state = C_INIT; /* mark as hardware not available */ + ci->next = c4_list; + c4_list = ci; + ci->brdno = ci->next ? ci->next->brdno + 1 : 0; - if (!CI) - CI = ci; /* DEBUG, only board 0 usage */ + if (!CI) + CI = ci; /* DEBUG, only board 0 usage */ - strcpy (ci->devname, hi->devname); - ci->release = &pmcc4_OSSI_release[0]; + strcpy(ci->devname, hi->devname); - /* tasklet */ + /* tasklet */ #if defined(SBE_ISR_TASKLET) - tasklet_init (&ci->ci_musycc_isr_tasklet, - (void (*) (unsigned long)) musycc_intr_bh_tasklet, - (unsigned long) ci); + tasklet_init(&ci->ci_musycc_isr_tasklet, + (void (*) (unsigned long)) musycc_intr_bh_tasklet, + (unsigned long) ci); - if (atomic_read (&ci->ci_musycc_isr_tasklet.count) == 0) - tasklet_disable_nosync (&ci->ci_musycc_isr_tasklet); + if (atomic_read(&ci->ci_musycc_isr_tasklet.count) == 0) + tasklet_disable_nosync(&ci->ci_musycc_isr_tasklet); #elif defined(SBE_ISR_IMMEDIATE) - ci->ci_musycc_isr_tq.routine = (void *) (unsigned long) musycc_intr_bh_tasklet; - ci->ci_musycc_isr_tq.data = ci; + ci->ci_musycc_isr_tq.routine = (void *)(unsigned long)musycc_intr_bh_tasklet; + ci->ci_musycc_isr_tq.data = ci; #endif - if (register_netdev (ndev) || - (c4_init (ci, (u_char *) f0, (u_char *) f1) != SBE_DRVR_SUCCESS)) - { - OS_kfree (netdev_priv(ndev)); - OS_kfree (ndev); - error_flag = ENODEV; - return NULL; - } - /************************************************************* - * int request_irq(unsigned int irq, - * void (*handler)(int, void *, struct pt_regs *), - * unsigned long flags, const char *dev_name, void *dev_id); - * wherein: - * irq -> The interrupt number that is being requested. - * handler -> Pointer to handling function being installed. - * flags -> A bit mask of options related to interrupt management. - * dev_name -> String used in /proc/interrupts to show owner of interrupt. - * dev_id -> Pointer (for shared interrupt lines) to point to its own - * private data area (to identify which device is interrupting). - * - * extern void free_irq(unsigned int irq, void *dev_id); - **************************************************************/ + if (register_netdev(ndev) || + (c4_init(ci, (u_char *) f0, (u_char *) f1) != SBE_DRVR_SUCCESS)) { + OS_kfree(netdev_priv(ndev)); + OS_kfree(ndev); + error_flag = -ENODEV; + return NULL; + } + /************************************************************* + * int request_irq(unsigned int irq, + * void (*handler)(int, void *, struct pt_regs *), + * unsigned long flags, const char *dev_name, void *dev_id); + * wherein: + * irq -> The interrupt number that is being requested. + * handler -> Pointer to handling function being installed. + * flags -> A bit mask of options related to interrupt management. + * dev_name -> String used in /proc/interrupts to show owner of interrupt. + * dev_id -> Pointer (for shared interrupt lines) to point to its own + * private data area (to identify which device is interrupting). + * + * extern void free_irq(unsigned int irq, void *dev_id); + **************************************************************/ - if (request_irq (irq0, &c4_linux_interrupt, - IRQF_SHARED, - ndev->name, ndev)) - { - pr_warning("%s: MUSYCC could not get irq: %d\n", ndev->name, irq0); - unregister_netdev (ndev); - OS_kfree (netdev_priv(ndev)); - OS_kfree (ndev); - error_flag = EIO; - return NULL; - } + if (request_irq(irq0, &c4_linux_interrupt, + IRQF_SHARED, + ndev->name, ndev)) { + pr_warning("%s: MUSYCC could not get irq: %d\n", + ndev->name, irq0); + unregister_netdev(ndev); + OS_kfree(netdev_priv(ndev)); + OS_kfree(ndev); + error_flag = -EIO; + return NULL; + } #ifdef CONFIG_SBE_PMCC4_NCOMM - if (request_irq (irq1, &c4_ebus_interrupt, IRQF_SHARED, ndev->name, ndev)) - { - pr_warning("%s: EBUS could not get irq: %d\n", hi->devname, irq1); - unregister_netdev (ndev); - free_irq (irq0, ndev); - OS_kfree (netdev_priv(ndev)); - OS_kfree (ndev); - error_flag = EIO; - return NULL; - } + if (request_irq(irq1, &c4_ebus_interrupt, IRQF_SHARED, ndev->name, ndev)) { + pr_warning("%s: EBUS could not get irq: %d\n", hi->devname, irq1); + unregister_netdev(ndev); + free_irq(irq0, ndev); + OS_kfree(netdev_priv(ndev)); + OS_kfree(ndev); + error_flag = -EIO; + return NULL; + } #endif - /* setup board identification information */ + /* setup board identification information */ - { - u_int32_t tmp; + { + u_int32_t tmp; - hdw_sn_get (hi, brdno); /* also sets PROM format type (promfmt) - * for later usage */ + /* also sets PROM format type (promfmt) for later usage */ + hdw_sn_get(hi, brdno); - switch (hi->promfmt) - { - case PROM_FORMAT_TYPE1: - memcpy (ndev->dev_addr, (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); - memcpy (&tmp, (FLD_TYPE1 *) (hi->mfg_info.pft1.Id), 4); /* unaligned data - * acquisition */ - ci->brd_id = cpu_to_be32 (tmp); - break; - case PROM_FORMAT_TYPE2: - memcpy (ndev->dev_addr, (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); - memcpy (&tmp, (FLD_TYPE2 *) (hi->mfg_info.pft2.Id), 4); /* unaligned data - * acquisition */ - ci->brd_id = cpu_to_be32 (tmp); - break; - default: - ci->brd_id = 0; - memset (ndev->dev_addr, 0, 6); - break; - } + switch (hi->promfmt) { + case PROM_FORMAT_TYPE1: + memcpy(ndev->dev_addr, + (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); + /* unaligned data acquisition */ + memcpy(&tmp, (FLD_TYPE1 *) (hi->mfg_info.pft1.Id), 4); + ci->brd_id = cpu_to_be32(tmp); + break; + case PROM_FORMAT_TYPE2: + memcpy(ndev->dev_addr, + (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); + /* unaligned data acquisition */ + memcpy(&tmp, (FLD_TYPE2 *) (hi->mfg_info.pft2.Id), 4); + ci->brd_id = cpu_to_be32(tmp); + break; + default: + ci->brd_id = 0; + memset(ndev->dev_addr, 0, 6); + break; + } #if 1 - sbeid_set_hdwbid (ci); /* requires bid to be preset */ + /* requires bid to be preset */ + sbeid_set_hdwbid(ci); #else - sbeid_set_bdtype (ci); /* requires hdw_bid to be preset */ + /* requires hdw_bid to be preset */ + sbeid_set_bdtype(ci); #endif - - } + } #ifdef CONFIG_PROC_FS - sbecom_proc_brd_init (ci); + sbecom_proc_brd_init(ci); #endif #if defined(SBE_ISR_TASKLET) - tasklet_enable (&ci->ci_musycc_isr_tasklet); + tasklet_enable(&ci->ci_musycc_isr_tasklet); #endif - - if ((error_flag = c4_init2 (ci)) != SBE_DRVR_SUCCESS) - { + error_flag = c4_init2(ci); + if (error_flag != SBE_DRVR_SUCCESS) { #ifdef CONFIG_PROC_FS - sbecom_proc_brd_cleanup (ci); + sbecom_proc_brd_cleanup(ci); #endif - unregister_netdev (ndev); - free_irq (irq1, ndev); - free_irq (irq0, ndev); - OS_kfree (netdev_priv(ndev)); - OS_kfree (ndev); - return NULL; /* failure, error_flag is set */ - } - return ndev; + unregister_netdev(ndev); + free_irq(irq1, ndev); + free_irq(irq0, ndev); + OS_kfree(netdev_priv(ndev)); + OS_kfree(ndev); + /* failure, error_flag is set */ + return NULL; + } + return ndev; } static int __init -c4_mod_init (void) +c4_mod_init(void) { - int rtn; + int rtn; - pr_warning("%s\n", pmcc4_OSSI_release); - if ((rtn = c4hw_attach_all ())) - return -rtn; /* installation failure - see system log */ + rtn = c4hw_attach_all(); + if (rtn) + return -rtn; /* installation failure - see system log */ - /* housekeeping notifications */ - if (cxt1e1_log_level != log_level_default) - pr_info("NOTE: driver parameter changed from default %d to %d.\n", - log_level_default, cxt1e1_log_level); - if (cxt1e1_max_mru != max_mru_default) - pr_info("NOTE: driver parameter changed from default %d to %d.\n", - max_mru_default, cxt1e1_max_mru); - if (cxt1e1_max_mtu != max_mtu_default) - pr_info("NOTE: driver parameter changed from default %d to %d.\n", - max_mtu_default, cxt1e1_max_mtu); - if (max_rxdesc_used != max_rxdesc_default) - { - if (max_rxdesc_used > 2000) - max_rxdesc_used = 2000; /* out-of-bounds reset */ - pr_info("NOTE: driver parameter changed from default %d to %d.\n", - max_rxdesc_default, max_rxdesc_used); - } - if (max_txdesc_used != max_txdesc_default) - { - if (max_txdesc_used > 1000) - max_txdesc_used = 1000; /* out-of-bounds reset */ - pr_info("NOTE: driver parameter changed from default %d to %d.\n", - max_txdesc_default, max_txdesc_used); - } - return 0; /* installation success */ + /* housekeeping notifications */ + if (cxt1e1_log_level != log_level_default) + pr_info("NOTE: driver parameter changed from default %d to %d.\n", + log_level_default, cxt1e1_log_level); + if (cxt1e1_max_mru != max_mru_default) + pr_info("NOTE: driver parameter changed from default %d to %d.\n", + max_mru_default, cxt1e1_max_mru); + if (cxt1e1_max_mtu != max_mtu_default) + pr_info("NOTE: driver parameter changed from default %d to %d.\n", + max_mtu_default, cxt1e1_max_mtu); + if (max_rxdesc_used != max_rxdesc_default) { + if (max_rxdesc_used > 2000) + max_rxdesc_used = 2000; /* out-of-bounds reset */ + pr_info("NOTE: driver parameter changed from default %d to %d.\n", + max_rxdesc_default, max_rxdesc_used); + } + if (max_txdesc_used != max_txdesc_default) { + if (max_txdesc_used > 1000) + max_txdesc_used = 1000; /* out-of-bounds reset */ + pr_info("NOTE: driver parameter changed from default %d to %d.\n", + max_txdesc_default, max_txdesc_used); + } + return 0; /* installation success */ } @@ -1140,31 +1117,29 @@ c4_mod_init (void) */ static void __exit -cleanup_hdlc (void) +cleanup_hdlc(void) { - hdw_info_t *hi; - ci_t *ci; - struct net_device *ndev; - int i, j, k; + hdw_info_t *hi; + ci_t *ci; + struct net_device *ndev; + int i, j, k; - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) - { - if (hi->ndev) /* a board has been attached */ - { - ci = (ci_t *)(netdev_priv(hi->ndev)); - for (j = 0; j < ci->max_port; j++) - for (k = 0; k < MUSYCC_NCHANS; k++) - if ((ndev = ci->port[j].chan[k]->user)) - { - do_deluser (ndev, 0); - } - } - } + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->ndev) { /* a board has been attached */ + ci = (ci_t *)(netdev_priv(hi->ndev)); + for (j = 0; j < ci->max_port; j++) + for (k = 0; k < MUSYCC_NCHANS; k++) { + ndev = ci->port[j].chan[k]->user; + if (ndev) + do_deluser(ndev, 0); + } + } + } } static void __exit -c4_mod_remove (void) +c4_mod_remove(void) { cleanup_hdlc(); /* delete any missed channels */ cleanup_devs(); @@ -1173,13 +1148,13 @@ c4_mod_remove (void) pr_info("SBE - driver removed.\n"); } -module_init (c4_mod_init); -module_exit (c4_mod_remove); +module_init(c4_mod_init); +module_exit(c4_mod_remove); -MODULE_AUTHOR ("SBE Technical Services "); -MODULE_DESCRIPTION ("wanPCI-CxT1E1 Generic HDLC WAN Driver module"); +MODULE_AUTHOR("SBE Technical Services "); +MODULE_DESCRIPTION("wanPCI-CxT1E1 Generic HDLC WAN Driver module"); #ifdef MODULE_LICENSE -MODULE_LICENSE ("GPL"); +MODULE_LICENSE("GPL"); #endif /*** End-of-File ***/ diff --git a/drivers/staging/cxt1e1/musycc.c b/drivers/staging/cxt1e1/musycc.c index 7a3a30cd0f7f..7b4f6f2108e3 100644 --- a/drivers/staging/cxt1e1/musycc.c +++ b/drivers/staging/cxt1e1/musycc.c @@ -42,7 +42,6 @@ static unsigned int max_bh = 0; /* global driver variables */ extern ci_t *c4_list; extern int drvr_state; -extern int cxt1e1_log_level; extern int cxt1e1_max_mru; extern int cxt1e1_max_mtu; @@ -217,7 +216,8 @@ musycc_dump_ring(ci_t *ci, unsigned int chan) max_intcnt = 0; /* reset counter */ } - if (!(ch = sd_find_chan(dummy, chan))) { + ch = sd_find_chan(dummy, chan); + if (!ch) { pr_info(">> musycc_dump_ring: channel %d not up.\n", chan); return ENOENT; } @@ -1044,17 +1044,19 @@ musycc_bh_rx_eom(mpi_t *pi, int gchan) #endif /*** CONFIG_SBE_WAN256T3_NCOMM ***/ { - if ((m2 = OS_mem_token_alloc(cxt1e1_max_mru))) { - /* substitute the mbuf+cluster */ - md->mem_token = m2; - md->data = cpu_to_le32(OS_vtophys(OS_mem_token_data(m2))); + m2 = OS_mem_token_alloc(cxt1e1_max_mru); + if (m2) { + /* substitute the mbuf+cluster */ + md->mem_token = m2; + md->data = cpu_to_le32(OS_vtophys( + OS_mem_token_data(m2))); - /* pass the received mbuf upward */ - sd_recv_consume(m, status & LENGTH_MASK, ch->user); - ch->s.rx_packets++; - ch->s.rx_bytes += status & LENGTH_MASK; + /* pass the received mbuf upward */ + sd_recv_consume(m, status & LENGTH_MASK, ch->user); + ch->s.rx_packets++; + ch->s.rx_bytes += status & LENGTH_MASK; } else - ch->s.rx_dropped++; + ch->s.rx_dropped++; } } else if (error == ERR_FCS) ch->s.rx_crc_errors++; @@ -1545,8 +1547,9 @@ musycc_chan_down(ci_t *dummy, int channum) mch_t *ch; int i, gchan; - if (!(ch = sd_find_chan(dummy, channum))) - return EINVAL; + ch = sd_find_chan(dummy, channum); + if (!ch) + return -EINVAL; pi = ch->up; gchan = ch->gchan; @@ -1589,6 +1592,8 @@ musycc_chan_down(ci_t *dummy, int channum) #endif +#if 0 +/* TODO: determine if these functions will not be needed and can be removed */ int musycc_del_chan(ci_t *ci, int channum) { @@ -1596,7 +1601,8 @@ musycc_del_chan(ci_t *ci, int channum) if ((channum < 0) || (channum >= (MUSYCC_NPORTS * MUSYCC_NCHANS))) /* sanity chk param */ return ECHRNG; - if (!(ch = sd_find_chan(ci, channum))) + ch = sd_find_chan(ci, channum); + if (!ch) return ENOENT; if (ch->state == UP) musycc_chan_down(ci, channum); @@ -1612,12 +1618,14 @@ musycc_del_chan_stats(ci_t *ci, int channum) if (channum < 0 || channum >= (MUSYCC_NPORTS * MUSYCC_NCHANS)) /* sanity chk param */ return ECHRNG; - if (!(ch = sd_find_chan(ci, channum))) + ch = sd_find_chan(ci, channum); + if (!ch) return ENOENT; memset(&ch->s, 0, sizeof(struct sbecom_chan_stats)); return 0; } +#endif int @@ -1632,7 +1640,8 @@ musycc_start_xmit(ci_t *ci, int channum, void *mem_token) int txd_need_cnt; u_int32_t len; - if (!(ch = sd_find_chan(ci, channum))) + ch = sd_find_chan(ci, channum); + if (!ch) return -ENOENT; if (ci->state != C_RUNNING) /* full interrupt processing available */ diff --git a/drivers/staging/cxt1e1/ossiRelease.c b/drivers/staging/cxt1e1/ossiRelease.c deleted file mode 100644 index f17a902e95e3..000000000000 --- a/drivers/staging/cxt1e1/ossiRelease.c +++ /dev/null @@ -1,29 +0,0 @@ -/*----------------------------------------------------------------------------- - * ossiRelease.c - - * - * This string will be embedded into the executable and will track the - * release. The embedded string may be displayed using the following: - * - * strings | grep \$Rel - * - * Copyright (C) 2002-2008 One Stop Systems, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * For further information, contact via email: support@onestopsystems.com - * One Stop Systems, Inc. Escondido, California U.S.A. - * - *----------------------------------------------------------------------------- - */ - -char pmcc4_OSSI_release[] = "$Release: PMCC4_3_1B, Copyright (c) 2008 One Stop Systems$"; - -/*** End-of-File ***/ diff --git a/drivers/staging/cxt1e1/pmc93x6_eeprom.c b/drivers/staging/cxt1e1/pmc93x6_eeprom.c index 137b63cb5537..78cc1709ebdb 100644 --- a/drivers/staging/cxt1e1/pmc93x6_eeprom.c +++ b/drivers/staging/cxt1e1/pmc93x6_eeprom.c @@ -90,7 +90,7 @@ static int ByteReverseBuilt = FALSE; *------------------------------------------------------------------------ */ -short mfg_template[sizeof (FLD_TYPE2)] = +static u8 mfg_template[sizeof(FLD_TYPE2)] = { PROM_FORMAT_TYPE2, /* type; */ 0x00, 0x1A, /* length[2]; */ @@ -491,13 +491,11 @@ pmc_init_seeprom (u_int32_t addr, u_int32_t serialNum) PROMFORMAT buffer; /* Memory image of structure */ u_int32_t crc; /* CRC of structure */ time_t createTime; - int i; createTime = get_seconds (); /* use template data */ - for (i = 0; i < sizeof (FLD_TYPE2); ++i) - buffer.bytes[i] = mfg_template[i]; + memcpy(&buffer.fldType2, mfg_template, sizeof(buffer.fldType2)); /* Update serial number field in buffer */ pmcSetBuffValue (&buffer.fldType2.Serial[3], serialNum, 3); diff --git a/drivers/staging/cxt1e1/pmcc4.h b/drivers/staging/cxt1e1/pmcc4.h index 003eb8690190..b4b5e5ad791b 100644 --- a/drivers/staging/cxt1e1/pmcc4.h +++ b/drivers/staging/cxt1e1/pmcc4.h @@ -96,7 +96,6 @@ void sbeid_set_bdtype (ci_t *ci); void sbeid_set_hdwbid (ci_t *ci); u_int32_t sbeCrc (u_int8_t *, u_int32_t, u_int32_t, u_int32_t *); -void VMETRO_TRACE (void *); /* put data into 8 LEDs */ void VMETRO_TRIGGER (ci_t *, int); /* Note: int = 0(default) * thru 15 */ diff --git a/drivers/staging/cxt1e1/pmcc4_drv.c b/drivers/staging/cxt1e1/pmcc4_drv.c index a9d95753be20..621a72926475 100644 --- a/drivers/staging/cxt1e1/pmcc4_drv.c +++ b/drivers/staging/cxt1e1/pmcc4_drv.c @@ -112,12 +112,12 @@ c4_find_chan (int channum) for (portnum = 0; portnum < ci->max_port; portnum++) for (gchan = 0; gchan < MUSYCC_NCHANS; gchan++) { - if ((ch = ci->port[portnum].chan[gchan])) - { - if ((ch->state != UNASSIGNED) && - (ch->channum == channum)) - return ch; - } + ch = ci->port[portnum].chan[gchan]; + if (ch) { + if ((ch->state != UNASSIGNED) && + (ch->channum == channum)) + return ch; + } } return NULL; } @@ -668,8 +668,9 @@ c4_init2 (ci_t *ci) status_t ret; /* PORT POINT: this routine generates first interrupt */ - if ((ret = musycc_init (ci)) != SBE_DRVR_SUCCESS) - return ret; + ret = musycc_init(ci); + if (ret != SBE_DRVR_SUCCESS) + return ret; #if 0 ci->p.framing_type = FRAMING_CBP; @@ -756,7 +757,7 @@ c4_frame_rw (ci_t *ci, struct sbecom_port_param *pp) volatile u_int32_t data; if (pp->portnum >= ci->max_port)/* sanity check */ - return ENXIO; + return -ENXIO; comet = ci->port[pp->portnum].cometbase; data = pci_read_32 ((u_int32_t *) comet + pp->port_mode) & 0xff; @@ -845,7 +846,7 @@ c4_musycc_rw (ci_t *ci, struct c4_musycc_param *mcp) */ portnum = (mcp->offset % 0x6000) / 0x800; if (portnum >= ci->max_port) - return ENXIO; + return -ENXIO; pi = &ci->port[portnum]; if (mcp->offset >= 0x6000) offset += 0x6000; /* put back in MsgCfgDesc address offset */ @@ -894,7 +895,7 @@ status_t c4_get_port (ci_t *ci, int portnum) { if (portnum >= ci->max_port) /* sanity check */ - return ENXIO; + return -ENXIO; SD_SEM_TAKE (&ci->sem_wdbusy, "_wd_"); /* only 1 thru here, per * board */ @@ -915,7 +916,7 @@ c4_set_port (ci_t *ci, int portnum) int i; if (portnum >= ci->max_port) /* sanity check */ - return ENXIO; + return -ENXIO; pi = &ci->port[portnum]; pp = &ci->port[portnum].p; @@ -927,15 +928,15 @@ c4_set_port (ci_t *ci, int portnum) portnum, e1mode, pi->openchans); } if (pi->openchans) - return EBUSY; /* group needs initialization only for + return -EBUSY; /* group needs initialization only for * first channel of a group */ { status_t ret; - if ((ret = c4_wq_port_init (pi))) /* create/init - * workqueue_struct */ - return ret; + ret = c4_wq_port_init(pi); + if (ret) /* create/init workqueue_struct */ + return ret; } init_comet (ci, pi->cometbase, pp->port_mode, 1 /* clockmaster == true */ , pp->portP); @@ -1018,10 +1019,10 @@ c4_new_chan (ci_t *ci, int portnum, int channum, void *user) int gchan; if (c4_find_chan (channum)) /* a new channel shouldn't already exist */ - return EEXIST; + return -EEXIST; if (portnum >= ci->max_port) /* sanity check */ - return ENXIO; + return -ENXIO; pi = &(ci->port[portnum]); /* find any available channel within this port */ @@ -1032,7 +1033,7 @@ c4_new_chan (ci_t *ci, int portnum, int channum, void *user) break; } if (gchan == MUSYCC_NCHANS) /* exhausted table, all were assigned */ - return ENFILE; + return -ENFILE; ch->up = pi; @@ -1055,8 +1056,9 @@ c4_new_chan (ci_t *ci, int portnum, int channum, void *user) { status_t ret; - if ((ret = c4_wk_chan_init (pi, ch))) - return ret; + ret = c4_wk_chan_init(pi, ch); + if (ret) + return ret; } /* save off interface assignments which bound a board */ @@ -1079,8 +1081,10 @@ c4_del_chan (int channum) { mch_t *ch; - if (!(ch = c4_find_chan (channum))) - return ENOENT; + ch = c4_find_chan(channum); + if (!ch) + return -ENOENT; + if (ch->state == UP) musycc_chan_down ((ci_t *) 0, channum); ch->state = UNASSIGNED; @@ -1095,8 +1099,9 @@ c4_del_chan_stats (int channum) { mch_t *ch; - if (!(ch = c4_find_chan (channum))) - return ENOENT; + ch = c4_find_chan(channum); + if (!ch) + return -ENOENT; memset (&ch->s, 0, sizeof (struct sbecom_chan_stats)); return 0; @@ -1109,19 +1114,20 @@ c4_set_chan (int channum, struct sbecom_chan_param *p) mch_t *ch; int i, x = 0; - if (!(ch = c4_find_chan (channum))) - return ENOENT; + ch = c4_find_chan(channum); + if (!ch) + return -ENOENT; #if 1 if (ch->p.card != p->card || ch->p.port != p->port || ch->p.channum != p->channum) - return EINVAL; + return -EINVAL; #endif if (!(ch->up->group_is_set)) { - return EIO; /* out of order, SET_PORT command + return -EIO; /* out of order, SET_PORT command * required prior to first group's * SET_CHAN command */ } @@ -1143,10 +1149,12 @@ c4_set_chan (int channum, struct sbecom_chan_param *p) { status_t ret; - if ((ret = musycc_chan_down ((ci_t *) 0, channum))) - return ret; - if ((ret = c4_chan_up (ch->up->up, channum))) - return ret; + ret = musycc_chan_down((ci_t *)0, channum); + if (ret) + return ret; + ret = c4_chan_up(ch->up->up, channum); + if (ret) + return ret; sd_enable_xmit (ch->user); /* re-enable to catch flow controlled * channel */ } @@ -1159,8 +1167,10 @@ c4_get_chan (int channum, struct sbecom_chan_param *p) { mch_t *ch; - if (!(ch = c4_find_chan (channum))) - return ENOENT; + ch = c4_find_chan(channum); + if (!ch) + return -ENOENT; + *p = ch->p; return 0; } @@ -1170,8 +1180,10 @@ c4_get_chan_stats (int channum, struct sbecom_chan_stats *p) { mch_t *ch; - if (!(ch = c4_find_chan (channum))) - return ENOENT; + ch = c4_find_chan(channum); + if (!ch) + return -ENOENT; + *p = ch->s; p->tx_pending = atomic_read (&ch->tx_pending); return 0; @@ -1240,8 +1252,10 @@ c4_chan_up (ci_t *ci, int channum) u_int32_t tmp; /* for optimizing conversion across BE * platform */ - if (!(ch = c4_find_chan (channum))) - return ENOENT; + ch = c4_find_chan(channum); + if (!ch) + return -ENOENT; + if (ch->state == UP) { if (cxt1e1_log_level >= LOG_MONITOR) @@ -1264,7 +1278,7 @@ c4_chan_up (ci_t *ci, int channum) pr_info("+ ask4 %x, currently %x\n", ch->p.bitmask[i], pi->tsm[i]); } - return EINVAL; + return -EINVAL; } for (j = 0; j < 8; j++) if (ch->p.bitmask[i] & (1 << j)) @@ -1277,7 +1291,7 @@ c4_chan_up (ci_t *ci, int channum) /* if( cxt1e1_log_level >= LOG_WARN) */ pr_info("%s: c4_chan_up[%d] ENOBUFS (no TimeSlots assigned)\n", ci->devname, channum); - return ENOBUFS; /* this should not happen */ + return -ENOBUFS; /* this should not happen */ } addr = c4_fifo_alloc (pi, gchan, &nbuf); ch->state = UP; @@ -1372,12 +1386,13 @@ c4_chan_up (ci_t *ci, int channum) } md->next = cpu_to_le32 (OS_vtophys (md->snext)); - if (!(m = OS_mem_token_alloc (cxt1e1_max_mru))) - { - if (cxt1e1_log_level >= LOG_MONITOR) - pr_info("%s: c4_chan_up[%d] - token alloc failure, size = %d.\n", - ci->devname, channum, cxt1e1_max_mru); - goto errfree; + m = OS_mem_token_alloc(cxt1e1_max_mru); + if (!m) { + if (cxt1e1_log_level >= LOG_MONITOR) + pr_info( + "%s: c4_chan_up[%d] - token alloc failure, size = %d.\n", + ci->devname, channum, cxt1e1_max_mru); + goto errfree; } md->mem_token = m; md->data = cpu_to_le32 (OS_vtophys (OS_mem_token_data (m))); @@ -1454,7 +1469,7 @@ errfree: ch->mdr = NULL; ch->rxd_num = 0; ch->state = DOWN; - return ENOBUFS; + return -ENOBUFS; } /* stop the hardware from servicing & interrupting */ @@ -1533,8 +1548,9 @@ c4_get_iidinfo (ci_t *ci, struct sbe_iid_info *iip) struct net_device *dev; char *np; - if (!(dev = getuserbychan (iip->channum))) - return ENOENT; + dev = getuserbychan(iip->channum); + if (!dev) + return -ENOENT; np = dev->name; strncpy (iip->iname, np, CHNM_STRLEN - 1); diff --git a/drivers/staging/cxt1e1/pmcc4_private.h b/drivers/staging/cxt1e1/pmcc4_private.h index 7edbd4e492e3..eb28f095ff8c 100644 --- a/drivers/staging/cxt1e1/pmcc4_private.h +++ b/drivers/staging/cxt1e1/pmcc4_private.h @@ -213,7 +213,6 @@ struct sbe_card_info struct sbe_card_info *next; u_int32_t *eeprombase; /* mapped address of board's EEPROM */ c4cpld_t *cpldbase; /* mapped address of board's CPLD hardware */ - char *release; /* SBE ID string w/in sbeRelease.c */ void *hdw_info; #ifdef CONFIG_PROC_FS struct proc_dir_entry *dir_dev; diff --git a/drivers/staging/cxt1e1/pmcc4_sysdep.h b/drivers/staging/cxt1e1/pmcc4_sysdep.h index 697f1943670f..2916c2cb13f9 100644 --- a/drivers/staging/cxt1e1/pmcc4_sysdep.h +++ b/drivers/staging/cxt1e1/pmcc4_sysdep.h @@ -60,3 +60,4 @@ void sd_line_is_down (void *user); int sd_queue_stopped (void *user); #endif /*** _INC_PMCC4_SYSDEP_H_ ***/ +extern int cxt1e1_log_level; diff --git a/drivers/staging/cxt1e1/sbeproc.c b/drivers/staging/cxt1e1/sbeproc.c index 353c001d3fbe..840c647fbf41 100644 --- a/drivers/staging/cxt1e1/sbeproc.c +++ b/drivers/staging/cxt1e1/sbeproc.c @@ -72,7 +72,8 @@ static int sbecom_proc_get_sbe_info(struct seq_file *m, void *v) char *spd; struct sbe_brd_info *bip; - if (!(bip = OS_kmalloc(sizeof(struct sbe_brd_info)))) + bip = OS_kmalloc(sizeof(struct sbe_brd_info)); + if (!bip) return -ENOMEM; pr_devel(">> sbecom_proc_get_sbe_info: entered\n"); @@ -150,7 +151,6 @@ static int sbecom_proc_get_sbe_info(struct seq_file *m, void *v) break; } seq_printf(m, "PCI Bus Speed: %s\n", spd); - seq_printf(m, "Release: %s\n", ci->release); #ifdef SBE_PMCC4_ENABLE { diff --git a/drivers/staging/dgap/Makefile b/drivers/staging/dgap/Makefile index 3abe8d2bb748..0063d044ca71 100644 --- a/drivers/staging/dgap/Makefile +++ b/drivers/staging/dgap/Makefile @@ -1,7 +1 @@ obj-$(CONFIG_DGAP) += dgap.o - - -dgap-objs := dgap_driver.o dgap_fep5.o \ - dgap_parse.o dgap_trace.o \ - dgap_tty.o dgap_sysfs.o - diff --git a/drivers/staging/dgap/dgap.c b/drivers/staging/dgap/dgap.c new file mode 100644 index 000000000000..a5fc3c75ed4e --- /dev/null +++ b/drivers/staging/dgap/dgap.c @@ -0,0 +1,7675 @@ +/* + * Copyright 2003 Digi International (www.digi.com) + * Scott H Kilau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! + * + * This is shared code between Digi's CVS archive and the + * Linux Kernel sources. + * Changing the source just for reformatting needlessly breaks + * our CVS diff history. + * + * Send any bug fixes/changes to: Eng.Linux at digi dot com. + * Thank you. + * + */ + +/* + * In the original out of kernel Digi dgap driver, firmware + * loading was done via user land to driver handshaking. + * + * For cards that support a concentrator (port expander), + * I believe the concentrator its self told the card which + * concentrator is actually attached and then that info + * was used to tell user land which concentrator firmware + * image was to be downloaded. I think even the BIOS or + * FEP images required could change with the connection + * of a particular concentrator. + * + * Since I have no access to any of these cards or + * concentrators, I cannot put the correct concentrator + * firmware file names into the firmware_info structure + * as is now done for the BIOS and FEP images. + * + * I think, but am not certain, that the cards supporting + * concentrators will function without them. So support + * of these cards has been left in this driver. + * + * In order to fully support those cards, they would + * either have to be acquired for dissection or maybe + * Digi International could provide some assistance. + */ +#undef DIGI_CONCENTRATORS_SUPPORTED + +#include +#include +#include +#include /* For udelay */ +#include +#include +#include + +#include /* For tasklet and interrupt structs/defines */ +#include +#include +#include +#include +#include /* For read[bwl]/write[bwl] */ + +#include +#include +#include +#include + +#include "dgap.h" + +#define init_MUTEX(sem) sema_init(sem, 1) +#define DECLARE_MUTEX(name) \ + struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Digi International, http://www.digi.com"); +MODULE_DESCRIPTION("Driver for the Digi International EPCA PCI based product line"); +MODULE_SUPPORTED_DEVICE("dgap"); + +/************************************************************************** + * + * protos for this file + * + */ + +static int dgap_start(void); +static void dgap_init_globals(void); +static int dgap_found_board(struct pci_dev *pdev, int id); +static void dgap_cleanup_board(struct board_t *brd); +static void dgap_poll_handler(ulong dummy); +static int dgap_init_pci(void); +static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +static void dgap_remove_one(struct pci_dev *dev); +static int dgap_probe1(struct pci_dev *pdev, int card_type); +static int dgap_do_remap(struct board_t *brd); +static irqreturn_t dgap_intr(int irq, void *voidbrd); + +/* Our function prototypes */ +static int dgap_tty_open(struct tty_struct *tty, struct file *file); +static void dgap_tty_close(struct tty_struct *tty, struct file *file); +static int dgap_block_til_ready(struct tty_struct *tty, struct file *file, + struct channel_t *ch); +static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd, + unsigned long arg); +static int dgap_tty_digigeta(struct tty_struct *tty, + struct digi_t __user *retinfo); +static int dgap_tty_digiseta(struct tty_struct *tty, + struct digi_t __user *new_info); +static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo); +static int dgap_tty_digisetedelay(struct tty_struct *tty, int __user *new_info); +static int dgap_tty_write_room(struct tty_struct *tty); +static int dgap_tty_chars_in_buffer(struct tty_struct *tty); +static void dgap_tty_start(struct tty_struct *tty); +static void dgap_tty_stop(struct tty_struct *tty); +static void dgap_tty_throttle(struct tty_struct *tty); +static void dgap_tty_unthrottle(struct tty_struct *tty); +static void dgap_tty_flush_chars(struct tty_struct *tty); +static void dgap_tty_flush_buffer(struct tty_struct *tty); +static void dgap_tty_hangup(struct tty_struct *tty); +static int dgap_wait_for_drain(struct tty_struct *tty); +static int dgap_set_modem_info(struct tty_struct *tty, unsigned int command, + unsigned int __user *value); +static int dgap_get_modem_info(struct channel_t *ch, + unsigned int __user *value); +static int dgap_tty_digisetcustombaud(struct tty_struct *tty, + int __user *new_info); +static int dgap_tty_digigetcustombaud(struct tty_struct *tty, + int __user *retinfo); +static int dgap_tty_tiocmget(struct tty_struct *tty); +static int dgap_tty_tiocmset(struct tty_struct *tty, unsigned int set, + unsigned int clear); +static int dgap_tty_send_break(struct tty_struct *tty, int msec); +static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout); +static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf, + int count); +static void dgap_tty_set_termios(struct tty_struct *tty, + struct ktermios *old_termios); +static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c); +static void dgap_tty_send_xchar(struct tty_struct *tty, char ch); + +static int dgap_tty_register(struct board_t *brd); +static int dgap_tty_init(struct board_t *); +static void dgap_tty_uninit(struct board_t *); +static void dgap_carrier(struct channel_t *ch); +static void dgap_input(struct channel_t *ch); + +/* + * Our function prototypes from dgap_fep5 + */ +static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds); +static int dgap_event(struct board_t *bd); + +static void dgap_poll_tasklet(unsigned long data); +static void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, + uchar byte2, uint ncmds); +static void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds); +static void dgap_wmove(struct channel_t *ch, char *buf, uint cnt); +static int dgap_param(struct tty_struct *tty); +static void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf, + unsigned char *fbuf, int *len); +static uint dgap_get_custom_baud(struct channel_t *ch); +static void dgap_firmware_reset_port(struct channel_t *ch); + +/* + * Function prototypes from dgap_parse.c. + */ +static int dgap_gettok(char **in, struct cnode *p); +static char *dgap_getword(char **in); +static char *dgap_savestring(char *s); +static struct cnode *dgap_newnode(int t); +static int dgap_checknode(struct cnode *p); +static void dgap_err(char *s); + +/* + * Function prototypes from dgap_sysfs.h + */ +struct board_t; +struct channel_t; +struct un_t; +struct pci_driver; +struct class_device; + +static void dgap_create_ports_sysfiles(struct board_t *bd); +static void dgap_remove_ports_sysfiles(struct board_t *bd); + +static int dgap_create_driver_sysfiles(struct pci_driver *); +static void dgap_remove_driver_sysfiles(struct pci_driver *); + +static void dgap_create_tty_sysfs(struct un_t *un, struct device *c); +static void dgap_remove_tty_sysfs(struct device *c); + +/* + * Function prototypes from dgap_parse.h + */ +static int dgap_parsefile(char **in, int Remove); +static struct cnode *dgap_find_config(int type, int bus, int slot); +static uint dgap_config_get_num_prts(struct board_t *bd); +static char *dgap_create_config_string(struct board_t *bd, char *string); +static uint dgap_config_get_useintr(struct board_t *bd); +static uint dgap_config_get_altpin(struct board_t *bd); + +static int dgap_ms_sleep(ulong ms); +static void dgap_do_bios_load(struct board_t *brd, const uchar *ubios, int len); +static void dgap_do_fep_load(struct board_t *brd, const uchar *ufep, int len); +#ifdef DIGI_CONCENTRATORS_SUPPORTED +static void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len); +#endif +static int dgap_after_config_loaded(int board); +static int dgap_finalize_board_init(struct board_t *brd); + +static void dgap_get_vpd(struct board_t *brd); +static void dgap_do_reset_board(struct board_t *brd); +static int dgap_do_wait_for_bios(struct board_t *brd); +static int dgap_do_wait_for_fep(struct board_t *brd); +static int dgap_tty_register_ports(struct board_t *brd); +static int dgap_firmware_load(struct pci_dev *pdev, int card_type); + +/* Driver unload function */ +static void dgap_cleanup_module(void); + +module_exit(dgap_cleanup_module); + +/* + * File operations permitted on Control/Management major. + */ +static const struct file_operations DgapBoardFops = { + .owner = THIS_MODULE, +}; + +/* + * Globals + */ +static uint dgap_NumBoards; +static struct board_t *dgap_Board[MAXBOARDS]; +static ulong dgap_poll_counter; +static char *dgap_config_buf; +static int dgap_driver_state = DRIVER_INITIALIZED; +DEFINE_SPINLOCK(dgap_dl_lock); +static wait_queue_head_t dgap_dl_wait; +static int dgap_dl_action; +static int dgap_poll_tick = 20; /* Poll interval - 20 ms */ + +/* + * Static vars. + */ +static struct class *dgap_class; + +static struct board_t *dgap_BoardsByMajor[256]; +static uint dgap_count = 500; + +/* + * Poller stuff + */ +DEFINE_SPINLOCK(dgap_poll_lock); /* Poll scheduling lock */ +static ulong dgap_poll_time; /* Time of next poll */ +static uint dgap_poll_stop; /* Used to tell poller to stop */ +static struct timer_list dgap_poll_timer; + +/* + SUPPORTED PRODUCTS + + Card Model Number of Ports Interface + ---------------------------------------------------------------- + Acceleport Xem 4 - 64 (EIA232 & EIA422) + Acceleport Xr 4 & 8 (EIA232) + Acceleport Xr 920 4 & 8 (EIA232) + Acceleport C/X 8 - 128 (EIA232) + Acceleport EPC/X 8 - 224 (EIA232) + Acceleport Xr/422 4 & 8 (EIA422) + Acceleport 2r/920 2 (EIA232) + Acceleport 4r/920 4 (EIA232) + Acceleport 8r/920 8 (EIA232) + + IBM 8-Port Asynchronous PCI Adapter (EIA232) + IBM 128-Port Asynchronous PCI Adapter (EIA232 & EIA422) +*/ + +static struct pci_device_id dgap_pci_tbl[] = { + { DIGI_VID, PCI_DEV_XEM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { DIGI_VID, PCI_DEV_CX_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, + { DIGI_VID, PCI_DEV_CX_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, + { DIGI_VID, PCI_DEV_EPCJ_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, + { DIGI_VID, PCI_DEV_920_2_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, + { DIGI_VID, PCI_DEV_920_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, + { DIGI_VID, PCI_DEV_920_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, + { DIGI_VID, PCI_DEV_XR_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, + { DIGI_VID, PCI_DEV_XRJ_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, + { DIGI_VID, PCI_DEV_XR_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 }, + { DIGI_VID, PCI_DEV_XR_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 }, + { DIGI_VID, PCI_DEV_XR_SAIP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 }, + { DIGI_VID, PCI_DEV_XR_BULL_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 }, + { DIGI_VID, PCI_DEV_920_8_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 }, + { DIGI_VID, PCI_DEV_XEM_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, + {0,} /* 0 terminated list. */ +}; +MODULE_DEVICE_TABLE(pci, dgap_pci_tbl); + +/* + * A generic list of Product names, PCI Vendor ID, and PCI Device ID. + */ +struct board_id { + uint config_type; + uchar *name; + uint maxports; + uint dpatype; +}; + +static struct board_id dgap_Ids[] = { + { PPCM, PCI_DEV_XEM_NAME, 64, (T_PCXM|T_PCLITE|T_PCIBUS) }, + { PCX, PCI_DEV_CX_NAME, 128, (T_CX|T_PCIBUS) }, + { PCX, PCI_DEV_CX_IBM_NAME, 128, (T_CX|T_PCIBUS) }, + { PEPC, PCI_DEV_EPCJ_NAME, 224, (T_EPC|T_PCIBUS) }, + { APORT2_920P, PCI_DEV_920_2_NAME, 2, (T_PCXR|T_PCLITE|T_PCIBUS) }, + { APORT4_920P, PCI_DEV_920_4_NAME, 4, (T_PCXR|T_PCLITE|T_PCIBUS) }, + { APORT8_920P, PCI_DEV_920_8_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) }, + { PAPORT8, PCI_DEV_XR_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) }, + { PAPORT8, PCI_DEV_XRJ_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) }, + { PAPORT8, PCI_DEV_XR_422_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) }, + { PAPORT8, PCI_DEV_XR_IBM_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) }, + { PAPORT8, PCI_DEV_XR_SAIP_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) }, + { PAPORT8, PCI_DEV_XR_BULL_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) }, + { APORT8_920P, PCI_DEV_920_8_HP_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) }, + { PPCM, PCI_DEV_XEM_HP_NAME, 64, (T_PCXM|T_PCLITE|T_PCIBUS) }, + {0,} /* 0 terminated list. */ +}; + +static struct pci_driver dgap_driver = { + .name = "dgap", + .probe = dgap_init_one, + .id_table = dgap_pci_tbl, + .remove = dgap_remove_one, +}; + +struct firmware_info { + uchar *conf_name; /* dgap.conf */ + uchar *bios_name; /* BIOS filename */ + uchar *fep_name; /* FEP filename */ + uchar *con_name; /* Concentrator filename FIXME*/ + int num; /* sequence number */ +}; + +/* + * Firmware - BIOS, FEP, and CONC filenames + */ +static struct firmware_info fw_info[] = { + { "dgap/dgap.conf", "dgap/sxbios.bin", "dgap/sxfep.bin", 0, 0 }, + { "dgap/dgap.conf", "dgap/cxpbios.bin", "dgap/cxpfep.bin", 0, 1 }, + { "dgap/dgap.conf", "dgap/cxpbios.bin", "dgap/cxpfep.bin", 0, 2 }, + { "dgap/dgap.conf", "dgap/pcibios.bin", "dgap/pcifep.bin", 0, 3 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 4 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 5 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 6 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 7 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 8 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 9 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 10 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 11 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 12 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 13 }, + { "dgap/dgap.conf", "dgap/sxbios.bin", "dgap/sxfep.bin", 0, 14 }, + {0,} +}; + +/* + * Default transparent print information. + */ +static struct digi_t dgap_digi_init = { + .digi_flags = DIGI_COOK, /* Flags */ + .digi_maxcps = 100, /* Max CPS */ + .digi_maxchar = 50, /* Max chars in print queue */ + .digi_bufsize = 100, /* Printer buffer size */ + .digi_onlen = 4, /* size of printer on string */ + .digi_offlen = 4, /* size of printer off string */ + .digi_onstr = "\033[5i", /* ANSI printer on string ] */ + .digi_offstr = "\033[4i", /* ANSI printer off string ] */ + .digi_term = "ansi" /* default terminal type */ +}; + +/* + * Define a local default termios struct. All ports will be created + * with this termios initially. + * + * This defines a raw port at 9600 baud, 8 data bits, no parity, + * 1 stop bit. + */ + +static struct ktermios DgapDefaultTermios = { + .c_iflag = (DEFAULT_IFLAGS), /* iflags */ + .c_oflag = (DEFAULT_OFLAGS), /* oflags */ + .c_cflag = (DEFAULT_CFLAGS), /* cflags */ + .c_lflag = (DEFAULT_LFLAGS), /* lflags */ + .c_cc = INIT_C_CC, + .c_line = 0, +}; + +static const struct tty_operations dgap_tty_ops = { + .open = dgap_tty_open, + .close = dgap_tty_close, + .write = dgap_tty_write, + .write_room = dgap_tty_write_room, + .flush_buffer = dgap_tty_flush_buffer, + .chars_in_buffer = dgap_tty_chars_in_buffer, + .flush_chars = dgap_tty_flush_chars, + .ioctl = dgap_tty_ioctl, + .set_termios = dgap_tty_set_termios, + .stop = dgap_tty_stop, + .start = dgap_tty_start, + .throttle = dgap_tty_throttle, + .unthrottle = dgap_tty_unthrottle, + .hangup = dgap_tty_hangup, + .put_char = dgap_tty_put_char, + .tiocmget = dgap_tty_tiocmget, + .tiocmset = dgap_tty_tiocmset, + .break_ctl = dgap_tty_send_break, + .wait_until_sent = dgap_tty_wait_until_sent, + .send_xchar = dgap_tty_send_xchar +}; + +/* + * Our needed internal static variables from dgap_parse.c + */ +static struct cnode dgap_head; +#define MAXCWORD 200 +static char dgap_cword[MAXCWORD]; + +struct toklist { + int token; + char *string; +}; + +static struct toklist dgap_tlist[] = { + { BEGIN, "config_begin" }, + { END, "config_end" }, + { BOARD, "board" }, + { PCX, "Digi_AccelePort_C/X_PCI" }, + { PEPC, "Digi_AccelePort_EPC/X_PCI" }, + { PPCM, "Digi_AccelePort_Xem_PCI" }, + { APORT2_920P, "Digi_AccelePort_2r_920_PCI" }, + { APORT4_920P, "Digi_AccelePort_4r_920_PCI" }, + { APORT8_920P, "Digi_AccelePort_8r_920_PCI" }, + { PAPORT4, "Digi_AccelePort_4r_PCI(EIA-232/RS-422)" }, + { PAPORT8, "Digi_AccelePort_8r_PCI(EIA-232/RS-422)" }, + { IO, "io" }, + { PCIINFO, "pciinfo" }, + { LINE, "line" }, + { CONC, "conc" }, + { CONC, "concentrator" }, + { CX, "cx" }, + { CX, "ccon" }, + { EPC, "epccon" }, + { EPC, "epc" }, + { MOD, "module" }, + { ID, "id" }, + { STARTO, "start" }, + { SPEED, "speed" }, + { CABLE, "cable" }, + { CONNECT, "connect" }, + { METHOD, "method" }, + { STATUS, "status" }, + { CUSTOM, "Custom" }, + { BASIC, "Basic" }, + { MEM, "mem" }, + { MEM, "memory" }, + { PORTS, "ports" }, + { MODEM, "modem" }, + { NPORTS, "nports" }, + { TTYN, "ttyname" }, + { CU, "cuname" }, + { PRINT, "prname" }, + { CMAJOR, "major" }, + { ALTPIN, "altpin" }, + { USEINTR, "useintr" }, + { TTSIZ, "ttysize" }, + { CHSIZ, "chsize" }, + { BSSIZ, "boardsize" }, + { UNTSIZ, "schedsize" }, + { F2SIZ, "f2200size" }, + { VPSIZ, "vpixsize" }, + { 0, NULL } +}; + +/************************************************************************ + * + * Driver load/unload functions + * + ************************************************************************/ + +/* + * init_module() + * + * Module load. This is where it all starts. + */ +static int dgap_init_module(void) +{ + int rc = 0; + + pr_info("%s, Digi International Part Number %s\n", DG_NAME, DG_PART); + + rc = dgap_start(); + if (rc) + return rc; + + rc = dgap_init_pci(); + if (rc) + goto err_cleanup; + + rc = dgap_create_driver_sysfiles(&dgap_driver); + if (rc) + goto err_cleanup; + + dgap_driver_state = DRIVER_READY; + + return 0; + +err_cleanup: + + dgap_cleanup_module(); + + return rc; +} +module_init(dgap_init_module); + +/* + * Start of driver. + */ +static int dgap_start(void) +{ + int rc = 0; + unsigned long flags; + struct device *device; + + /* + * make sure that the globals are + * init'd before we do anything else + */ + dgap_init_globals(); + + dgap_NumBoards = 0; + + pr_info("For the tools package please visit http://www.digi.com\n"); + + /* + * Register our base character device into the kernel. + */ + + /* + * Register management/dpa devices + */ + rc = register_chrdev(DIGI_DGAP_MAJOR, "dgap", &DgapBoardFops); + if (rc < 0) + return rc; + + dgap_class = class_create(THIS_MODULE, "dgap_mgmt"); + if (IS_ERR(dgap_class)) { + rc = PTR_ERR(dgap_class); + goto failed_class; + } + + device = device_create(dgap_class, NULL, + MKDEV(DIGI_DGAP_MAJOR, 0), + NULL, "dgap_mgmt"); + if (IS_ERR(device)) { + rc = PTR_ERR(device); + goto failed_device; + } + + /* Start the poller */ + spin_lock_irqsave(&dgap_poll_lock, flags); + init_timer(&dgap_poll_timer); + dgap_poll_timer.function = dgap_poll_handler; + dgap_poll_timer.data = 0; + dgap_poll_time = jiffies + dgap_jiffies_from_ms(dgap_poll_tick); + dgap_poll_timer.expires = dgap_poll_time; + spin_unlock_irqrestore(&dgap_poll_lock, flags); + + add_timer(&dgap_poll_timer); + + return rc; + +failed_device: + class_destroy(dgap_class); +failed_class: + unregister_chrdev(DIGI_DGAP_MAJOR, "dgap"); + return rc; +} + +/* + * Register pci driver, and return how many boards we have. + */ +static int dgap_init_pci(void) +{ + return pci_register_driver(&dgap_driver); +} + +/* returns count (>= 0), or negative on error */ +static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int rc; + + /* wake up and enable device */ + rc = pci_enable_device(pdev); + + if (rc < 0) { + rc = -EIO; + } else { + rc = dgap_probe1(pdev, ent->driver_data); + if (rc == 0) { + dgap_NumBoards++; + rc = dgap_firmware_load(pdev, ent->driver_data); + } + } + return rc; +} + +static int dgap_probe1(struct pci_dev *pdev, int card_type) +{ + return dgap_found_board(pdev, card_type); +} + +static void dgap_remove_one(struct pci_dev *dev) +{ + /* Do Nothing */ +} + +/* + * dgap_cleanup_module() + * + * Module unload. This is where it all ends. + */ +static void dgap_cleanup_module(void) +{ + int i; + ulong lock_flags; + + spin_lock_irqsave(&dgap_poll_lock, lock_flags); + dgap_poll_stop = 1; + spin_unlock_irqrestore(&dgap_poll_lock, lock_flags); + + /* Turn off poller right away. */ + del_timer_sync(&dgap_poll_timer); + + dgap_remove_driver_sysfiles(&dgap_driver); + + device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 0)); + class_destroy(dgap_class); + unregister_chrdev(DIGI_DGAP_MAJOR, "dgap"); + + kfree(dgap_config_buf); + + for (i = 0; i < dgap_NumBoards; ++i) { + dgap_remove_ports_sysfiles(dgap_Board[i]); + dgap_tty_uninit(dgap_Board[i]); + dgap_cleanup_board(dgap_Board[i]); + } + + if (dgap_NumBoards) + pci_unregister_driver(&dgap_driver); +} + +/* + * dgap_cleanup_board() + * + * Free all the memory associated with a board + */ +static void dgap_cleanup_board(struct board_t *brd) +{ + int i = 0; + + if (!brd || brd->magic != DGAP_BOARD_MAGIC) + return; + + if (brd->intr_used && brd->irq) + free_irq(brd->irq, brd); + + tasklet_kill(&brd->helper_tasklet); + + if (brd->re_map_port) { + release_mem_region(brd->membase + 0x200000, 0x200000); + iounmap(brd->re_map_port); + brd->re_map_port = NULL; + } + + if (brd->re_map_membase) { + release_mem_region(brd->membase, 0x200000); + iounmap(brd->re_map_membase); + brd->re_map_membase = NULL; + } + + /* Free all allocated channels structs */ + for (i = 0; i < MAXPORTS ; i++) + kfree(brd->channels[i]); + + kfree(brd->flipbuf); + kfree(brd->flipflagbuf); + + dgap_Board[brd->boardnum] = NULL; + + kfree(brd); +} + +/* + * dgap_found_board() + * + * A board has been found, init it. + */ +static int dgap_found_board(struct pci_dev *pdev, int id) +{ + struct board_t *brd; + unsigned int pci_irq; + int i = 0; + + /* get the board structure and prep it */ + brd = kzalloc(sizeof(struct board_t), GFP_KERNEL); + if (!brd) + return -ENOMEM; + + dgap_Board[dgap_NumBoards] = brd; + + /* store the info for the board we've found */ + brd->magic = DGAP_BOARD_MAGIC; + brd->boardnum = dgap_NumBoards; + brd->firstminor = 0; + brd->vendor = dgap_pci_tbl[id].vendor; + brd->device = dgap_pci_tbl[id].device; + brd->pdev = pdev; + brd->pci_bus = pdev->bus->number; + brd->pci_slot = PCI_SLOT(pdev->devfn); + brd->name = dgap_Ids[id].name; + brd->maxports = dgap_Ids[id].maxports; + brd->type = dgap_Ids[id].config_type; + brd->dpatype = dgap_Ids[id].dpatype; + brd->dpastatus = BD_NOFEP; + init_waitqueue_head(&brd->state_wait); + + spin_lock_init(&brd->bd_lock); + + brd->runwait = 0; + brd->inhibit_poller = FALSE; + brd->wait_for_bios = 0; + brd->wait_for_fep = 0; + + for (i = 0; i < MAXPORTS; i++) + brd->channels[i] = NULL; + + /* store which card & revision we have */ + pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &brd->subvendor); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &brd->subdevice); + pci_read_config_byte(pdev, PCI_REVISION_ID, &brd->rev); + + pci_irq = pdev->irq; + brd->irq = pci_irq; + + /* get the PCI Base Address Registers */ + + /* Xr Jupiter and EPC use BAR 2 */ + if (brd->device == PCI_DEV_XRJ_DID || brd->device == PCI_DEV_EPCJ_DID) { + brd->membase = pci_resource_start(pdev, 2); + brd->membase_end = pci_resource_end(pdev, 2); + } + /* Everyone else uses BAR 0 */ + else { + brd->membase = pci_resource_start(pdev, 0); + brd->membase_end = pci_resource_end(pdev, 0); + } + + if (!brd->membase) + return -ENODEV; + + if (brd->membase & 1) + brd->membase &= ~3; + else + brd->membase &= ~15; + + /* + * On the PCI boards, there is no IO space allocated + * The I/O registers will be in the first 3 bytes of the + * upper 2MB of the 4MB memory space. The board memory + * will be mapped into the low 2MB of the 4MB memory space + */ + brd->port = brd->membase + PCI_IO_OFFSET; + brd->port_end = brd->port + PCI_IO_SIZE; + + /* + * Special initialization for non-PLX boards + */ + if (brd->device != PCI_DEV_XRJ_DID && brd->device != PCI_DEV_EPCJ_DID) { + unsigned short cmd; + + pci_write_config_byte(pdev, 0x40, 0); + pci_write_config_byte(pdev, 0x46, 0); + + /* Limit burst length to 2 doubleword transactions */ + pci_write_config_byte(pdev, 0x42, 1); + + /* + * Enable IO and mem if not already done. + * This was needed for support on Itanium. + */ + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pci_write_config_word(pdev, PCI_COMMAND, cmd); + } + + /* init our poll helper tasklet */ + tasklet_init(&brd->helper_tasklet, dgap_poll_tasklet, + (unsigned long) brd); + + i = dgap_do_remap(brd); + if (i) + brd->state = BOARD_FAILED; + + pr_info("dgap: board %d: %s (rev %d), irq %ld, %s\n", + dgap_NumBoards, brd->name, brd->rev, brd->irq, + brd->state ? "NOT READY\0" : "READY\0"); + + return 0; +} + + +static int dgap_finalize_board_init(struct board_t *brd) +{ + int rc; + + if (!brd || brd->magic != DGAP_BOARD_MAGIC) + return -ENODEV; + + brd->use_interrupts = dgap_config_get_useintr(brd); + + /* + * Set up our interrupt handler if we are set to do interrupts. + */ + if (brd->use_interrupts && brd->irq) { + + rc = request_irq(brd->irq, dgap_intr, IRQF_SHARED, "DGAP", brd); + + if (rc) + brd->intr_used = 0; + else + brd->intr_used = 1; + } else { + brd->intr_used = 0; + } + + return 0; +} + +static int dgap_firmware_load(struct pci_dev *pdev, int card_type) +{ + struct board_t *brd = dgap_Board[dgap_NumBoards - 1]; + const struct firmware *fw; + int ret; + + dgap_get_vpd(brd); + dgap_do_reset_board(brd); + + if (fw_info[card_type].conf_name) { + ret = request_firmware(&fw, fw_info[card_type].conf_name, + &pdev->dev); + if (ret) { + pr_err("dgap: config file %s not found\n", + fw_info[card_type].conf_name); + return ret; + } + if (!dgap_config_buf) { + dgap_config_buf = kmalloc(fw->size + 1, GFP_ATOMIC); + if (!dgap_config_buf) { + release_firmware(fw); + return -ENOMEM; + } + } + + memcpy(dgap_config_buf, fw->data, fw->size); + release_firmware(fw); + dgap_config_buf[fw->size + 1] = '\0'; + + if (dgap_parsefile(&dgap_config_buf, TRUE) != 0) + return -EINVAL; + } + + ret = dgap_after_config_loaded(brd->boardnum); + if (ret) + return ret; + /* + * Match this board to a config the user created for us. + */ + brd->bd_config = + dgap_find_config(brd->type, brd->pci_bus, brd->pci_slot); + + /* + * Because the 4 port Xr products share the same PCI ID + * as the 8 port Xr products, if we receive a NULL config + * back, and this is a PAPORT8 board, retry with a + * PAPORT4 attempt as well. + */ + if (brd->type == PAPORT8 && !brd->bd_config) + brd->bd_config = + dgap_find_config(PAPORT4, brd->pci_bus, brd->pci_slot); + + if (!brd->bd_config) { + pr_err("dgap: No valid configuration found\n"); + return -EINVAL; + } + + dgap_tty_register(brd); + dgap_finalize_board_init(brd); + + if (fw_info[card_type].bios_name) { + ret = request_firmware(&fw, fw_info[card_type].bios_name, + &pdev->dev); + if (ret) { + pr_err("dgap: bios file %s not found\n", + fw_info[card_type].bios_name); + return ret; + } + dgap_do_bios_load(brd, fw->data, fw->size); + release_firmware(fw); + + /* Wait for BIOS to test board... */ + if (!dgap_do_wait_for_bios(brd)) + return -ENXIO; + } + + if (fw_info[card_type].fep_name) { + ret = request_firmware(&fw, fw_info[card_type].fep_name, + &pdev->dev); + if (ret) { + pr_err("dgap: fep file %s not found\n", + fw_info[card_type].fep_name); + return ret; + } + dgap_do_fep_load(brd, fw->data, fw->size); + release_firmware(fw); + + /* Wait for FEP to load on board... */ + if (!dgap_do_wait_for_fep(brd)) + return -ENXIO; + } + +#ifdef DIGI_CONCENTRATORS_SUPPORTED + /* + * If this is a CX or EPCX, we need to see if the firmware + * is requesting a concentrator image from us. + */ + if ((bd->type == PCX) || (bd->type == PEPC)) { + chk_addr = (u16 *) (vaddr + DOWNREQ); + /* Nonzero if FEP is requesting concentrator image. */ + check = readw(chk_addr); + vaddr = brd->re_map_membase; + } + + if (fw_info[card_type].con_name && check && vaddr) { + ret = request_firmware(&fw, fw_info[card_type].con_name, + &pdev->dev); + if (ret) { + pr_err("dgap: conc file %s not found\n", + fw_info[card_type].con_name); + return ret; + } + /* Put concentrator firmware loading code here */ + offset = readw((u16 *) (vaddr + DOWNREQ)); + memcpy_toio(offset, fw->data, fw->size); + + dgap_do_conc_load(brd, (char *)fw->data, fw->size) + release_firmware(fw); + } +#endif + /* + * Do tty device initialization. + */ + ret = dgap_tty_init(brd); + if (ret < 0) { + dgap_tty_uninit(brd); + return ret; + } + + ret = dgap_tty_register_ports(brd); + if (ret) + return ret; + + brd->state = BOARD_READY; + brd->dpastatus = BD_RUNNING; + + return 0; +} + +/* + * Remap PCI memory. + */ +static int dgap_do_remap(struct board_t *brd) +{ + if (!brd || brd->magic != DGAP_BOARD_MAGIC) + return -ENXIO; + + if (!request_mem_region(brd->membase, 0x200000, "dgap")) + return -ENOMEM; + + if (!request_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000, + "dgap")) { + release_mem_region(brd->membase, 0x200000); + return -ENOMEM; + } + + brd->re_map_membase = ioremap(brd->membase, 0x200000); + if (!brd->re_map_membase) { + release_mem_region(brd->membase, 0x200000); + release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000); + return -ENOMEM; + } + + brd->re_map_port = ioremap((brd->membase + PCI_IO_OFFSET), 0x200000); + if (!brd->re_map_port) { + release_mem_region(brd->membase, 0x200000); + release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000); + iounmap(brd->re_map_membase); + return -ENOMEM; + } + + return 0; +} + +/***************************************************************************** +* +* Function: +* +* dgap_poll_handler +* +* Author: +* +* Scott H Kilau +* +* Parameters: +* +* dummy -- ignored +* +* Return Values: +* +* none +* +* Description: +* +* As each timer expires, it determines (a) whether the "transmit" +* waiter needs to be woken up, and (b) whether the poller needs to +* be rescheduled. +* +******************************************************************************/ + +static void dgap_poll_handler(ulong dummy) +{ + int i; + struct board_t *brd; + unsigned long lock_flags; + ulong new_time; + + dgap_poll_counter++; + + /* + * Do not start the board state machine until + * driver tells us its up and running, and has + * everything it needs. + */ + if (dgap_driver_state != DRIVER_READY) + goto schedule_poller; + + /* + * If we have just 1 board, or the system is not SMP, + * then use the typical old style poller. + * Otherwise, use our new tasklet based poller, which should + * speed things up for multiple boards. + */ + if ((dgap_NumBoards == 1) || (num_online_cpus() <= 1)) { + for (i = 0; i < dgap_NumBoards; i++) { + + brd = dgap_Board[i]; + + if (brd->state == BOARD_FAILED) + continue; + if (!brd->intr_running) + /* Call the real board poller directly */ + dgap_poll_tasklet((unsigned long) brd); + } + } else { + /* + * Go thru each board, kicking off a + * tasklet for each if needed + */ + for (i = 0; i < dgap_NumBoards; i++) { + brd = dgap_Board[i]; + + /* + * Attempt to grab the board lock. + * + * If we can't get it, no big deal, the next poll + * will get it. Basically, I just really don't want + * to spin in here, because I want to kick off my + * tasklets as fast as I can, and then get out the + * poller. + */ + if (!spin_trylock(&brd->bd_lock)) + continue; + + /* + * If board is in a failed state, don't bother + * scheduling a tasklet + */ + if (brd->state == BOARD_FAILED) { + spin_unlock(&brd->bd_lock); + continue; + } + + /* Schedule a poll helper task */ + if (!brd->intr_running) + tasklet_schedule(&brd->helper_tasklet); + + /* + * Can't do DGAP_UNLOCK here, as we don't have + * lock_flags because we did a trylock above. + */ + spin_unlock(&brd->bd_lock); + } + } + +schedule_poller: + + /* + * Schedule ourself back at the nominal wakeup interval. + */ + spin_lock_irqsave(&dgap_poll_lock, lock_flags); + dgap_poll_time += dgap_jiffies_from_ms(dgap_poll_tick); + + new_time = dgap_poll_time - jiffies; + + if ((ulong) new_time >= 2 * dgap_poll_tick) { + dgap_poll_time = + jiffies + dgap_jiffies_from_ms(dgap_poll_tick); + } + + dgap_poll_timer.function = dgap_poll_handler; + dgap_poll_timer.data = 0; + dgap_poll_timer.expires = dgap_poll_time; + spin_unlock_irqrestore(&dgap_poll_lock, lock_flags); + + if (!dgap_poll_stop) + add_timer(&dgap_poll_timer); +} + +/* + * dgap_intr() + * + * Driver interrupt handler. + */ +static irqreturn_t dgap_intr(int irq, void *voidbrd) +{ + struct board_t *brd = (struct board_t *) voidbrd; + + if (!brd) + return IRQ_NONE; + + /* + * Check to make sure its for us. + */ + if (brd->magic != DGAP_BOARD_MAGIC) + return IRQ_NONE; + + brd->intr_count++; + + /* + * Schedule tasklet to run at a better time. + */ + tasklet_schedule(&brd->helper_tasklet); + return IRQ_HANDLED; +} + +/* + * dgap_init_globals() + * + * This is where we initialize the globals from the static insmod + * configuration variables. These are declared near the head of + * this file. + */ +static void dgap_init_globals(void) +{ + int i = 0; + + for (i = 0; i < MAXBOARDS; i++) + dgap_Board[i] = NULL; + + init_timer(&dgap_poll_timer); + + init_waitqueue_head(&dgap_dl_wait); + dgap_dl_action = 0; +} + +/************************************************************************ + * + * Utility functions + * + ************************************************************************/ + +/* + * dgap_ms_sleep() + * + * Put the driver to sleep for x ms's + * + * Returns 0 if timed out, !0 (showing signal) if interrupted by a signal. + */ +static int dgap_ms_sleep(ulong ms) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((ms * HZ) / 1000); + return signal_pending(current); +} + +/************************************************************************ + * + * TTY Initialization/Cleanup Functions + * + ************************************************************************/ + +/* + * dgap_tty_register() + * + * Init the tty subsystem for this board. + */ +static int dgap_tty_register(struct board_t *brd) +{ + int rc = 0; + + brd->SerialDriver = alloc_tty_driver(MAXPORTS); + + snprintf(brd->SerialName, MAXTTYNAMELEN, "tty_dgap_%d_", brd->boardnum); + brd->SerialDriver->name = brd->SerialName; + brd->SerialDriver->name_base = 0; + brd->SerialDriver->major = 0; + brd->SerialDriver->minor_start = 0; + brd->SerialDriver->type = TTY_DRIVER_TYPE_SERIAL; + brd->SerialDriver->subtype = SERIAL_TYPE_NORMAL; + brd->SerialDriver->init_termios = DgapDefaultTermios; + brd->SerialDriver->driver_name = DRVSTR; + brd->SerialDriver->flags = (TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV | + TTY_DRIVER_HARDWARE_BREAK); + + /* The kernel wants space to store pointers to tty_structs */ + brd->SerialDriver->ttys = + kzalloc(MAXPORTS * sizeof(struct tty_struct *), GFP_KERNEL); + if (!brd->SerialDriver->ttys) + return -ENOMEM; + + /* + * Entry points for driver. Called by the kernel from + * tty_io.c and n_tty.c. + */ + tty_set_operations(brd->SerialDriver, &dgap_tty_ops); + + /* + * If we're doing transparent print, we have to do all of the above + * again, separately so we don't get the LD confused about what major + * we are when we get into the dgap_tty_open() routine. + */ + brd->PrintDriver = alloc_tty_driver(MAXPORTS); + + snprintf(brd->PrintName, MAXTTYNAMELEN, "pr_dgap_%d_", brd->boardnum); + brd->PrintDriver->name = brd->PrintName; + brd->PrintDriver->name_base = 0; + brd->PrintDriver->major = 0; + brd->PrintDriver->minor_start = 0; + brd->PrintDriver->type = TTY_DRIVER_TYPE_SERIAL; + brd->PrintDriver->subtype = SERIAL_TYPE_NORMAL; + brd->PrintDriver->init_termios = DgapDefaultTermios; + brd->PrintDriver->driver_name = DRVSTR; + brd->PrintDriver->flags = (TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV | + TTY_DRIVER_HARDWARE_BREAK); + + /* The kernel wants space to store pointers to tty_structs */ + brd->PrintDriver->ttys = + kzalloc(MAXPORTS * sizeof(struct tty_struct *), GFP_KERNEL); + if (!brd->PrintDriver->ttys) + return -ENOMEM; + + /* + * Entry points for driver. Called by the kernel from + * tty_io.c and n_tty.c. + */ + tty_set_operations(brd->PrintDriver, &dgap_tty_ops); + + if (!brd->dgap_Major_Serial_Registered) { + /* Register tty devices */ + rc = tty_register_driver(brd->SerialDriver); + if (rc < 0) + return rc; + brd->dgap_Major_Serial_Registered = TRUE; + dgap_BoardsByMajor[brd->SerialDriver->major] = brd; + brd->dgap_Serial_Major = brd->SerialDriver->major; + } + + if (!brd->dgap_Major_TransparentPrint_Registered) { + /* Register Transparent Print devices */ + rc = tty_register_driver(brd->PrintDriver); + if (rc < 0) + return rc; + brd->dgap_Major_TransparentPrint_Registered = TRUE; + dgap_BoardsByMajor[brd->PrintDriver->major] = brd; + brd->dgap_TransparentPrint_Major = brd->PrintDriver->major; + } + + return rc; +} + +/* + * dgap_tty_init() + * + * Init the tty subsystem. Called once per board after board has been + * downloaded and init'ed. + */ +static int dgap_tty_init(struct board_t *brd) +{ + int i; + int tlw; + uint true_count = 0; + uchar *vaddr; + uchar modem = 0; + struct channel_t *ch; + struct bs_t *bs; + struct cm_t *cm; + + if (!brd) + return -ENXIO; + + /* + * Initialize board structure elements. + */ + + vaddr = brd->re_map_membase; + true_count = readw((vaddr + NCHAN)); + + brd->nasync = dgap_config_get_num_prts(brd); + + if (!brd->nasync) + brd->nasync = brd->maxports; + + if (brd->nasync > brd->maxports) + brd->nasync = brd->maxports; + + if (true_count != brd->nasync) { + if ((brd->type == PPCM) && (true_count == 64)) { + pr_warn("dgap: %s configured for %d ports, has %d ports.\n", + brd->name, brd->nasync, true_count); + pr_warn("dgap: Please make SURE the EBI cable running from the card\n"); + pr_warn("dgap: to each EM module is plugged into EBI IN!\n"); + } else if ((brd->type == PPCM) && (true_count == 0)) { + pr_warn("dgap: %s configured for %d ports, has %d ports.\n", + brd->name, brd->nasync, true_count); + pr_warn("dgap: Please make SURE the EBI cable running from the card\n"); + pr_warn("dgap: to each EM module is plugged into EBI IN!\n"); + } else + pr_warn("dgap: %s configured for %d ports, has %d ports.\n", + brd->name, brd->nasync, true_count); + + brd->nasync = true_count; + + /* If no ports, don't bother going any further */ + if (!brd->nasync) { + brd->state = BOARD_FAILED; + brd->dpastatus = BD_NOFEP; + return -ENXIO; + } + } + + /* + * Allocate channel memory that might not have been allocated + * when the driver was first loaded. + */ + for (i = 0; i < brd->nasync; i++) { + if (!brd->channels[i]) { + brd->channels[i] = + kzalloc(sizeof(struct channel_t), GFP_ATOMIC); + if (!brd->channels[i]) + return -ENOMEM; + } + } + + ch = brd->channels[0]; + vaddr = brd->re_map_membase; + + bs = (struct bs_t *) ((ulong) vaddr + CHANBUF); + cm = (struct cm_t *) ((ulong) vaddr + CMDBUF); + + brd->bd_bs = bs; + + /* Set up channel variables */ + for (i = 0; i < brd->nasync; i++, ch = brd->channels[i], bs++) { + + if (!brd->channels[i]) + continue; + + spin_lock_init(&ch->ch_lock); + + /* Store all our magic numbers */ + ch->magic = DGAP_CHANNEL_MAGIC; + ch->ch_tun.magic = DGAP_UNIT_MAGIC; + ch->ch_tun.un_type = DGAP_SERIAL; + ch->ch_tun.un_ch = ch; + ch->ch_tun.un_dev = i; + + ch->ch_pun.magic = DGAP_UNIT_MAGIC; + ch->ch_pun.un_type = DGAP_PRINT; + ch->ch_pun.un_ch = ch; + ch->ch_pun.un_dev = i; + + ch->ch_vaddr = vaddr; + ch->ch_bs = bs; + ch->ch_cm = cm; + ch->ch_bd = brd; + ch->ch_portnum = i; + ch->ch_digi = dgap_digi_init; + + /* + * Set up digi dsr and dcd bits based on altpin flag. + */ + if (dgap_config_get_altpin(brd)) { + ch->ch_dsr = DM_CD; + ch->ch_cd = DM_DSR; + ch->ch_digi.digi_flags |= DIGI_ALTPIN; + } else { + ch->ch_cd = DM_CD; + ch->ch_dsr = DM_DSR; + } + + ch->ch_taddr = vaddr + ((ch->ch_bs->tx_seg) << 4); + ch->ch_raddr = vaddr + ((ch->ch_bs->rx_seg) << 4); + ch->ch_tx_win = 0; + ch->ch_rx_win = 0; + ch->ch_tsize = readw(&(ch->ch_bs->tx_max)) + 1; + ch->ch_rsize = readw(&(ch->ch_bs->rx_max)) + 1; + ch->ch_tstart = 0; + ch->ch_rstart = 0; + + /* .25 second delay */ + ch->ch_close_delay = 250; + + /* + * Set queue water marks, interrupt mask, + * and general tty parameters. + */ + tlw = ch->ch_tsize >= 2000 ? ((ch->ch_tsize * 5) / 8) : + ch->ch_tsize / 2; + ch->ch_tlw = tlw; + + dgap_cmdw(ch, STLOW, tlw, 0); + + dgap_cmdw(ch, SRLOW, ch->ch_rsize / 2, 0); + + dgap_cmdw(ch, SRHIGH, 7 * ch->ch_rsize / 8, 0); + + ch->ch_mistat = readb(&(ch->ch_bs->m_stat)); + + init_waitqueue_head(&ch->ch_flags_wait); + init_waitqueue_head(&ch->ch_tun.un_flags_wait); + init_waitqueue_head(&ch->ch_pun.un_flags_wait); + init_waitqueue_head(&ch->ch_sniff_wait); + + /* Turn on all modem interrupts for now */ + modem = (DM_CD | DM_DSR | DM_CTS | DM_RI); + writeb(modem, &(ch->ch_bs->m_int)); + + /* + * Set edelay to 0 if interrupts are turned on, + * otherwise set edelay to the usual 100. + */ + if (brd->intr_used) + writew(0, &(ch->ch_bs->edelay)); + else + writew(100, &(ch->ch_bs->edelay)); + + writeb(1, &(ch->ch_bs->idata)); + } + + return 0; +} + +/* + * dgap_tty_uninit() + * + * Uninitialize the TTY portion of this driver. Free all memory and + * resources. + */ +static void dgap_tty_uninit(struct board_t *brd) +{ + struct device *dev; + int i = 0; + + if (brd->dgap_Major_Serial_Registered) { + dgap_BoardsByMajor[brd->SerialDriver->major] = NULL; + brd->dgap_Serial_Major = 0; + for (i = 0; i < brd->nasync; i++) { + tty_port_destroy(&brd->SerialPorts[i]); + dev = brd->channels[i]->ch_tun.un_sysfs; + dgap_remove_tty_sysfs(dev); + tty_unregister_device(brd->SerialDriver, i); + } + tty_unregister_driver(brd->SerialDriver); + kfree(brd->SerialDriver->ttys); + brd->SerialDriver->ttys = NULL; + put_tty_driver(brd->SerialDriver); + kfree(brd->SerialPorts); + brd->dgap_Major_Serial_Registered = FALSE; + } + + if (brd->dgap_Major_TransparentPrint_Registered) { + dgap_BoardsByMajor[brd->PrintDriver->major] = NULL; + brd->dgap_TransparentPrint_Major = 0; + for (i = 0; i < brd->nasync; i++) { + tty_port_destroy(&brd->PrinterPorts[i]); + dev = brd->channels[i]->ch_pun.un_sysfs; + dgap_remove_tty_sysfs(dev); + tty_unregister_device(brd->PrintDriver, i); + } + tty_unregister_driver(brd->PrintDriver); + kfree(brd->PrintDriver->ttys); + brd->PrintDriver->ttys = NULL; + put_tty_driver(brd->PrintDriver); + kfree(brd->PrinterPorts); + brd->dgap_Major_TransparentPrint_Registered = FALSE; + } +} + +#define TMPBUFLEN (1024) +/* + * dgap_sniff - Dump data out to the "sniff" buffer if the + * proc sniff file is opened... + */ +static void dgap_sniff_nowait_nolock(struct channel_t *ch, uchar *text, + uchar *buf, int len) +{ + struct timeval tv; + int n; + int r; + int nbuf; + int i; + int tmpbuflen; + char tmpbuf[TMPBUFLEN]; + char *p = tmpbuf; + int too_much_data; + + /* Leave if sniff not open */ + if (!(ch->ch_sniff_flags & SNIFF_OPEN)) + return; + + do_gettimeofday(&tv); + + /* Create our header for data dump */ + p += sprintf(p, "<%ld %ld><%s><", tv.tv_sec, tv.tv_usec, text); + tmpbuflen = p - tmpbuf; + + do { + too_much_data = 0; + + for (i = 0; i < len && tmpbuflen < (TMPBUFLEN - 4); i++) { + p += sprintf(p, "%02x ", *buf); + buf++; + tmpbuflen = p - tmpbuf; + } + + if (tmpbuflen < (TMPBUFLEN - 4)) { + if (i > 0) + p += sprintf(p - 1, "%s\n", ">"); + else + p += sprintf(p, "%s\n", ">"); + } else { + too_much_data = 1; + len -= i; + } + + nbuf = strlen(tmpbuf); + p = tmpbuf; + + /* + * Loop while data remains. + */ + while (nbuf > 0 && ch->ch_sniff_buf) { + /* + * Determine the amount of available space left in the + * buffer. If there's none, wait until some appears. + */ + n = (ch->ch_sniff_out - ch->ch_sniff_in - 1) & + SNIFF_MASK; + + /* + * If there is no space left to write to in our sniff + * buffer, we have no choice but to drop the data. + * We *cannot* sleep here waiting for space, because + * this function was probably called by the + * interrupt/timer routines! + */ + if (n == 0) + return; + + /* + * Copy as much data as will fit. + */ + + if (n > nbuf) + n = nbuf; + + r = SNIFF_MAX - ch->ch_sniff_in; + + if (r <= n) { + memcpy(ch->ch_sniff_buf + + ch->ch_sniff_in, p, r); + + n -= r; + ch->ch_sniff_in = 0; + p += r; + nbuf -= r; + } + + memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, n); + + ch->ch_sniff_in += n; + p += n; + nbuf -= n; + + /* + * Wakeup any thread waiting for data + */ + if (ch->ch_sniff_flags & SNIFF_WAIT_DATA) { + ch->ch_sniff_flags &= ~SNIFF_WAIT_DATA; + wake_up_interruptible(&ch->ch_sniff_wait); + } + } + + /* + * If the user sent us too much data to push into our tmpbuf, + * we need to keep looping around on all the data. + */ + if (too_much_data) { + p = tmpbuf; + tmpbuflen = 0; + } + + } while (too_much_data); +} + +/*======================================================================= + * + * dgap_input - Process received data. + * + * ch - Pointer to channel structure. + * + *=======================================================================*/ + +static void dgap_input(struct channel_t *ch) +{ + struct board_t *bd; + struct bs_t *bs; + struct tty_struct *tp; + struct tty_ldisc *ld; + uint rmask; + uint head; + uint tail; + int data_len; + ulong lock_flags; + ulong lock_flags2; + int flip_len; + int len = 0; + int n = 0; + uchar *buf; + uchar tmpchar; + int s = 0; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + tp = ch->ch_tun.un_tty; + + bs = ch->ch_bs; + if (!bs) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + /* + * Figure the number of characters in the buffer. + * Exit immediately if none. + */ + + rmask = ch->ch_rsize - 1; + + head = readw(&(bs->rx_head)); + head &= rmask; + tail = readw(&(bs->rx_tail)); + tail &= rmask; + + data_len = (head - tail) & rmask; + + if (data_len == 0) { + writeb(1, &(bs->idata)); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return; + } + + /* + * If the device is not open, or CREAD is off, flush + * input data and return immediately. + */ + if ((bd->state != BOARD_READY) || !tp || + (tp->magic != TTY_MAGIC) || + !(ch->ch_tun.un_flags & UN_ISOPEN) || + !(tp->termios.c_cflag & CREAD) || + (ch->ch_tun.un_flags & UN_CLOSING)) { + + writew(head, &(bs->rx_tail)); + writeb(1, &(bs->idata)); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return; + } + + /* + * If we are throttled, simply don't read any data. + */ + if (ch->ch_flags & CH_RXBLOCK) { + writeb(1, &(bs->idata)); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return; + } + + /* + * Ignore oruns. + */ + tmpchar = readb(&(bs->orun)); + if (tmpchar) { + ch->ch_err_overrun++; + writeb(0, &(bs->orun)); + } + + /* Decide how much data we can send into the tty layer */ + flip_len = TTY_FLIPBUF_SIZE; + + /* Chop down the length, if needed */ + len = min(data_len, flip_len); + len = min(len, (N_TTY_BUF_SIZE - 1)); + + ld = tty_ldisc_ref(tp); + +#ifdef TTY_DONT_FLIP + /* + * If the DONT_FLIP flag is on, don't flush our buffer, and act + * like the ld doesn't have any space to put the data right now. + */ + if (test_bit(TTY_DONT_FLIP, &tp->flags)) + len = 0; +#endif + + /* + * If we were unable to get a reference to the ld, + * don't flush our buffer, and act like the ld doesn't + * have any space to put the data right now. + */ + if (!ld) { + len = 0; + } else { + /* + * If ld doesn't have a pointer to a receive_buf function, + * flush the data, then act like the ld doesn't have any + * space to put the data right now. + */ + if (!ld->ops->receive_buf) { + writew(head, &(bs->rx_tail)); + len = 0; + } + } + + if (len <= 0) { + writeb(1, &(bs->idata)); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + if (ld) + tty_ldisc_deref(ld); + return; + } + + buf = ch->ch_bd->flipbuf; + n = len; + + /* + * n now contains the most amount of data we can copy, + * bounded either by our buffer size or the amount + * of data the card actually has pending... + */ + while (n) { + + s = ((head >= tail) ? head : ch->ch_rsize) - tail; + s = min(s, n); + + if (s <= 0) + break; + + memcpy_fromio(buf, (char *) ch->ch_raddr + tail, s); + dgap_sniff_nowait_nolock(ch, "USER READ", buf, s); + + tail += s; + buf += s; + + n -= s; + /* Flip queue if needed */ + tail &= rmask; + } + + writew(tail, &(bs->rx_tail)); + writeb(1, &(bs->idata)); + ch->ch_rxcount += len; + + /* + * If we are completely raw, we don't need to go through a lot + * of the tty layers that exist. + * In this case, we take the shortest and fastest route we + * can to relay the data to the user. + * + * On the other hand, if we are not raw, we need to go through + * the tty layer, which has its API more well defined. + */ + if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { + dgap_parity_scan(ch, ch->ch_bd->flipbuf, + ch->ch_bd->flipflagbuf, &len); + + len = tty_buffer_request_room(tp->port, len); + tty_insert_flip_string_flags(tp->port, ch->ch_bd->flipbuf, + ch->ch_bd->flipflagbuf, len); + } else { + len = tty_buffer_request_room(tp->port, len); + tty_insert_flip_string(tp->port, ch->ch_bd->flipbuf, len); + } + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + /* Tell the tty layer its okay to "eat" the data now */ + tty_flip_buffer_push(tp->port); + + if (ld) + tty_ldisc_deref(ld); + +} + +/************************************************************************ + * Determines when CARRIER changes state and takes appropriate + * action. + ************************************************************************/ +static void dgap_carrier(struct channel_t *ch) +{ + struct board_t *bd; + + int virt_carrier = 0; + int phys_carrier = 0; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + /* Make sure altpin is always set correctly */ + if (ch->ch_digi.digi_flags & DIGI_ALTPIN) { + ch->ch_dsr = DM_CD; + ch->ch_cd = DM_DSR; + } else { + ch->ch_dsr = DM_DSR; + ch->ch_cd = DM_CD; + } + + if (ch->ch_mistat & D_CD(ch)) + phys_carrier = 1; + + if (ch->ch_digi.digi_flags & DIGI_FORCEDCD) + virt_carrier = 1; + + if (ch->ch_c_cflag & CLOCAL) + virt_carrier = 1; + + /* + * Test for a VIRTUAL carrier transition to HIGH. + */ + if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) { + + /* + * When carrier rises, wake any threads waiting + * for carrier in the open routine. + */ + + if (waitqueue_active(&(ch->ch_flags_wait))) + wake_up_interruptible(&ch->ch_flags_wait); + } + + /* + * Test for a PHYSICAL carrier transition to HIGH. + */ + if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) { + + /* + * When carrier rises, wake any threads waiting + * for carrier in the open routine. + */ + + if (waitqueue_active(&(ch->ch_flags_wait))) + wake_up_interruptible(&ch->ch_flags_wait); + } + + /* + * Test for a PHYSICAL transition to low, so long as we aren't + * currently ignoring physical transitions (which is what "virtual + * carrier" indicates). + * + * The transition of the virtual carrier to low really doesn't + * matter... it really only means "ignore carrier state", not + * "make pretend that carrier is there". + */ + if ((virt_carrier == 0) && + ((ch->ch_flags & CH_CD) != 0) && + (phys_carrier == 0)) { + + /* + * When carrier drops: + * + * Drop carrier on all open units. + * + * Flush queues, waking up any task waiting in the + * line discipline. + * + * Send a hangup to the control terminal. + * + * Enable all select calls. + */ + if (waitqueue_active(&(ch->ch_flags_wait))) + wake_up_interruptible(&ch->ch_flags_wait); + + if (ch->ch_tun.un_open_count > 0) + tty_hangup(ch->ch_tun.un_tty); + + if (ch->ch_pun.un_open_count > 0) + tty_hangup(ch->ch_pun.un_tty); + } + + /* + * Make sure that our cached values reflect the current reality. + */ + if (virt_carrier == 1) + ch->ch_flags |= CH_FCAR; + else + ch->ch_flags &= ~CH_FCAR; + + if (phys_carrier == 1) + ch->ch_flags |= CH_CD; + else + ch->ch_flags &= ~CH_CD; +} + +/************************************************************************ + * + * TTY Entry points and helper functions + * + ************************************************************************/ + +/* + * dgap_tty_open() + * + */ +static int dgap_tty_open(struct tty_struct *tty, struct file *file) +{ + struct board_t *brd; + struct channel_t *ch; + struct un_t *un; + struct bs_t *bs; + uint major = 0; + uint minor = 0; + int rc = 0; + ulong lock_flags; + ulong lock_flags2; + u16 head; + + rc = 0; + + major = MAJOR(tty_devnum(tty)); + minor = MINOR(tty_devnum(tty)); + + if (major > 255) + return -ENXIO; + + /* Get board pointer from our array of majors we have allocated */ + brd = dgap_BoardsByMajor[major]; + if (!brd) + return -ENXIO; + + /* + * If board is not yet up to a state of READY, go to + * sleep waiting for it to happen or they cancel the open. + */ + rc = wait_event_interruptible(brd->state_wait, + (brd->state & BOARD_READY)); + + if (rc) + return rc; + + spin_lock_irqsave(&brd->bd_lock, lock_flags); + + /* The wait above should guarantee this cannot happen */ + if (brd->state != BOARD_READY) { + spin_unlock_irqrestore(&brd->bd_lock, lock_flags); + return -ENXIO; + } + + /* If opened device is greater than our number of ports, bail. */ + if (MINOR(tty_devnum(tty)) > brd->nasync) { + spin_unlock_irqrestore(&brd->bd_lock, lock_flags); + return -ENXIO; + } + + ch = brd->channels[minor]; + if (!ch) { + spin_unlock_irqrestore(&brd->bd_lock, lock_flags); + return -ENXIO; + } + + /* Grab channel lock */ + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + /* Figure out our type */ + if (major == brd->dgap_Serial_Major) { + un = &brd->channels[minor]->ch_tun; + un->un_type = DGAP_SERIAL; + } else if (major == brd->dgap_TransparentPrint_Major) { + un = &brd->channels[minor]->ch_pun; + un->un_type = DGAP_PRINT; + } else { + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&brd->bd_lock, lock_flags); + return -ENXIO; + } + + /* Store our unit into driver_data, so we always have it available. */ + tty->driver_data = un; + + /* + * Error if channel info pointer is NULL. + */ + bs = ch->ch_bs; + if (!bs) { + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&brd->bd_lock, lock_flags); + return -ENXIO; + } + + /* + * Initialize tty's + */ + if (!(un->un_flags & UN_ISOPEN)) { + /* Store important variables. */ + un->un_tty = tty; + + /* Maybe do something here to the TTY struct as well? */ + } + + /* + * Initialize if neither terminal or printer is open. + */ + if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_ISOPEN)) { + + ch->ch_mforce = 0; + ch->ch_mval = 0; + + /* + * Flush input queue. + */ + head = readw(&(bs->rx_head)); + writew(head, &(bs->rx_tail)); + + ch->ch_flags = 0; + ch->pscan_state = 0; + ch->pscan_savechar = 0; + + ch->ch_c_cflag = tty->termios.c_cflag; + ch->ch_c_iflag = tty->termios.c_iflag; + ch->ch_c_oflag = tty->termios.c_oflag; + ch->ch_c_lflag = tty->termios.c_lflag; + ch->ch_startc = tty->termios.c_cc[VSTART]; + ch->ch_stopc = tty->termios.c_cc[VSTOP]; + + /* TODO: flush our TTY struct here? */ + } + + dgap_carrier(ch); + /* + * Run param in case we changed anything + */ + dgap_param(tty); + + /* + * follow protocol for opening port + */ + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&brd->bd_lock, lock_flags); + + rc = dgap_block_til_ready(tty, file, ch); + + if (!un->un_tty) + return -ENODEV; + + /* No going back now, increment our unit and channel counters */ + spin_lock_irqsave(&ch->ch_lock, lock_flags); + ch->ch_open_count++; + un->un_open_count++; + un->un_flags |= (UN_ISOPEN); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + + return rc; +} + +/* + * dgap_block_til_ready() + * + * Wait for DCD, if needed. + */ +static int dgap_block_til_ready(struct tty_struct *tty, struct file *file, + struct channel_t *ch) +{ + int retval = 0; + struct un_t *un = NULL; + ulong lock_flags; + uint old_flags = 0; + int sleep_on_un_flags = 0; + + if (!tty || tty->magic != TTY_MAGIC || !file || !ch || + ch->magic != DGAP_CHANNEL_MAGIC) + return -ENXIO; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -ENXIO; + + spin_lock_irqsave(&ch->ch_lock, lock_flags); + + ch->ch_wopen++; + + /* Loop forever */ + while (1) { + + sleep_on_un_flags = 0; + + /* + * If board has failed somehow during our sleep, + * bail with error. + */ + if (ch->ch_bd->state == BOARD_FAILED) { + retval = -ENXIO; + break; + } + + /* If tty was hung up, break out of loop and set error. */ + if (tty_hung_up_p(file)) { + retval = -EAGAIN; + break; + } + + /* + * If either unit is in the middle of the fragile part of close, + * we just cannot touch the channel safely. + * Go back to sleep, knowing that when the channel can be + * touched safely, the close routine will signal the + * ch_wait_flags to wake us back up. + */ + if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & + UN_CLOSING)) { + + /* + * Our conditions to leave cleanly and happily: + * 1) NONBLOCKING on the tty is set. + * 2) CLOCAL is set. + * 3) DCD (fake or real) is active. + */ + + if (file->f_flags & O_NONBLOCK) + break; + + if (tty->flags & (1 << TTY_IO_ERROR)) + break; + + if (ch->ch_flags & CH_CD) + break; + + if (ch->ch_flags & CH_FCAR) + break; + } else { + sleep_on_un_flags = 1; + } + + /* + * If there is a signal pending, the user probably + * interrupted (ctrl-c) us. + * Leave loop with error set. + */ + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + /* + * Store the flags before we let go of channel lock + */ + if (sleep_on_un_flags) + old_flags = ch->ch_tun.un_flags | ch->ch_pun.un_flags; + else + old_flags = ch->ch_flags; + + /* + * Let go of channel lock before calling schedule. + * Our poller will get any FEP events and wake us up when DCD + * eventually goes active. + */ + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + + /* + * Wait for something in the flags to change + * from the current value. + */ + if (sleep_on_un_flags) { + retval = wait_event_interruptible(un->un_flags_wait, + (old_flags != (ch->ch_tun.un_flags | + ch->ch_pun.un_flags))); + } else { + retval = wait_event_interruptible(ch->ch_flags_wait, + (old_flags != ch->ch_flags)); + } + + /* + * We got woken up for some reason. + * Before looping around, grab our channel lock. + */ + spin_lock_irqsave(&ch->ch_lock, lock_flags); + } + + ch->ch_wopen--; + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + + if (retval) + return retval; + + return 0; +} + +/* + * dgap_tty_hangup() + * + * Hangup the port. Like a close, but don't wait for output to drain. + */ +static void dgap_tty_hangup(struct tty_struct *tty) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + /* flush the transmit queues */ + dgap_tty_flush_buffer(tty); + +} + +/* + * dgap_tty_close() + * + */ +static void dgap_tty_close(struct tty_struct *tty, struct file *file) +{ + struct ktermios *ts; + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + ulong lock_flags; + int rc = 0; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + ts = &tty->termios; + + spin_lock_irqsave(&ch->ch_lock, lock_flags); + + /* + * Determine if this is the last close or not - and if we agree about + * which type of close it is with the Line Discipline + */ + if ((tty->count == 1) && (un->un_open_count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. un_open_count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + un->un_open_count = 1; + } + + if (--un->un_open_count < 0) + un->un_open_count = 0; + + ch->ch_open_count--; + + if (ch->ch_open_count && un->un_open_count) { + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + return; + } + + /* OK, its the last close on the unit */ + + un->un_flags |= UN_CLOSING; + + tty->closing = 1; + + /* + * Only officially close channel if count is 0 and + * DIGI_PRINTER bit is not set. + */ + if ((ch->ch_open_count == 0) && + !(ch->ch_digi.digi_flags & DIGI_PRINTER)) { + + ch->ch_flags &= ~(CH_RXBLOCK); + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + + /* wait for output to drain */ + /* This will also return if we take an interrupt */ + + rc = dgap_wait_for_drain(tty); + + dgap_tty_flush_buffer(tty); + tty_ldisc_flush(tty); + + spin_lock_irqsave(&ch->ch_lock, lock_flags); + + tty->closing = 0; + + /* + * If we have HUPCL set, lower DTR and RTS + */ + if (ch->ch_c_cflag & HUPCL) { + ch->ch_mostat &= ~(D_RTS(ch)|D_DTR(ch)); + dgap_cmdb(ch, SMODEM, 0, D_DTR(ch)|D_RTS(ch), 0); + + /* + * Go to sleep to ensure RTS/DTR + * have been dropped for modems to see it. + */ + if (ch->ch_close_delay) { + spin_unlock_irqrestore(&ch->ch_lock, + lock_flags); + dgap_ms_sleep(ch->ch_close_delay); + spin_lock_irqsave(&ch->ch_lock, lock_flags); + } + } + + ch->pscan_state = 0; + ch->pscan_savechar = 0; + ch->ch_baud_info = 0; + + } + + /* + * turn off print device when closing print device. + */ + if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON)) { + dgap_wmove(ch, ch->ch_digi.digi_offstr, + (int) ch->ch_digi.digi_offlen); + ch->ch_flags &= ~CH_PRON; + } + + un->un_tty = NULL; + un->un_flags &= ~(UN_ISOPEN | UN_CLOSING); + tty->driver_data = NULL; + + wake_up_interruptible(&ch->ch_flags_wait); + wake_up_interruptible(&un->un_flags_wait); + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); +} + +/* + * dgap_tty_chars_in_buffer() + * + * Return number of characters that have not been transmitted yet. + * + * This routine is used by the line discipline to determine if there + * is data waiting to be transmitted/drained/flushed or not. + */ +static int dgap_tty_chars_in_buffer(struct tty_struct *tty) +{ + struct board_t *bd = NULL; + struct channel_t *ch = NULL; + struct un_t *un = NULL; + struct bs_t *bs = NULL; + uchar tbusy; + uint chars = 0; + u16 thead, ttail, tmask, chead, ctail; + ulong lock_flags = 0; + ulong lock_flags2 = 0; + + if (tty == NULL) + return 0; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + + bs = ch->ch_bs; + if (!bs) + return 0; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + tmask = (ch->ch_tsize - 1); + + /* Get Transmit queue pointers */ + thead = readw(&(bs->tx_head)) & tmask; + ttail = readw(&(bs->tx_tail)) & tmask; + + /* Get tbusy flag */ + tbusy = readb(&(bs->tbusy)); + + /* Get Command queue pointers */ + chead = readw(&(ch->ch_cm->cm_head)); + ctail = readw(&(ch->ch_cm->cm_tail)); + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + /* + * The only way we know for sure if there is no pending + * data left to be transferred, is if: + * 1) Transmit head and tail are equal (empty). + * 2) Command queue head and tail are equal (empty). + * 3) The "TBUSY" flag is 0. (Transmitter not busy). + */ + + if ((ttail == thead) && (tbusy == 0) && (chead == ctail)) { + chars = 0; + } else { + if (thead >= ttail) + chars = thead - ttail; + else + chars = thead - ttail + ch->ch_tsize; + /* + * Fudge factor here. + * If chars is zero, we know that the command queue had + * something in it or tbusy was set. Because we cannot + * be sure if there is still some data to be transmitted, + * lets lie, and tell ld we have 1 byte left. + */ + if (chars == 0) { + /* + * If TBUSY is still set, and our tx buffers are empty, + * force the firmware to send me another wakeup after + * TBUSY has been cleared. + */ + if (tbusy != 0) { + spin_lock_irqsave(&ch->ch_lock, lock_flags); + un->un_flags |= UN_EMPTY; + writeb(1, &(bs->iempty)); + spin_unlock_irqrestore(&ch->ch_lock, + lock_flags); + } + chars = 1; + } + } + + return chars; +} + +static int dgap_wait_for_drain(struct tty_struct *tty) +{ + struct channel_t *ch; + struct un_t *un; + struct bs_t *bs; + int ret = -EIO; + uint count = 1; + ulong lock_flags = 0; + + if (!tty || tty->magic != TTY_MAGIC) + return ret; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return ret; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return ret; + + bs = ch->ch_bs; + if (!bs) + return ret; + + ret = 0; + + /* Loop until data is drained */ + while (count != 0) { + + count = dgap_tty_chars_in_buffer(tty); + + if (count == 0) + break; + + /* Set flag waiting for drain */ + spin_lock_irqsave(&ch->ch_lock, lock_flags); + un->un_flags |= UN_EMPTY; + writeb(1, &(bs->iempty)); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + + /* Go to sleep till we get woken up */ + ret = wait_event_interruptible(un->un_flags_wait, + ((un->un_flags & UN_EMPTY) == 0)); + /* If ret is non-zero, user ctrl-c'ed us */ + if (ret) + break; + } + + spin_lock_irqsave(&ch->ch_lock, lock_flags); + un->un_flags &= ~(UN_EMPTY); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + + return ret; +} + +/* + * dgap_maxcps_room + * + * Reduces bytes_available to the max number of characters + * that can be sent currently given the maxcps value, and + * returns the new bytes_available. This only affects printer + * output. + */ +static int dgap_maxcps_room(struct tty_struct *tty, int bytes_available) +{ + struct channel_t *ch = NULL; + struct un_t *un = NULL; + + if (tty == NULL) + return bytes_available; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return bytes_available; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return bytes_available; + + /* + * If its not the Transparent print device, return + * the full data amount. + */ + if (un->un_type != DGAP_PRINT) + return bytes_available; + + if (ch->ch_digi.digi_maxcps > 0 && ch->ch_digi.digi_bufsize > 0) { + int cps_limit = 0; + unsigned long current_time = jiffies; + unsigned long buffer_time = current_time + + (HZ * ch->ch_digi.digi_bufsize) / + ch->ch_digi.digi_maxcps; + + if (ch->ch_cpstime < current_time) { + /* buffer is empty */ + ch->ch_cpstime = current_time; /* reset ch_cpstime */ + cps_limit = ch->ch_digi.digi_bufsize; + } else if (ch->ch_cpstime < buffer_time) { + /* still room in the buffer */ + cps_limit = ((buffer_time - ch->ch_cpstime) * + ch->ch_digi.digi_maxcps) / HZ; + } else { + /* no room in the buffer */ + cps_limit = 0; + } + + bytes_available = min(cps_limit, bytes_available); + } + + return bytes_available; +} + +static inline void dgap_set_firmware_event(struct un_t *un, unsigned int event) +{ + struct channel_t *ch = NULL; + struct bs_t *bs = NULL; + + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + bs = ch->ch_bs; + if (!bs) + return; + + if ((event & UN_LOW) != 0) { + if ((un->un_flags & UN_LOW) == 0) { + un->un_flags |= UN_LOW; + writeb(1, &(bs->ilow)); + } + } + if ((event & UN_LOW) != 0) { + if ((un->un_flags & UN_EMPTY) == 0) { + un->un_flags |= UN_EMPTY; + writeb(1, &(bs->iempty)); + } + } +} + +/* + * dgap_tty_write_room() + * + * Return space available in Tx buffer + */ +static int dgap_tty_write_room(struct tty_struct *tty) +{ + struct channel_t *ch = NULL; + struct un_t *un = NULL; + struct bs_t *bs = NULL; + u16 head, tail, tmask; + int ret = 0; + ulong lock_flags = 0; + + if (!tty) + return 0; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + + bs = ch->ch_bs; + if (!bs) + return 0; + + spin_lock_irqsave(&ch->ch_lock, lock_flags); + + tmask = ch->ch_tsize - 1; + head = readw(&(bs->tx_head)) & tmask; + tail = readw(&(bs->tx_tail)) & tmask; + + ret = tail - head - 1; + if (ret < 0) + ret += ch->ch_tsize; + + /* Limit printer to maxcps */ + ret = dgap_maxcps_room(tty, ret); + + /* + * If we are printer device, leave space for + * possibly both the on and off strings. + */ + if (un->un_type == DGAP_PRINT) { + if (!(ch->ch_flags & CH_PRON)) + ret -= ch->ch_digi.digi_onlen; + ret -= ch->ch_digi.digi_offlen; + } else { + if (ch->ch_flags & CH_PRON) + ret -= ch->ch_digi.digi_offlen; + } + + if (ret < 0) + ret = 0; + + /* + * Schedule FEP to wake us up if needed. + * + * TODO: This might be overkill... + * Do we really need to schedule callbacks from the FEP + * in every case? Can we get smarter based on ret? + */ + dgap_set_firmware_event(un, UN_LOW | UN_EMPTY); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + + return ret; +} + +/* + * dgap_tty_put_char() + * + * Put a character into ch->ch_buf + * + * - used by the line discipline for OPOST processing + */ +static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c) +{ + /* + * Simply call tty_write. + */ + dgap_tty_write(tty, &c, 1); + return 1; +} + +/* + * dgap_tty_write() + * + * Take data from the user or kernel and send it out to the FEP. + * In here exists all the Transparent Print magic as well. + */ +static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf, + int count) +{ + struct channel_t *ch = NULL; + struct un_t *un = NULL; + struct bs_t *bs = NULL; + char *vaddr = NULL; + u16 head, tail, tmask, remain; + int bufcount = 0, n = 0; + int orig_count = 0; + ulong lock_flags; + + if (!tty) + return 0; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + + bs = ch->ch_bs; + if (!bs) + return 0; + + if (!count) + return 0; + + /* + * Store original amount of characters passed in. + * This helps to figure out if we should ask the FEP + * to send us an event when it has more space available. + */ + orig_count = count; + + spin_lock_irqsave(&ch->ch_lock, lock_flags); + + /* Get our space available for the channel from the board */ + tmask = ch->ch_tsize - 1; + head = readw(&(bs->tx_head)) & tmask; + tail = readw(&(bs->tx_tail)) & tmask; + + bufcount = tail - head - 1; + if (bufcount < 0) + bufcount += ch->ch_tsize; + + /* + * Limit printer output to maxcps overall, with bursts allowed + * up to bufsize characters. + */ + bufcount = dgap_maxcps_room(tty, bufcount); + + /* + * Take minimum of what the user wants to send, and the + * space available in the FEP buffer. + */ + count = min(count, bufcount); + + /* + * Bail if no space left. + */ + if (count <= 0) { + dgap_set_firmware_event(un, UN_LOW | UN_EMPTY); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + return 0; + } + + /* + * Output the printer ON string, if we are in terminal mode, but + * need to be in printer mode. + */ + if ((un->un_type == DGAP_PRINT) && !(ch->ch_flags & CH_PRON)) { + dgap_wmove(ch, ch->ch_digi.digi_onstr, + (int) ch->ch_digi.digi_onlen); + head = readw(&(bs->tx_head)) & tmask; + ch->ch_flags |= CH_PRON; + } + + /* + * On the other hand, output the printer OFF string, if we are + * currently in printer mode, but need to output to the terminal. + */ + if ((un->un_type != DGAP_PRINT) && (ch->ch_flags & CH_PRON)) { + dgap_wmove(ch, ch->ch_digi.digi_offstr, + (int) ch->ch_digi.digi_offlen); + head = readw(&(bs->tx_head)) & tmask; + ch->ch_flags &= ~CH_PRON; + } + + /* + * If there is nothing left to copy, or + * I can't handle any more data, leave. + */ + if (count <= 0) { + dgap_set_firmware_event(un, UN_LOW | UN_EMPTY); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + return 0; + } + + n = count; + + /* + * If the write wraps over the top of the circular buffer, + * move the portion up to the wrap point, and reset the + * pointers to the bottom. + */ + remain = ch->ch_tstart + ch->ch_tsize - head; + + if (n >= remain) { + n -= remain; + vaddr = ch->ch_taddr + head; + + memcpy_toio(vaddr, (uchar *) buf, remain); + dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *) buf, + remain); + + head = ch->ch_tstart; + buf += remain; + } + + if (n > 0) { + + /* + * Move rest of data. + */ + vaddr = ch->ch_taddr + head; + remain = n; + + memcpy_toio(vaddr, (uchar *) buf, remain); + dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *)buf, + remain); + + head += remain; + + } + + if (count) { + ch->ch_txcount += count; + head &= tmask; + writew(head, &(bs->tx_head)); + } + + dgap_set_firmware_event(un, UN_LOW | UN_EMPTY); + + /* + * If this is the print device, and the + * printer is still on, we need to turn it + * off before going idle. If the buffer is + * non-empty, wait until it goes empty. + * Otherwise turn it off right now. + */ + if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON)) { + tail = readw(&(bs->tx_tail)) & tmask; + + if (tail != head) { + un->un_flags |= UN_EMPTY; + writeb(1, &(bs->iempty)); + } else { + dgap_wmove(ch, ch->ch_digi.digi_offstr, + (int) ch->ch_digi.digi_offlen); + head = readw(&(bs->tx_head)) & tmask; + ch->ch_flags &= ~CH_PRON; + } + } + + /* Update printer buffer empty time. */ + if ((un->un_type == DGAP_PRINT) && (ch->ch_digi.digi_maxcps > 0) + && (ch->ch_digi.digi_bufsize > 0)) { + ch->ch_cpstime += (HZ * count) / ch->ch_digi.digi_maxcps; + } + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + + return count; +} + +/* + * Return modem signals to ld. + */ +static int dgap_tty_tiocmget(struct tty_struct *tty) +{ + struct channel_t *ch; + struct un_t *un; + int result = -EIO; + uchar mstat = 0; + ulong lock_flags; + + if (!tty || tty->magic != TTY_MAGIC) + return result; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return result; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return result; + + spin_lock_irqsave(&ch->ch_lock, lock_flags); + + mstat = readb(&(ch->ch_bs->m_stat)); + /* Append any outbound signals that might be pending... */ + mstat |= ch->ch_mostat; + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + + result = 0; + + if (mstat & D_DTR(ch)) + result |= TIOCM_DTR; + if (mstat & D_RTS(ch)) + result |= TIOCM_RTS; + if (mstat & D_CTS(ch)) + result |= TIOCM_CTS; + if (mstat & D_DSR(ch)) + result |= TIOCM_DSR; + if (mstat & D_RI(ch)) + result |= TIOCM_RI; + if (mstat & D_CD(ch)) + result |= TIOCM_CD; + + return result; +} + +/* + * dgap_tty_tiocmset() + * + * Set modem signals, called by ld. + */ +static int dgap_tty_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + int ret = -EIO; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return ret; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return ret; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return ret; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return ret; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + if (set & TIOCM_RTS) { + ch->ch_mforce |= D_RTS(ch); + ch->ch_mval |= D_RTS(ch); + } + + if (set & TIOCM_DTR) { + ch->ch_mforce |= D_DTR(ch); + ch->ch_mval |= D_DTR(ch); + } + + if (clear & TIOCM_RTS) { + ch->ch_mforce |= D_RTS(ch); + ch->ch_mval &= ~(D_RTS(ch)); + } + + if (clear & TIOCM_DTR) { + ch->ch_mforce |= D_DTR(ch); + ch->ch_mval &= ~(D_DTR(ch)); + } + + dgap_param(tty); + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + return 0; +} + +/* + * dgap_tty_send_break() + * + * Send a Break, called by ld. + */ +static int dgap_tty_send_break(struct tty_struct *tty, int msec) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + int ret = -EIO; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return ret; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return ret; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return ret; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return ret; + + switch (msec) { + case -1: + msec = 0xFFFF; + break; + case 0: + msec = 1; + break; + default: + msec /= 10; + break; + } + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); +#if 0 + dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0); +#endif + dgap_cmdw(ch, SBREAK, (u16) msec, 0); + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + return 0; +} + +/* + * dgap_tty_wait_until_sent() + * + * wait until data has been transmitted, called by ld. + */ +static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout) +{ + dgap_wait_for_drain(tty); +} + +/* + * dgap_send_xchar() + * + * send a high priority character, called by ld. + */ +static void dgap_tty_send_xchar(struct tty_struct *tty, char c) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + /* + * This is technically what we should do. + * However, the NIST tests specifically want + * to see each XON or XOFF character that it + * sends, so lets just send each character + * by hand... + */ +#if 0 + if (c == STOP_CHAR(tty)) + dgap_cmdw(ch, RPAUSE, 0, 0); + else if (c == START_CHAR(tty)) + dgap_cmdw(ch, RRESUME, 0, 0); + else + dgap_wmove(ch, &c, 1); +#else + dgap_wmove(ch, &c, 1); +#endif + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + return; +} + +/* + * Return modem signals to ld. + */ +static int dgap_get_modem_info(struct channel_t *ch, unsigned int __user *value) +{ + int result = 0; + uchar mstat = 0; + ulong lock_flags; + int rc = 0; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -ENXIO; + + spin_lock_irqsave(&ch->ch_lock, lock_flags); + + mstat = readb(&(ch->ch_bs->m_stat)); + /* Append any outbound signals that might be pending... */ + mstat |= ch->ch_mostat; + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + + result = 0; + + if (mstat & D_DTR(ch)) + result |= TIOCM_DTR; + if (mstat & D_RTS(ch)) + result |= TIOCM_RTS; + if (mstat & D_CTS(ch)) + result |= TIOCM_CTS; + if (mstat & D_DSR(ch)) + result |= TIOCM_DSR; + if (mstat & D_RI(ch)) + result |= TIOCM_RI; + if (mstat & D_CD(ch)) + result |= TIOCM_CD; + + rc = put_user(result, value); + + return rc; +} + +/* + * dgap_set_modem_info() + * + * Set modem signals, called by ld. + */ +static int dgap_set_modem_info(struct tty_struct *tty, unsigned int command, + unsigned int __user *value) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + int ret = -ENXIO; + unsigned int arg = 0; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return ret; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return ret; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return ret; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return ret; + + ret = get_user(arg, value); + if (ret) + return ret; + + switch (command) { + case TIOCMBIS: + if (arg & TIOCM_RTS) { + ch->ch_mforce |= D_RTS(ch); + ch->ch_mval |= D_RTS(ch); + } + + if (arg & TIOCM_DTR) { + ch->ch_mforce |= D_DTR(ch); + ch->ch_mval |= D_DTR(ch); + } + + break; + + case TIOCMBIC: + if (arg & TIOCM_RTS) { + ch->ch_mforce |= D_RTS(ch); + ch->ch_mval &= ~(D_RTS(ch)); + } + + if (arg & TIOCM_DTR) { + ch->ch_mforce |= D_DTR(ch); + ch->ch_mval &= ~(D_DTR(ch)); + } + + break; + + case TIOCMSET: + ch->ch_mforce = D_DTR(ch)|D_RTS(ch); + + if (arg & TIOCM_RTS) + ch->ch_mval |= D_RTS(ch); + else + ch->ch_mval &= ~(D_RTS(ch)); + + if (arg & TIOCM_DTR) + ch->ch_mval |= (D_DTR(ch)); + else + ch->ch_mval &= ~(D_DTR(ch)); + + break; + + default: + return -EINVAL; + } + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + dgap_param(tty); + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + return 0; +} + +/* + * dgap_tty_digigeta() + * + * Ioctl to get the information for ditty. + * + * + * + */ +static int dgap_tty_digigeta(struct tty_struct *tty, + struct digi_t __user *retinfo) +{ + struct channel_t *ch; + struct un_t *un; + struct digi_t tmp; + ulong lock_flags; + + if (!retinfo) + return -EFAULT; + + if (!tty || tty->magic != TTY_MAGIC) + return -EFAULT; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -EFAULT; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + + spin_lock_irqsave(&ch->ch_lock, lock_flags); + memcpy(&tmp, &ch->ch_digi, sizeof(tmp)); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + + return 0; +} + +/* + * dgap_tty_digiseta() + * + * Ioctl to set the information for ditty. + * + * + * + */ +static int dgap_tty_digiseta(struct tty_struct *tty, + struct digi_t __user *new_info) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + struct digi_t new_digi; + ulong lock_flags = 0; + unsigned long lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return -EFAULT; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -EFAULT; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -EFAULT; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return -EFAULT; + + if (copy_from_user(&new_digi, new_info, sizeof(struct digi_t))) + return -EFAULT; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + memcpy(&ch->ch_digi, &new_digi, sizeof(struct digi_t)); + + if (ch->ch_digi.digi_maxcps < 1) + ch->ch_digi.digi_maxcps = 1; + + if (ch->ch_digi.digi_maxcps > 10000) + ch->ch_digi.digi_maxcps = 10000; + + if (ch->ch_digi.digi_bufsize < 10) + ch->ch_digi.digi_bufsize = 10; + + if (ch->ch_digi.digi_maxchar < 1) + ch->ch_digi.digi_maxchar = 1; + + if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize) + ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize; + + if (ch->ch_digi.digi_onlen > DIGI_PLEN) + ch->ch_digi.digi_onlen = DIGI_PLEN; + + if (ch->ch_digi.digi_offlen > DIGI_PLEN) + ch->ch_digi.digi_offlen = DIGI_PLEN; + + dgap_param(tty); + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + return 0; +} + +/* + * dgap_tty_digigetedelay() + * + * Ioctl to get the current edelay setting. + * + * + * + */ +static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo) +{ + struct channel_t *ch; + struct un_t *un; + int tmp; + ulong lock_flags; + + if (!retinfo) + return -EFAULT; + + if (!tty || tty->magic != TTY_MAGIC) + return -EFAULT; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -EFAULT; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + + spin_lock_irqsave(&ch->ch_lock, lock_flags); + tmp = readw(&(ch->ch_bs->edelay)); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + + return 0; +} + +/* + * dgap_tty_digisetedelay() + * + * Ioctl to set the EDELAY setting + * + */ +static int dgap_tty_digisetedelay(struct tty_struct *tty, int __user *new_info) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + int new_digi; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return -EFAULT; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -EFAULT; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -EFAULT; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return -EFAULT; + + if (copy_from_user(&new_digi, new_info, sizeof(int))) + return -EFAULT; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + writew((u16) new_digi, &(ch->ch_bs->edelay)); + + dgap_param(tty); + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + return 0; +} + +/* + * dgap_tty_digigetcustombaud() + * + * Ioctl to get the current custom baud rate setting. + */ +static int dgap_tty_digigetcustombaud(struct tty_struct *tty, + int __user *retinfo) +{ + struct channel_t *ch; + struct un_t *un; + int tmp; + ulong lock_flags; + + if (!retinfo) + return -EFAULT; + + if (!tty || tty->magic != TTY_MAGIC) + return -EFAULT; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -EFAULT; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + + spin_lock_irqsave(&ch->ch_lock, lock_flags); + tmp = dgap_get_custom_baud(ch); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags); + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + + return 0; +} + +/* + * dgap_tty_digisetcustombaud() + * + * Ioctl to set the custom baud rate setting + */ +static int dgap_tty_digisetcustombaud(struct tty_struct *tty, + int __user *new_info) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + uint new_rate; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return -EFAULT; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -EFAULT; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -EFAULT; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return -EFAULT; + + + if (copy_from_user(&new_rate, new_info, sizeof(unsigned int))) + return -EFAULT; + + if (bd->bd_flags & BD_FEP5PLUS) { + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + ch->ch_custom_speed = new_rate; + + dgap_param(tty); + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + } + + return 0; +} + +/* + * dgap_set_termios() + */ +static void dgap_tty_set_termios(struct tty_struct *tty, + struct ktermios *old_termios) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + unsigned long lock_flags; + unsigned long lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + ch->ch_c_cflag = tty->termios.c_cflag; + ch->ch_c_iflag = tty->termios.c_iflag; + ch->ch_c_oflag = tty->termios.c_oflag; + ch->ch_c_lflag = tty->termios.c_lflag; + ch->ch_startc = tty->termios.c_cc[VSTART]; + ch->ch_stopc = tty->termios.c_cc[VSTOP]; + + dgap_carrier(ch); + dgap_param(tty); + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); +} + +static void dgap_tty_throttle(struct tty_struct *tty) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + ch->ch_flags |= (CH_RXBLOCK); +#if 1 + dgap_cmdw(ch, RPAUSE, 0, 0); +#endif + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + +} + +static void dgap_tty_unthrottle(struct tty_struct *tty) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + ch->ch_flags &= ~(CH_RXBLOCK); + +#if 1 + dgap_cmdw(ch, RRESUME, 0, 0); +#endif + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); +} + +static void dgap_tty_start(struct tty_struct *tty) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + dgap_cmdw(ch, RESUMETX, 0, 0); + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + +} + +static void dgap_tty_stop(struct tty_struct *tty) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + dgap_cmdw(ch, PAUSETX, 0, 0); + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + +} + +/* + * dgap_tty_flush_chars() + * + * Flush the cook buffer + * + * Note to self, and any other poor souls who venture here: + * + * flush in this case DOES NOT mean dispose of the data. + * instead, it means "stop buffering and send it if you + * haven't already." Just guess how I figured that out... SRW 2-Jun-98 + * + * It is also always called in interrupt context - JAR 8-Sept-99 + */ +static void dgap_tty_flush_chars(struct tty_struct *tty) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + /* TODO: Do something here */ + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); +} + +/* + * dgap_tty_flush_buffer() + * + * Flush Tx buffer (make in == out) + */ +static void dgap_tty_flush_buffer(struct tty_struct *tty) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + ulong lock_flags; + ulong lock_flags2; + u16 head = 0; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + ch->ch_flags &= ~CH_STOP; + head = readw(&(ch->ch_bs->tx_head)); + dgap_cmdw(ch, FLUSHTX, (u16) head, 0); + dgap_cmdw(ch, RESUMETX, 0, 0); + if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) { + ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY); + wake_up_interruptible(&ch->ch_tun.un_flags_wait); + } + if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) { + ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY); + wake_up_interruptible(&ch->ch_pun.un_flags_wait); + } + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + if (waitqueue_active(&tty->write_wait)) + wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); +} + +/***************************************************************************** + * + * The IOCTL function and all of its helpers + * + *****************************************************************************/ + +/* + * dgap_tty_ioctl() + * + * The usual assortment of ioctl's + */ +static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd, + unsigned long arg) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + int rc; + u16 head = 0; + ulong lock_flags = 0; + ulong lock_flags2 = 0; + void __user *uarg = (void __user *) arg; + + if (!tty || tty->magic != TTY_MAGIC) + return -ENODEV; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -ENODEV; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -ENODEV; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return -ENODEV; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + if (un->un_open_count <= 0) { + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return -EIO; + } + + switch (cmd) { + + /* Here are all the standard ioctl's that we MUST implement */ + + case TCSBRK: + /* + * TCSBRK is SVID version: non-zero arg --> no break + * this behaviour is exploited by tcdrain(). + * + * According to POSIX.1 spec (7.2.2.1.2) breaks should be + * between 0.25 and 0.5 seconds so we'll ask for something + * in the middle: 0.375 seconds. + */ + rc = tty_check_change(tty); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + if (rc) + return rc; + + rc = dgap_wait_for_drain(tty); + + if (rc) + return -EINTR; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + if (((cmd == TCSBRK) && (!arg)) || (cmd == TCSBRKP)) + dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0); + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + return 0; + + case TCSBRKP: + /* support for POSIX tcsendbreak() + + * According to POSIX.1 spec (7.2.2.1.2) breaks should be + * between 0.25 and 0.5 seconds so we'll ask for something + * in the middle: 0.375 seconds. + */ + rc = tty_check_change(tty); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + if (rc) + return rc; + + rc = dgap_wait_for_drain(tty); + if (rc) + return -EINTR; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0); + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + return 0; + + case TIOCSBRK: + /* + * FEP5 doesn't support turning on a break unconditionally. + * The FEP5 device will stop sending a break automatically + * after the specified time value that was sent when turning on + * the break. + */ + rc = tty_check_change(tty); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + if (rc) + return rc; + + rc = dgap_wait_for_drain(tty); + if (rc) + return -EINTR; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0); + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + return 0; + + case TIOCCBRK: + /* + * FEP5 doesn't support turning off a break unconditionally. + * The FEP5 device will stop sending a break automatically + * after the specified time value that was sent when turning on + * the break. + */ + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return 0; + + case TIOCGSOFTCAR: + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + rc = put_user(C_CLOCAL(tty) ? 1 : 0, + (unsigned long __user *) arg); + return rc; + + case TIOCSSOFTCAR: + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + rc = get_user(arg, (unsigned long __user *) arg); + if (rc) + return rc; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + tty->termios.c_cflag = ((tty->termios.c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + dgap_param(tty); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + return 0; + + case TIOCMGET: + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return dgap_get_modem_info(ch, uarg); + + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return dgap_set_modem_info(tty, cmd, uarg); + + /* + * Here are any additional ioctl's that we want to implement + */ + + case TCFLSH: + /* + * The linux tty driver doesn't have a flush + * input routine for the driver, assuming all backed + * up data is in the line disc. buffers. However, + * we all know that's not the case. Here, we + * act on the ioctl, but then lie and say we didn't + * so the line discipline will process the flush + * also. + */ + rc = tty_check_change(tty); + if (rc) { + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return rc; + } + + if ((arg == TCIFLUSH) || (arg == TCIOFLUSH)) { + if (!(un->un_type == DGAP_PRINT)) { + head = readw(&(ch->ch_bs->rx_head)); + writew(head, &(ch->ch_bs->rx_tail)); + writeb(0, &(ch->ch_bs->orun)); + } + } + + if ((arg != TCOFLUSH) && (arg != TCIOFLUSH)) { + /* pretend we didn't recognize this IOCTL */ + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + return -ENOIOCTLCMD; + } + + ch->ch_flags &= ~CH_STOP; + head = readw(&(ch->ch_bs->tx_head)); + dgap_cmdw(ch, FLUSHTX, (u16) head, 0); + dgap_cmdw(ch, RESUMETX, 0, 0); + if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) { + ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY); + wake_up_interruptible(&ch->ch_tun.un_flags_wait); + } + if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) { + ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY); + wake_up_interruptible(&ch->ch_pun.un_flags_wait); + } + if (waitqueue_active(&tty->write_wait)) + wake_up_interruptible(&tty->write_wait); + + /* Can't hold any locks when calling tty_wakeup! */ + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + tty_wakeup(tty); + + /* pretend we didn't recognize this IOCTL */ + return -ENOIOCTLCMD; + + case TCSETSF: + case TCSETSW: + /* + * The linux tty driver doesn't have a flush + * input routine for the driver, assuming all backed + * up data is in the line disc. buffers. However, + * we all know that's not the case. Here, we + * act on the ioctl, but then lie and say we didn't + * so the line discipline will process the flush + * also. + */ + if (cmd == TCSETSF) { + /* flush rx */ + ch->ch_flags &= ~CH_STOP; + head = readw(&(ch->ch_bs->rx_head)); + writew(head, &(ch->ch_bs->rx_tail)); + } + + /* now wait for all the output to drain */ + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + rc = dgap_wait_for_drain(tty); + if (rc) + return -EINTR; + + /* pretend we didn't recognize this */ + return -ENOIOCTLCMD; + + case TCSETAW: + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + rc = dgap_wait_for_drain(tty); + if (rc) + return -EINTR; + + /* pretend we didn't recognize this */ + return -ENOIOCTLCMD; + + case TCXONC: + /* + * The Linux Line Discipline (LD) would do this for us if we + * let it, but we have the special firmware options to do this + * the "right way" regardless of hardware or software flow + * control so we'll do it outselves instead of letting the LD + * do it. + */ + rc = tty_check_change(tty); + if (rc) { + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return rc; + } + + switch (arg) { + + case TCOON: + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + dgap_tty_start(tty); + return 0; + case TCOOFF: + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + dgap_tty_stop(tty); + return 0; + case TCION: + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + /* Make the ld do it */ + return -ENOIOCTLCMD; + case TCIOFF: + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + /* Make the ld do it */ + return -ENOIOCTLCMD; + default: + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return -EINVAL; + } + + case DIGI_GETA: + /* get information for ditty */ + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return dgap_tty_digigeta(tty, uarg); + + case DIGI_SETAW: + case DIGI_SETAF: + + /* set information for ditty */ + if (cmd == (DIGI_SETAW)) { + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + rc = dgap_wait_for_drain(tty); + if (rc) + return -EINTR; + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + } else + tty_ldisc_flush(tty); + /* fall thru */ + + case DIGI_SETA: + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return dgap_tty_digiseta(tty, uarg); + + case DIGI_GEDELAY: + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return dgap_tty_digigetedelay(tty, uarg); + + case DIGI_SEDELAY: + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return dgap_tty_digisetedelay(tty, uarg); + + case DIGI_GETCUSTOMBAUD: + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return dgap_tty_digigetcustombaud(tty, uarg); + + case DIGI_SETCUSTOMBAUD: + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return dgap_tty_digisetcustombaud(tty, uarg); + + case DIGI_RESET_PORT: + dgap_firmware_reset_port(ch); + dgap_param(tty); + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return 0; + + default: + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + return -ENOIOCTLCMD; + } +} + +static int dgap_after_config_loaded(int board) +{ + /* + * Initialize KME waitqueues... + */ + init_waitqueue_head(&(dgap_Board[board]->kme_wait)); + + /* + * allocate flip buffer for board. + */ + dgap_Board[board]->flipbuf = kmalloc(MYFLIPLEN, GFP_ATOMIC); + if (!dgap_Board[board]->flipbuf) + return -ENOMEM; + + dgap_Board[board]->flipflagbuf = kmalloc(MYFLIPLEN, GFP_ATOMIC); + if (!dgap_Board[board]->flipflagbuf) { + kfree(dgap_Board[board]->flipbuf); + return -ENOMEM; + } + + return 0; +} + +/* + * Create pr and tty device entries + */ +static int dgap_tty_register_ports(struct board_t *brd) +{ + struct channel_t *ch; + int i; + + brd->SerialPorts = kcalloc(brd->nasync, sizeof(*brd->SerialPorts), + GFP_KERNEL); + if (brd->SerialPorts == NULL) + return -ENOMEM; + for (i = 0; i < brd->nasync; i++) + tty_port_init(&brd->SerialPorts[i]); + + brd->PrinterPorts = kcalloc(brd->nasync, sizeof(*brd->PrinterPorts), + GFP_KERNEL); + if (brd->PrinterPorts == NULL) { + kfree(brd->SerialPorts); + return -ENOMEM; + } + for (i = 0; i < brd->nasync; i++) + tty_port_init(&brd->PrinterPorts[i]); + + ch = brd->channels[0]; + for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) { + + struct device *classp; + + classp = tty_port_register_device(&brd->SerialPorts[i], + brd->SerialDriver, + brd->firstminor + i, NULL); + + dgap_create_tty_sysfs(&ch->ch_tun, classp); + ch->ch_tun.un_sysfs = classp; + + classp = tty_port_register_device(&brd->PrinterPorts[i], + brd->PrintDriver, + brd->firstminor + i, NULL); + + dgap_create_tty_sysfs(&ch->ch_pun, classp); + ch->ch_pun.un_sysfs = classp; + } + dgap_create_ports_sysfiles(brd); + + return 0; +} + +/* + * Copies the BIOS code from the user to the board, + * and starts the BIOS running. + */ +static void dgap_do_bios_load(struct board_t *brd, const uchar *ubios, int len) +{ + uchar *addr; + uint offset; + int i; + + if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) + return; + + addr = brd->re_map_membase; + + /* + * clear POST area + */ + for (i = 0; i < 16; i++) + writeb(0, addr + POSTAREA + i); + + /* + * Download bios + */ + offset = 0x1000; + memcpy_toio(addr + offset, ubios, len); + + writel(0x0bf00401, addr); + writel(0, (addr + 4)); + + /* Clear the reset, and change states. */ + writeb(FEPCLR, brd->re_map_port); +} + +/* + * Checks to see if the BIOS completed running on the card. + */ +static int dgap_do_wait_for_bios(struct board_t *brd) +{ + uchar *addr; + u16 word; + u16 err1; + u16 err2; + int ret = 0; + + if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) + return ret; + + addr = brd->re_map_membase; + word = readw(addr + POSTAREA); + + /* + * It can take 5-6 seconds for a board to + * pass the bios self test and post results. + * Give it 10 seconds. + */ + brd->wait_for_bios = 0; + while (brd->wait_for_bios < 1000) { + /* Check to see if BIOS thinks board is good. (GD). */ + if (word == *(u16 *) "GD") + return 1; + msleep_interruptible(10); + brd->wait_for_bios++; + word = readw(addr + POSTAREA); + } + + /* Gave up on board after too long of time taken */ + err1 = readw(addr + SEQUENCE); + err2 = readw(addr + ERROR); + pr_warn("dgap: %s failed diagnostics. Error #(%x,%x).\n", + brd->name, err1, err2); + brd->state = BOARD_FAILED; + brd->dpastatus = BD_NOBIOS; + + return ret; +} + +/* + * Copies the FEP code from the user to the board, + * and starts the FEP running. + */ +static void dgap_do_fep_load(struct board_t *brd, const uchar *ufep, int len) +{ + uchar *addr; + uint offset; + + if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) + return; + + addr = brd->re_map_membase; + + /* + * Download FEP + */ + offset = 0x1000; + memcpy_toio(addr + offset, ufep, len); + + /* + * If board is a concentrator product, we need to give + * it its config string describing how the concentrators look. + */ + if ((brd->type == PCX) || (brd->type == PEPC)) { + uchar string[100]; + uchar *config, *xconfig; + int i = 0; + + xconfig = dgap_create_config_string(brd, string); + + /* Write string to board memory */ + config = addr + CONFIG; + for (; i < CONFIGSIZE; i++, config++, xconfig++) { + writeb(*xconfig, config); + if ((*xconfig & 0xff) == 0xff) + break; + } + } + + writel(0xbfc01004, (addr + 0xc34)); + writel(0x3, (addr + 0xc30)); + +} + +/* + * Waits for the FEP to report thats its ready for us to use. + */ +static int dgap_do_wait_for_fep(struct board_t *brd) +{ + uchar *addr; + u16 word; + u16 err1; + u16 err2; + int ret = 0; + + if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) + return ret; + + addr = brd->re_map_membase; + word = readw(addr + FEPSTAT); + + /* + * It can take 2-3 seconds for the FEP to + * be up and running. Give it 5 secs. + */ + brd->wait_for_fep = 0; + while (brd->wait_for_fep < 500) { + /* Check to see if FEP is up and running now. */ + if (word == *(u16 *) "OS") { + /* + * Check to see if the board can support FEP5+ commands. + */ + word = readw(addr + FEP5_PLUS); + if (word == *(u16 *) "5A") + brd->bd_flags |= BD_FEP5PLUS; + + return 1; + } + msleep_interruptible(10); + brd->wait_for_fep++; + word = readw(addr + FEPSTAT); + } + + /* Gave up on board after too long of time taken */ + err1 = readw(addr + SEQUENCE); + err2 = readw(addr + ERROR); + pr_warn("dgap: FEPOS for %s not functioning. Error #(%x,%x).\n", + brd->name, err1, err2); + brd->state = BOARD_FAILED; + brd->dpastatus = BD_NOFEP; + + return ret; +} + +/* + * Physically forces the FEP5 card to reset itself. + */ +static void dgap_do_reset_board(struct board_t *brd) +{ + uchar check; + u32 check1; + u32 check2; + int i = 0; + + if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || + !brd->re_map_membase || !brd->re_map_port) + return; + + /* FEPRST does not vary among supported boards */ + writeb(FEPRST, brd->re_map_port); + + for (i = 0; i <= 1000; i++) { + check = readb(brd->re_map_port) & 0xe; + if (check == FEPRST) + break; + udelay(10); + + } + if (i > 1000) { + pr_warn("dgap: Board not resetting... Failing board.\n"); + brd->state = BOARD_FAILED; + brd->dpastatus = BD_NOFEP; + return; + } + + /* + * Make sure there really is memory out there. + */ + writel(0xa55a3cc3, (brd->re_map_membase + LOWMEM)); + writel(0x5aa5c33c, (brd->re_map_membase + HIGHMEM)); + check1 = readl(brd->re_map_membase + LOWMEM); + check2 = readl(brd->re_map_membase + HIGHMEM); + + if ((check1 != 0xa55a3cc3) || (check2 != 0x5aa5c33c)) { + pr_warn("dgap: No memory at %p for board.\n", + brd->re_map_membase); + brd->state = BOARD_FAILED; + brd->dpastatus = BD_NOFEP; + return; + } + +} + +#ifdef DIGI_CONCENTRATORS_SUPPORTED +/* + * Sends a concentrator image into the FEP5 board. + */ +static void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len) +{ + char *vaddr; + u16 offset = 0; + struct downld_t *to_dp; + + if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) + return; + + vaddr = brd->re_map_membase; + + offset = readw((u16 *) (vaddr + DOWNREQ)); + to_dp = (struct downld_t *) (vaddr + (int) offset); + memcpy_toio(to_dp, uaddr, len); + + /* Tell card we have data for it */ + writew(0, vaddr + (DOWNREQ)); + + brd->conc_dl_status = NO_PENDING_CONCENTRATOR_REQUESTS; +} +#endif + +#define EXPANSION_ROM_SIZE (64 * 1024) +#define FEP5_ROM_MAGIC (0xFEFFFFFF) + +static void dgap_get_vpd(struct board_t *brd) +{ + u32 magic; + u32 base_offset; + u16 rom_offset; + u16 vpd_offset; + u16 image_length; + u16 i; + uchar byte1; + uchar byte2; + + /* + * Poke the magic number at the PCI Rom Address location. + * If VPD is supported, the value read from that address + * will be non-zero. + */ + magic = FEP5_ROM_MAGIC; + pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic); + pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic); + + /* VPD not supported, bail */ + if (!magic) + return; + + /* + * To get to the OTPROM memory, we have to send the boards base + * address or'ed with 1 into the PCI Rom Address location. + */ + magic = brd->membase | 0x01; + pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic); + pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic); + + byte1 = readb(brd->re_map_membase); + byte2 = readb(brd->re_map_membase + 1); + + /* + * If the board correctly swapped to the OTPROM memory, + * the first 2 bytes (header) should be 0x55, 0xAA + */ + if (byte1 == 0x55 && byte2 == 0xAA) { + + base_offset = 0; + + /* + * We have to run through all the OTPROM memory looking + * for the VPD offset. + */ + while (base_offset <= EXPANSION_ROM_SIZE) { + + /* + * Lots of magic numbers here. + * + * The VPD offset is located inside the ROM Data + * Structure. + * + * We also have to remember the length of each + * ROM Data Structure, so we can "hop" to the next + * entry if the VPD isn't in the current + * ROM Data Structure. + */ + rom_offset = readw(brd->re_map_membase + + base_offset + 0x18); + image_length = readw(brd->re_map_membase + + rom_offset + 0x10) * 512; + vpd_offset = readw(brd->re_map_membase + + rom_offset + 0x08); + + /* Found the VPD entry */ + if (vpd_offset) + break; + + /* We didn't find a VPD entry, go to next ROM entry. */ + base_offset += image_length; + + byte1 = readb(brd->re_map_membase + base_offset); + byte2 = readb(brd->re_map_membase + base_offset + 1); + + /* + * If the new ROM offset doesn't have 0x55, 0xAA + * as its header, we have run out of ROM. + */ + if (byte1 != 0x55 || byte2 != 0xAA) + break; + } + + /* + * If we have a VPD offset, then mark the board + * as having a valid VPD, and copy VPDSIZE (512) bytes of + * that VPD to the buffer we have in our board structure. + */ + if (vpd_offset) { + brd->bd_flags |= BD_HAS_VPD; + for (i = 0; i < VPDSIZE; i++) { + brd->vpd[i] = readb(brd->re_map_membase + + vpd_offset + i); + } + } + } + + /* + * We MUST poke the magic number at the PCI Rom Address location again. + * This makes the card report the regular board memory back to us, + * rather than the OTPROM memory. + */ + magic = FEP5_ROM_MAGIC; + pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic); +} + +/* + * Our board poller function. + */ +static void dgap_poll_tasklet(unsigned long data) +{ + struct board_t *bd = (struct board_t *) data; + ulong lock_flags; + char *vaddr; + u16 head, tail; + + if (!bd || (bd->magic != DGAP_BOARD_MAGIC)) + return; + + if (bd->inhibit_poller) + return; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + + vaddr = bd->re_map_membase; + + /* + * If board is ready, parse deeper to see if there is anything to do. + */ + if (bd->state == BOARD_READY) { + + struct ev_t *eaddr = NULL; + + if (!bd->re_map_membase) { + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return; + } + if (!bd->re_map_port) { + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return; + } + + if (!bd->nasync) + goto out; + + eaddr = (struct ev_t *) (vaddr + EVBUF); + + /* Get our head and tail */ + head = readw(&(eaddr->ev_head)); + tail = readw(&(eaddr->ev_tail)); + + /* + * If there is an event pending. Go service it. + */ + if (head != tail) { + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + dgap_event(bd); + spin_lock_irqsave(&bd->bd_lock, lock_flags); + } + +out: + /* + * If board is doing interrupts, ACK the interrupt. + */ + if (bd && bd->intr_running) + readb(bd->re_map_port + 2); + + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return; + } + + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); +} + +/*======================================================================= + * + * dgap_cmdb - Sends a 2 byte command to the FEP. + * + * ch - Pointer to channel structure. + * cmd - Command to be sent. + * byte1 - Integer containing first byte to be sent. + * byte2 - Integer containing second byte to be sent. + * ncmds - Wait until ncmds or fewer cmds are left + * in the cmd buffer before returning. + * + *=======================================================================*/ +static void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, + uchar byte2, uint ncmds) +{ + char *vaddr = NULL; + struct cm_t *cm_addr = NULL; + uint count; + uint n; + u16 head; + u16 tail; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + /* + * Check if board is still alive. + */ + if (ch->ch_bd->state == BOARD_FAILED) + return; + + /* + * Make sure the pointers are in range before + * writing to the FEP memory. + */ + vaddr = ch->ch_bd->re_map_membase; + + if (!vaddr) + return; + + cm_addr = (struct cm_t *) (vaddr + CMDBUF); + head = readw(&(cm_addr->cm_head)); + + /* + * Forget it if pointers out of range. + */ + if (head >= (CMDMAX - CMDSTART) || (head & 03)) { + ch->ch_bd->state = BOARD_FAILED; + return; + } + + /* + * Put the data in the circular command buffer. + */ + writeb(cmd, (char *) (vaddr + head + CMDSTART + 0)); + writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1)); + writeb(byte1, (char *) (vaddr + head + CMDSTART + 2)); + writeb(byte2, (char *) (vaddr + head + CMDSTART + 3)); + + head = (head + 4) & (CMDMAX - CMDSTART - 4); + + writew(head, &(cm_addr->cm_head)); + + /* + * Wait if necessary before updating the head + * pointer to limit the number of outstanding + * commands to the FEP. If the time spent waiting + * is outlandish, declare the FEP dead. + */ + for (count = dgap_count ;;) { + + head = readw(&(cm_addr->cm_head)); + tail = readw(&(cm_addr->cm_tail)); + + n = (head - tail) & (CMDMAX - CMDSTART - 4); + + if (n <= ncmds * sizeof(struct cm_t)) + break; + + if (--count == 0) { + ch->ch_bd->state = BOARD_FAILED; + return; + } + udelay(10); + } +} + +/*======================================================================= + * + * dgap_cmdw - Sends a 1 word command to the FEP. + * + * ch - Pointer to channel structure. + * cmd - Command to be sent. + * word - Integer containing word to be sent. + * ncmds - Wait until ncmds or fewer cmds are left + * in the cmd buffer before returning. + * + *=======================================================================*/ +static void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds) +{ + char *vaddr = NULL; + struct cm_t *cm_addr = NULL; + uint count; + uint n; + u16 head; + u16 tail; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + /* + * Check if board is still alive. + */ + if (ch->ch_bd->state == BOARD_FAILED) + return; + + /* + * Make sure the pointers are in range before + * writing to the FEP memory. + */ + vaddr = ch->ch_bd->re_map_membase; + if (!vaddr) + return; + + cm_addr = (struct cm_t *) (vaddr + CMDBUF); + head = readw(&(cm_addr->cm_head)); + + /* + * Forget it if pointers out of range. + */ + if (head >= (CMDMAX - CMDSTART) || (head & 03)) { + ch->ch_bd->state = BOARD_FAILED; + return; + } + + /* + * Put the data in the circular command buffer. + */ + writeb(cmd, (char *) (vaddr + head + CMDSTART + 0)); + writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1)); + writew((u16) word, (char *) (vaddr + head + CMDSTART + 2)); + + head = (head + 4) & (CMDMAX - CMDSTART - 4); + + writew(head, &(cm_addr->cm_head)); + + /* + * Wait if necessary before updating the head + * pointer to limit the number of outstanding + * commands to the FEP. If the time spent waiting + * is outlandish, declare the FEP dead. + */ + for (count = dgap_count ;;) { + + head = readw(&(cm_addr->cm_head)); + tail = readw(&(cm_addr->cm_tail)); + + n = (head - tail) & (CMDMAX - CMDSTART - 4); + + if (n <= ncmds * sizeof(struct cm_t)) + break; + + if (--count == 0) { + ch->ch_bd->state = BOARD_FAILED; + return; + } + udelay(10); + } +} + +/*======================================================================= + * + * dgap_cmdw_ext - Sends a extended word command to the FEP. + * + * ch - Pointer to channel structure. + * cmd - Command to be sent. + * word - Integer containing word to be sent. + * ncmds - Wait until ncmds or fewer cmds are left + * in the cmd buffer before returning. + * + *=======================================================================*/ +static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds) +{ + char *vaddr = NULL; + struct cm_t *cm_addr = NULL; + uint count; + uint n; + u16 head; + u16 tail; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + /* + * Check if board is still alive. + */ + if (ch->ch_bd->state == BOARD_FAILED) + return; + + /* + * Make sure the pointers are in range before + * writing to the FEP memory. + */ + vaddr = ch->ch_bd->re_map_membase; + if (!vaddr) + return; + + cm_addr = (struct cm_t *) (vaddr + CMDBUF); + head = readw(&(cm_addr->cm_head)); + + /* + * Forget it if pointers out of range. + */ + if (head >= (CMDMAX - CMDSTART) || (head & 03)) { + ch->ch_bd->state = BOARD_FAILED; + return; + } + + /* + * Put the data in the circular command buffer. + */ + + /* Write an FF to tell the FEP that we want an extended command */ + writeb((uchar) 0xff, (char *) (vaddr + head + CMDSTART + 0)); + + writeb((uchar) ch->ch_portnum, (uchar *) (vaddr + head + CMDSTART + 1)); + writew((u16) cmd, (char *) (vaddr + head + CMDSTART + 2)); + + /* + * If the second part of the command won't fit, + * put it at the beginning of the circular buffer. + */ + if (((head + 4) >= ((CMDMAX - CMDSTART)) || (head & 03))) + writew((u16) word, (char *) (vaddr + CMDSTART)); + else + writew((u16) word, (char *) (vaddr + head + CMDSTART + 4)); + + head = (head + 8) & (CMDMAX - CMDSTART - 4); + + writew(head, &(cm_addr->cm_head)); + + /* + * Wait if necessary before updating the head + * pointer to limit the number of outstanding + * commands to the FEP. If the time spent waiting + * is outlandish, declare the FEP dead. + */ + for (count = dgap_count ;;) { + + head = readw(&(cm_addr->cm_head)); + tail = readw(&(cm_addr->cm_tail)); + + n = (head - tail) & (CMDMAX - CMDSTART - 4); + + if (n <= ncmds * sizeof(struct cm_t)) + break; + + if (--count == 0) { + ch->ch_bd->state = BOARD_FAILED; + return; + } + udelay(10); + } +} + +/*======================================================================= + * + * dgap_wmove - Write data to FEP buffer. + * + * ch - Pointer to channel structure. + * buf - Poiter to characters to be moved. + * cnt - Number of characters to move. + * + *=======================================================================*/ +static void dgap_wmove(struct channel_t *ch, char *buf, uint cnt) +{ + int n; + char *taddr; + struct bs_t *bs; + u16 head; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + /* + * Check parameters. + */ + bs = ch->ch_bs; + head = readw(&(bs->tx_head)); + + /* + * If pointers are out of range, just return. + */ + if ((cnt > ch->ch_tsize) || + (unsigned)(head - ch->ch_tstart) >= ch->ch_tsize) + return; + + /* + * If the write wraps over the top of the circular buffer, + * move the portion up to the wrap point, and reset the + * pointers to the bottom. + */ + n = ch->ch_tstart + ch->ch_tsize - head; + + if (cnt >= n) { + cnt -= n; + taddr = ch->ch_taddr + head; + memcpy_toio(taddr, buf, n); + head = ch->ch_tstart; + buf += n; + } + + /* + * Move rest of data. + */ + taddr = ch->ch_taddr + head; + n = cnt; + memcpy_toio(taddr, buf, n); + head += cnt; + + writew(head, &(bs->tx_head)); +} + +/* + * Retrives the current custom baud rate from FEP memory, + * and returns it back to the user. + * Returns 0 on error. + */ +static uint dgap_get_custom_baud(struct channel_t *ch) +{ + uchar *vaddr; + ulong offset = 0; + uint value = 0; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + + if (!ch->ch_bd || ch->ch_bd->magic != DGAP_BOARD_MAGIC) + return 0; + + if (!(ch->ch_bd->bd_flags & BD_FEP5PLUS)) + return 0; + + vaddr = ch->ch_bd->re_map_membase; + + if (!vaddr) + return 0; + + /* + * Go get from fep mem, what the fep + * believes the custom baud rate is. + */ + offset = ((((*(unsigned short *)(vaddr + ECS_SEG)) << 4) + + (ch->ch_portnum * 0x28) + LINE_SPEED)); + + value = readw(vaddr + offset); + return value; +} + +/* + * Calls the firmware to reset this channel. + */ +static void dgap_firmware_reset_port(struct channel_t *ch) +{ + dgap_cmdb(ch, CHRESET, 0, 0, 0); + + /* + * Now that the channel is reset, we need to make sure + * all the current settings get reapplied to the port + * in the firmware. + * + * So we will set the driver's cache of firmware + * settings all to 0, and then call param. + */ + ch->ch_fepiflag = 0; + ch->ch_fepcflag = 0; + ch->ch_fepoflag = 0; + ch->ch_fepstartc = 0; + ch->ch_fepstopc = 0; + ch->ch_fepastartc = 0; + ch->ch_fepastopc = 0; + ch->ch_mostat = 0; + ch->ch_hflow = 0; +} + +/*======================================================================= + * + * dgap_param - Set Digi parameters. + * + * struct tty_struct * - TTY for port. + * + *=======================================================================*/ +static int dgap_param(struct tty_struct *tty) +{ + struct ktermios *ts; + struct board_t *bd; + struct channel_t *ch; + struct bs_t *bs; + struct un_t *un; + u16 head; + u16 cflag; + u16 iflag; + uchar mval; + uchar hflow; + + if (!tty || tty->magic != TTY_MAGIC) + return -ENXIO; + + un = (struct un_t *) tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -ENXIO; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -ENXIO; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return -ENXIO; + + bs = ch->ch_bs; + if (!bs) + return -ENXIO; + + ts = &tty->termios; + + /* + * If baud rate is zero, flush queues, and set mval to drop DTR. + */ + if ((ch->ch_c_cflag & (CBAUD)) == 0) { + + /* flush rx */ + head = readw(&(ch->ch_bs->rx_head)); + writew(head, &(ch->ch_bs->rx_tail)); + + /* flush tx */ + head = readw(&(ch->ch_bs->tx_head)); + writew(head, &(ch->ch_bs->tx_tail)); + + ch->ch_flags |= (CH_BAUD0); + + /* Drop RTS and DTR */ + ch->ch_mval &= ~(D_RTS(ch)|D_DTR(ch)); + mval = D_DTR(ch) | D_RTS(ch); + ch->ch_baud_info = 0; + + } else if (ch->ch_custom_speed && (bd->bd_flags & BD_FEP5PLUS)) { + /* + * Tell the fep to do the command + */ + + dgap_cmdw_ext(ch, 0xff01, ch->ch_custom_speed, 0); + + /* + * Now go get from fep mem, what the fep + * believes the custom baud rate is. + */ + ch->ch_custom_speed = dgap_get_custom_baud(ch); + ch->ch_baud_info = ch->ch_custom_speed; + + /* Handle transition from B0 */ + if (ch->ch_flags & CH_BAUD0) { + ch->ch_flags &= ~(CH_BAUD0); + ch->ch_mval |= (D_RTS(ch)|D_DTR(ch)); + } + mval = D_DTR(ch) | D_RTS(ch); + + } else { + /* + * Set baud rate, character size, and parity. + */ + + + int iindex = 0; + int jindex = 0; + int baud = 0; + + ulong bauds[4][16] = { + { /* slowbaud */ + 0, 50, 75, 110, + 134, 150, 200, 300, + 600, 1200, 1800, 2400, + 4800, 9600, 19200, 38400 }, + { /* slowbaud & CBAUDEX */ + 0, 57600, 115200, 230400, + 460800, 150, 200, 921600, + 600, 1200, 1800, 2400, + 4800, 9600, 19200, 38400 }, + { /* fastbaud */ + 0, 57600, 76800, 115200, + 14400, 57600, 230400, 76800, + 115200, 230400, 28800, 460800, + 921600, 9600, 19200, 38400 }, + { /* fastbaud & CBAUDEX */ + 0, 57600, 115200, 230400, + 460800, 150, 200, 921600, + 600, 1200, 1800, 2400, + 4800, 9600, 19200, 38400 } + }; + + /* + * Only use the TXPrint baud rate if the + * terminal unit is NOT open + */ + if (!(ch->ch_tun.un_flags & UN_ISOPEN) && + (un->un_type == DGAP_PRINT)) + baud = C_BAUD(ch->ch_pun.un_tty) & 0xff; + else + baud = C_BAUD(ch->ch_tun.un_tty) & 0xff; + + if (ch->ch_c_cflag & CBAUDEX) + iindex = 1; + + if (ch->ch_digi.digi_flags & DIGI_FAST) + iindex += 2; + + jindex = baud; + + if ((iindex >= 0) && (iindex < 4) && + (jindex >= 0) && (jindex < 16)) + baud = bauds[iindex][jindex]; + else + baud = 0; + + if (baud == 0) + baud = 9600; + + ch->ch_baud_info = baud; + + /* + * CBAUD has bit position 0x1000 set these days to + * indicate Linux baud rate remap. + * We use a different bit assignment for high speed. + * Clear this bit out while grabbing the parts of + * "cflag" we want. + */ + cflag = ch->ch_c_cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | + CSTOPB | CSIZE); + + /* + * HUPCL bit is used by FEP to indicate fast baud + * table is to be used. + */ + if ((ch->ch_digi.digi_flags & DIGI_FAST) || + (ch->ch_c_cflag & CBAUDEX)) + cflag |= HUPCL; + + if ((ch->ch_c_cflag & CBAUDEX) && + !(ch->ch_digi.digi_flags & DIGI_FAST)) { + /* + * The below code is trying to guarantee that only + * baud rates 115200, 230400, 460800, 921600 are + * remapped. We use exclusive or because the various + * baud rates share common bit positions and therefore + * can't be tested for easily. + */ + tcflag_t tcflag = (ch->ch_c_cflag & CBAUD) | CBAUDEX; + int baudpart = 0; + + /* + * Map high speed requests to index + * into FEP's baud table + */ + switch (tcflag) { + case B57600: + baudpart = 1; + break; +#ifdef B76800 + case B76800: + baudpart = 2; + break; +#endif + case B115200: + baudpart = 3; + break; + case B230400: + baudpart = 9; + break; + case B460800: + baudpart = 11; + break; +#ifdef B921600 + case B921600: + baudpart = 12; + break; +#endif + default: + baudpart = 0; + } + + if (baudpart) + cflag = (cflag & ~(CBAUD | CBAUDEX)) | baudpart; + } + + cflag &= 0xffff; + + if (cflag != ch->ch_fepcflag) { + ch->ch_fepcflag = (u16) (cflag & 0xffff); + + /* + * Okay to have channel and board + * locks held calling this + */ + dgap_cmdw(ch, SCFLAG, (u16) cflag, 0); + } + + /* Handle transition from B0 */ + if (ch->ch_flags & CH_BAUD0) { + ch->ch_flags &= ~(CH_BAUD0); + ch->ch_mval |= (D_RTS(ch)|D_DTR(ch)); + } + mval = D_DTR(ch) | D_RTS(ch); + } + + /* + * Get input flags. + */ + iflag = ch->ch_c_iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | + INPCK | ISTRIP | IXON | IXANY | IXOFF); + + if ((ch->ch_startc == _POSIX_VDISABLE) || + (ch->ch_stopc == _POSIX_VDISABLE)) { + iflag &= ~(IXON | IXOFF); + ch->ch_c_iflag &= ~(IXON | IXOFF); + } + + /* + * Only the IBM Xr card can switch between + * 232 and 422 modes on the fly + */ + if (bd->device == PCI_DEV_XR_IBM_DID) { + if (ch->ch_digi.digi_flags & DIGI_422) + dgap_cmdb(ch, SCOMMODE, MODE_422, 0, 0); + else + dgap_cmdb(ch, SCOMMODE, MODE_232, 0, 0); + } + + if (ch->ch_digi.digi_flags & DIGI_ALTPIN) + iflag |= IALTPIN; + + if (iflag != ch->ch_fepiflag) { + ch->ch_fepiflag = iflag; + + /* Okay to have channel and board locks held calling this */ + dgap_cmdw(ch, SIFLAG, (u16) ch->ch_fepiflag, 0); + } + + /* + * Select hardware handshaking. + */ + hflow = 0; + + if (ch->ch_c_cflag & CRTSCTS) + hflow |= (D_RTS(ch) | D_CTS(ch)); + if (ch->ch_digi.digi_flags & RTSPACE) + hflow |= D_RTS(ch); + if (ch->ch_digi.digi_flags & DTRPACE) + hflow |= D_DTR(ch); + if (ch->ch_digi.digi_flags & CTSPACE) + hflow |= D_CTS(ch); + if (ch->ch_digi.digi_flags & DSRPACE) + hflow |= D_DSR(ch); + if (ch->ch_digi.digi_flags & DCDPACE) + hflow |= D_CD(ch); + + if (hflow != ch->ch_hflow) { + ch->ch_hflow = hflow; + + /* Okay to have channel and board locks held calling this */ + dgap_cmdb(ch, SHFLOW, (uchar) hflow, 0xff, 0); + } + + + /* + * Set RTS and/or DTR Toggle if needed, + * but only if product is FEP5+ based. + */ + if (bd->bd_flags & BD_FEP5PLUS) { + u16 hflow2 = 0; + if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) + hflow2 |= (D_RTS(ch)); + if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) + hflow2 |= (D_DTR(ch)); + + dgap_cmdw_ext(ch, 0xff03, hflow2, 0); + } + + /* + * Set modem control lines. + */ + + mval ^= ch->ch_mforce & (mval ^ ch->ch_mval); + + if (ch->ch_mostat ^ mval) { + ch->ch_mostat = mval; + + /* Okay to have channel and board locks held calling this */ + dgap_cmdb(ch, SMODEM, (uchar) mval, D_RTS(ch)|D_DTR(ch), 0); + } + + /* + * Read modem signals, and then call carrier function. + */ + ch->ch_mistat = readb(&(bs->m_stat)); + dgap_carrier(ch); + + /* + * Set the start and stop characters. + */ + if (ch->ch_startc != ch->ch_fepstartc || + ch->ch_stopc != ch->ch_fepstopc) { + ch->ch_fepstartc = ch->ch_startc; + ch->ch_fepstopc = ch->ch_stopc; + + /* Okay to have channel and board locks held calling this */ + dgap_cmdb(ch, SFLOWC, ch->ch_fepstartc, ch->ch_fepstopc, 0); + } + + /* + * Set the Auxiliary start and stop characters. + */ + if (ch->ch_astartc != ch->ch_fepastartc || + ch->ch_astopc != ch->ch_fepastopc) { + ch->ch_fepastartc = ch->ch_astartc; + ch->ch_fepastopc = ch->ch_astopc; + + /* Okay to have channel and board locks held calling this */ + dgap_cmdb(ch, SAFLOWC, ch->ch_fepastartc, ch->ch_fepastopc, 0); + } + + return 0; +} + +/* + * dgap_parity_scan() + * + * Convert the FEP5 way of reporting parity errors and breaks into + * the Linux line discipline way. + */ +static void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf, + unsigned char *fbuf, int *len) +{ + int l = *len; + int count = 0; + unsigned char *in, *cout, *fout; + unsigned char c; + + in = cbuf; + cout = cbuf; + fout = fbuf; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + while (l--) { + c = *in++; + switch (ch->pscan_state) { + default: + /* reset to sanity and fall through */ + ch->pscan_state = 0; + + case 0: + /* No FF seen yet */ + if (c == (unsigned char) '\377') + /* delete this character from stream */ + ch->pscan_state = 1; + else { + *cout++ = c; + *fout++ = TTY_NORMAL; + count += 1; + } + break; + + case 1: + /* first FF seen */ + if (c == (unsigned char) '\377') { + /* doubled ff, transform to single ff */ + *cout++ = c; + *fout++ = TTY_NORMAL; + count += 1; + ch->pscan_state = 0; + } else { + /* save value examination in next state */ + ch->pscan_savechar = c; + ch->pscan_state = 2; + } + break; + + case 2: + /* third character of ff sequence */ + + *cout++ = c; + + if (ch->pscan_savechar == 0x0) { + + if (c == 0x0) { + ch->ch_err_break++; + *fout++ = TTY_BREAK; + } else { + ch->ch_err_parity++; + *fout++ = TTY_PARITY; + } + } + + count += 1; + ch->pscan_state = 0; + } + } + *len = count; +} + +static void dgap_write_wakeup(struct board_t *bd, struct channel_t *ch, + struct un_t *un, u32 mask, + unsigned long *irq_flags1, + unsigned long *irq_flags2) +{ + if (!(un->un_flags & mask)) + return; + + un->un_flags &= ~mask; + + if (!(un->un_flags & UN_ISOPEN)) + return; + + if ((un->un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + un->un_tty->ldisc->ops->write_wakeup) { + spin_unlock_irqrestore(&ch->ch_lock, *irq_flags2); + spin_unlock_irqrestore(&bd->bd_lock, *irq_flags1); + + (un->un_tty->ldisc->ops->write_wakeup)(un->un_tty); + + spin_lock_irqsave(&bd->bd_lock, *irq_flags1); + spin_lock_irqsave(&ch->ch_lock, *irq_flags2); + } + wake_up_interruptible(&un->un_tty->write_wait); + wake_up_interruptible(&un->un_flags_wait); +} + +/*======================================================================= + * + * dgap_event - FEP to host event processing routine. + * + * bd - Board of current event. + * + *=======================================================================*/ +static int dgap_event(struct board_t *bd) +{ + struct channel_t *ch; + ulong lock_flags; + ulong lock_flags2; + struct bs_t *bs; + uchar *event; + uchar *vaddr = NULL; + struct ev_t *eaddr = NULL; + uint head; + uint tail; + int port; + int reason; + int modem; + int b1; + + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return -ENXIO; + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + + vaddr = bd->re_map_membase; + + if (!vaddr) { + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return -ENXIO; + } + + eaddr = (struct ev_t *) (vaddr + EVBUF); + + /* Get our head and tail */ + head = readw(&(eaddr->ev_head)); + tail = readw(&(eaddr->ev_tail)); + + /* + * Forget it if pointers out of range. + */ + + if (head >= EVMAX - EVSTART || tail >= EVMAX - EVSTART || + (head | tail) & 03) { + /* Let go of board lock */ + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + return -ENXIO; + } + + /* + * Loop to process all the events in the buffer. + */ + while (tail != head) { + + /* + * Get interrupt information. + */ + + event = bd->re_map_membase + tail + EVSTART; + + port = event[0]; + reason = event[1]; + modem = event[2]; + b1 = event[3]; + + /* + * Make sure the interrupt is valid. + */ + if (port >= bd->nasync) + goto next; + + if (!(reason & (IFMODEM | IFBREAK | IFTLW | IFTEM | IFDATA))) + goto next; + + ch = bd->channels[port]; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + goto next; + + /* + * If we have made it here, the event was valid. + * Lock down the channel. + */ + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + bs = ch->ch_bs; + + if (!bs) { + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + goto next; + } + + /* + * Process received data. + */ + if (reason & IFDATA) { + + /* + * ALL LOCKS *MUST* BE DROPPED BEFORE CALLING INPUT! + * input could send some data to ld, which in turn + * could do a callback to one of our other functions. + */ + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + dgap_input(ch); + + spin_lock_irqsave(&bd->bd_lock, lock_flags); + spin_lock_irqsave(&ch->ch_lock, lock_flags2); + + if (ch->ch_flags & CH_RACTIVE) + ch->ch_flags |= CH_RENABLE; + else + writeb(1, &(bs->idata)); + + if (ch->ch_flags & CH_RWAIT) { + ch->ch_flags &= ~CH_RWAIT; + + wake_up_interruptible + (&ch->ch_tun.un_flags_wait); + } + } + + /* + * Process Modem change signals. + */ + if (reason & IFMODEM) { + ch->ch_mistat = modem; + dgap_carrier(ch); + } + + /* + * Process break. + */ + if (reason & IFBREAK) { + + if (ch->ch_tun.un_tty) { + /* A break has been indicated */ + ch->ch_err_break++; + tty_buffer_request_room + (ch->ch_tun.un_tty->port, 1); + tty_insert_flip_char(ch->ch_tun.un_tty->port, + 0, TTY_BREAK); + tty_flip_buffer_push(ch->ch_tun.un_tty->port); + } + } + + /* + * Process Transmit low. + */ + if (reason & IFTLW) { + dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_LOW, + &lock_flags, &lock_flags2); + dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_LOW, + &lock_flags, &lock_flags2); + if (ch->ch_flags & CH_WLOW) { + ch->ch_flags &= ~CH_WLOW; + wake_up_interruptible(&ch->ch_flags_wait); + } + } + + /* + * Process Transmit empty. + */ + if (reason & IFTEM) { + dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_EMPTY, + &lock_flags, &lock_flags2); + dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_EMPTY, + &lock_flags, &lock_flags2); + if (ch->ch_flags & CH_WEMPTY) { + ch->ch_flags &= ~CH_WEMPTY; + wake_up_interruptible(&ch->ch_flags_wait); + } + } + + spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); + +next: + tail = (tail + 4) & (EVMAX - EVSTART - 4); + } + + writew(tail, &(eaddr->ev_tail)); + spin_unlock_irqrestore(&bd->bd_lock, lock_flags); + + return 0; +} + +static ssize_t dgap_driver_version_show(struct device_driver *ddp, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", DG_PART); +} +static DRIVER_ATTR(version, S_IRUSR, dgap_driver_version_show, NULL); + + +static ssize_t dgap_driver_boards_show(struct device_driver *ddp, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", dgap_NumBoards); +} +static DRIVER_ATTR(boards, S_IRUSR, dgap_driver_boards_show, NULL); + + +static ssize_t dgap_driver_maxboards_show(struct device_driver *ddp, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", MAXBOARDS); +} +static DRIVER_ATTR(maxboards, S_IRUSR, dgap_driver_maxboards_show, NULL); + + +static ssize_t dgap_driver_pollcounter_show(struct device_driver *ddp, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%ld\n", dgap_poll_counter); +} +static DRIVER_ATTR(pollcounter, S_IRUSR, dgap_driver_pollcounter_show, NULL); + +static ssize_t dgap_driver_pollrate_show(struct device_driver *ddp, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%dms\n", dgap_poll_tick); +} + +static ssize_t dgap_driver_pollrate_store(struct device_driver *ddp, + const char *buf, size_t count) +{ + if (sscanf(buf, "%d\n", &dgap_poll_tick) != 1) + return -EINVAL; + return count; +} +static DRIVER_ATTR(pollrate, (S_IRUSR | S_IWUSR), dgap_driver_pollrate_show, + dgap_driver_pollrate_store); + +static int dgap_create_driver_sysfiles(struct pci_driver *dgap_driver) +{ + int rc = 0; + struct device_driver *driverfs = &dgap_driver->driver; + + rc |= driver_create_file(driverfs, &driver_attr_version); + rc |= driver_create_file(driverfs, &driver_attr_boards); + rc |= driver_create_file(driverfs, &driver_attr_maxboards); + rc |= driver_create_file(driverfs, &driver_attr_pollrate); + rc |= driver_create_file(driverfs, &driver_attr_pollcounter); + + return rc; +} + +static void dgap_remove_driver_sysfiles(struct pci_driver *dgap_driver) +{ + struct device_driver *driverfs = &dgap_driver->driver; + driver_remove_file(driverfs, &driver_attr_version); + driver_remove_file(driverfs, &driver_attr_boards); + driver_remove_file(driverfs, &driver_attr_maxboards); + driver_remove_file(driverfs, &driver_attr_pollrate); + driver_remove_file(driverfs, &driver_attr_pollcounter); +} + +static struct board_t *dgap_verify_board(struct device *p) +{ + struct board_t *bd; + + if (!p) + return NULL; + + bd = dev_get_drvdata(p); + if (!bd || bd->magic != DGAP_BOARD_MAGIC || bd->state != BOARD_READY) + return NULL; + + return bd; +} + +static ssize_t dgap_ports_state_show(struct device *p, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + bd = dgap_verify_board(p); + if (!bd) + return 0; + + for (i = 0; i < bd->nasync; i++) { + count += snprintf(buf + count, PAGE_SIZE - count, + "%d %s\n", bd->channels[i]->ch_portnum, + bd->channels[i]->ch_open_count ? "Open" : "Closed"); + } + return count; +} +static DEVICE_ATTR(ports_state, S_IRUSR, dgap_ports_state_show, NULL); + +static ssize_t dgap_ports_baud_show(struct device *p, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + bd = dgap_verify_board(p); + if (!bd) + return 0; + + for (i = 0; i < bd->nasync; i++) { + count += snprintf(buf + count, PAGE_SIZE - count, "%d %d\n", + bd->channels[i]->ch_portnum, + bd->channels[i]->ch_baud_info); + } + return count; +} +static DEVICE_ATTR(ports_baud, S_IRUSR, dgap_ports_baud_show, NULL); + +static ssize_t dgap_ports_msignals_show(struct device *p, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + bd = dgap_verify_board(p); + if (!bd) + return 0; + + for (i = 0; i < bd->nasync; i++) { + if (bd->channels[i]->ch_open_count) + count += snprintf(buf + count, PAGE_SIZE - count, + "%d %s %s %s %s %s %s\n", + bd->channels[i]->ch_portnum, + (bd->channels[i]->ch_mostat & + UART_MCR_RTS) ? "RTS" : "", + (bd->channels[i]->ch_mistat & + UART_MSR_CTS) ? "CTS" : "", + (bd->channels[i]->ch_mostat & + UART_MCR_DTR) ? "DTR" : "", + (bd->channels[i]->ch_mistat & + UART_MSR_DSR) ? "DSR" : "", + (bd->channels[i]->ch_mistat & + UART_MSR_DCD) ? "DCD" : "", + (bd->channels[i]->ch_mistat & + UART_MSR_RI) ? "RI" : ""); + else + count += snprintf(buf + count, PAGE_SIZE - count, + "%d\n", bd->channels[i]->ch_portnum); + } + return count; +} +static DEVICE_ATTR(ports_msignals, S_IRUSR, dgap_ports_msignals_show, NULL); + +static ssize_t dgap_ports_iflag_show(struct device *p, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + bd = dgap_verify_board(p); + if (!bd) + return 0; + + for (i = 0; i < bd->nasync; i++) + count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", + bd->channels[i]->ch_portnum, + bd->channels[i]->ch_c_iflag); + return count; +} +static DEVICE_ATTR(ports_iflag, S_IRUSR, dgap_ports_iflag_show, NULL); + +static ssize_t dgap_ports_cflag_show(struct device *p, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + bd = dgap_verify_board(p); + if (!bd) + return 0; + + for (i = 0; i < bd->nasync; i++) + count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", + bd->channels[i]->ch_portnum, + bd->channels[i]->ch_c_cflag); + return count; +} +static DEVICE_ATTR(ports_cflag, S_IRUSR, dgap_ports_cflag_show, NULL); + +static ssize_t dgap_ports_oflag_show(struct device *p, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + bd = dgap_verify_board(p); + if (!bd) + return 0; + + for (i = 0; i < bd->nasync; i++) + count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", + bd->channels[i]->ch_portnum, + bd->channels[i]->ch_c_oflag); + return count; +} +static DEVICE_ATTR(ports_oflag, S_IRUSR, dgap_ports_oflag_show, NULL); + +static ssize_t dgap_ports_lflag_show(struct device *p, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + bd = dgap_verify_board(p); + if (!bd) + return 0; + + for (i = 0; i < bd->nasync; i++) + count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", + bd->channels[i]->ch_portnum, + bd->channels[i]->ch_c_lflag); + return count; +} +static DEVICE_ATTR(ports_lflag, S_IRUSR, dgap_ports_lflag_show, NULL); + +static ssize_t dgap_ports_digi_flag_show(struct device *p, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + bd = dgap_verify_board(p); + if (!bd) + return 0; + + for (i = 0; i < bd->nasync; i++) + count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", + bd->channels[i]->ch_portnum, + bd->channels[i]->ch_digi.digi_flags); + return count; +} +static DEVICE_ATTR(ports_digi_flag, S_IRUSR, dgap_ports_digi_flag_show, NULL); + +static ssize_t dgap_ports_rxcount_show(struct device *p, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + bd = dgap_verify_board(p); + if (!bd) + return 0; + + for (i = 0; i < bd->nasync; i++) + count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n", + bd->channels[i]->ch_portnum, + bd->channels[i]->ch_rxcount); + return count; +} +static DEVICE_ATTR(ports_rxcount, S_IRUSR, dgap_ports_rxcount_show, NULL); + +static ssize_t dgap_ports_txcount_show(struct device *p, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + bd = dgap_verify_board(p); + if (!bd) + return 0; + + for (i = 0; i < bd->nasync; i++) + count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n", + bd->channels[i]->ch_portnum, + bd->channels[i]->ch_txcount); + return count; +} +static DEVICE_ATTR(ports_txcount, S_IRUSR, dgap_ports_txcount_show, NULL); + +/* this function creates the sys files that will export each signal status + * to sysfs each value will be put in a separate filename + */ +static void dgap_create_ports_sysfiles(struct board_t *bd) +{ + dev_set_drvdata(&bd->pdev->dev, bd); + device_create_file(&(bd->pdev->dev), &dev_attr_ports_state); + device_create_file(&(bd->pdev->dev), &dev_attr_ports_baud); + device_create_file(&(bd->pdev->dev), &dev_attr_ports_msignals); + device_create_file(&(bd->pdev->dev), &dev_attr_ports_iflag); + device_create_file(&(bd->pdev->dev), &dev_attr_ports_cflag); + device_create_file(&(bd->pdev->dev), &dev_attr_ports_oflag); + device_create_file(&(bd->pdev->dev), &dev_attr_ports_lflag); + device_create_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag); + device_create_file(&(bd->pdev->dev), &dev_attr_ports_rxcount); + device_create_file(&(bd->pdev->dev), &dev_attr_ports_txcount); +} + +/* removes all the sys files created for that port */ +static void dgap_remove_ports_sysfiles(struct board_t *bd) +{ + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_state); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_baud); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_msignals); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_iflag); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_cflag); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_oflag); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_lflag); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_rxcount); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_txcount); +} + +static ssize_t dgap_tty_state_show(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%s", un->un_open_count ? + "Open" : "Closed"); +} +static DEVICE_ATTR(state, S_IRUSR, dgap_tty_state_show, NULL); + +static ssize_t dgap_tty_baud_show(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_baud_info); +} +static DEVICE_ATTR(baud, S_IRUSR, dgap_tty_baud_show, NULL); + +static ssize_t dgap_tty_msignals_show(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + if (ch->ch_open_count) { + return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n", + (ch->ch_mostat & UART_MCR_RTS) ? "RTS" : "", + (ch->ch_mistat & UART_MSR_CTS) ? "CTS" : "", + (ch->ch_mostat & UART_MCR_DTR) ? "DTR" : "", + (ch->ch_mistat & UART_MSR_DSR) ? "DSR" : "", + (ch->ch_mistat & UART_MSR_DCD) ? "DCD" : "", + (ch->ch_mistat & UART_MSR_RI) ? "RI" : ""); + } + return 0; +} +static DEVICE_ATTR(msignals, S_IRUSR, dgap_tty_msignals_show, NULL); + +static ssize_t dgap_tty_iflag_show(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_iflag); +} +static DEVICE_ATTR(iflag, S_IRUSR, dgap_tty_iflag_show, NULL); + +static ssize_t dgap_tty_cflag_show(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_cflag); +} +static DEVICE_ATTR(cflag, S_IRUSR, dgap_tty_cflag_show, NULL); + +static ssize_t dgap_tty_oflag_show(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_oflag); +} +static DEVICE_ATTR(oflag, S_IRUSR, dgap_tty_oflag_show, NULL); + +static ssize_t dgap_tty_lflag_show(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_lflag); +} +static DEVICE_ATTR(lflag, S_IRUSR, dgap_tty_lflag_show, NULL); + +static ssize_t dgap_tty_digi_flag_show(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags); +} +static DEVICE_ATTR(digi_flag, S_IRUSR, dgap_tty_digi_flag_show, NULL); + +static ssize_t dgap_tty_rxcount_show(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_rxcount); +} +static DEVICE_ATTR(rxcount, S_IRUSR, dgap_tty_rxcount_show, NULL); + +static ssize_t dgap_tty_txcount_show(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_txcount); +} +static DEVICE_ATTR(txcount, S_IRUSR, dgap_tty_txcount_show, NULL); + +static ssize_t dgap_tty_name_show(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + int cn; + int bn; + struct cnode *cptr = NULL; + int found = FALSE; + int ncount = 0; + int starto = 0; + int i = 0; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + bn = bd->boardnum; + cn = ch->ch_portnum; + + for (cptr = bd->bd_config; cptr; cptr = cptr->next) { + + if ((cptr->type == BNODE) && + ((cptr->u.board.type == APORT2_920P) || + (cptr->u.board.type == APORT4_920P) || + (cptr->u.board.type == APORT8_920P) || + (cptr->u.board.type == PAPORT4) || + (cptr->u.board.type == PAPORT8))) { + + found = TRUE; + if (cptr->u.board.v_start) + starto = cptr->u.board.start; + else + starto = 1; + } + + if (cptr->type == TNODE && found == TRUE) { + char *ptr1; + if (strstr(cptr->u.ttyname, "tty")) { + ptr1 = cptr->u.ttyname; + ptr1 += 3; + } else + ptr1 = cptr->u.ttyname; + + for (i = 0; i < dgap_config_get_num_prts(bd); i++) { + if (cn != i) + continue; + + return snprintf(buf, PAGE_SIZE, "%s%s%02d\n", + (un->un_type == DGAP_PRINT) ? + "pr" : "tty", + ptr1, i + starto); + } + } + + if (cptr->type == CNODE) { + + for (i = 0; i < cptr->u.conc.nport; i++) { + if (cn != (i + ncount)) + continue; + + return snprintf(buf, PAGE_SIZE, "%s%s%02ld\n", + (un->un_type == DGAP_PRINT) ? + "pr" : "tty", + cptr->u.conc.id, + i + (cptr->u.conc.v_start ? + cptr->u.conc.start : 1)); + } + + ncount += cptr->u.conc.nport; + } + + if (cptr->type == MNODE) { + + for (i = 0; i < cptr->u.module.nport; i++) { + if (cn != (i + ncount)) + continue; + + return snprintf(buf, PAGE_SIZE, "%s%s%02ld\n", + (un->un_type == DGAP_PRINT) ? + "pr" : "tty", + cptr->u.module.id, + i + (cptr->u.module.v_start ? + cptr->u.module.start : 1)); + } + + ncount += cptr->u.module.nport; + + } + } + + return snprintf(buf, PAGE_SIZE, "%s_dgap_%d_%d\n", + (un->un_type == DGAP_PRINT) ? "pr" : "tty", bn, cn); + +} +static DEVICE_ATTR(custom_name, S_IRUSR, dgap_tty_name_show, NULL); + +static struct attribute *dgap_sysfs_tty_entries[] = { + &dev_attr_state.attr, + &dev_attr_baud.attr, + &dev_attr_msignals.attr, + &dev_attr_iflag.attr, + &dev_attr_cflag.attr, + &dev_attr_oflag.attr, + &dev_attr_lflag.attr, + &dev_attr_digi_flag.attr, + &dev_attr_rxcount.attr, + &dev_attr_txcount.attr, + &dev_attr_custom_name.attr, + NULL +}; + +static struct attribute_group dgap_tty_attribute_group = { + .name = NULL, + .attrs = dgap_sysfs_tty_entries, +}; + +static void dgap_create_tty_sysfs(struct un_t *un, struct device *c) +{ + int ret; + + ret = sysfs_create_group(&c->kobj, &dgap_tty_attribute_group); + if (ret) + return; + + dev_set_drvdata(c, un); + +} + +static void dgap_remove_tty_sysfs(struct device *c) +{ + sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group); +} + +/* + * Parse a configuration file read into memory as a string. + */ +static int dgap_parsefile(char **in, int Remove) +{ + struct cnode *p, *brd, *line, *conc; + int rc; + char *s = NULL; + int linecnt = 0; + + p = &dgap_head; + brd = line = conc = NULL; + + /* perhaps we are adding to an existing list? */ + while (p->next != NULL) + p = p->next; + + /* file must start with a BEGIN */ + while ((rc = dgap_gettok(in, p)) != BEGIN) { + if (rc == 0) { + dgap_err("unexpected EOF"); + return -1; + } + } + + for (; ;) { + rc = dgap_gettok(in, p); + if (rc == 0) { + dgap_err("unexpected EOF"); + return -1; + } + + switch (rc) { + case 0: + dgap_err("unexpected end of file"); + return -1; + + case BEGIN: /* should only be 1 begin */ + dgap_err("unexpected config_begin\n"); + return -1; + + case END: + return 0; + + case BOARD: /* board info */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(BNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + + p->u.board.status = dgap_savestring("No"); + line = conc = NULL; + brd = p; + linecnt = -1; + break; + + case APORT2_920P: /* AccelePort_4 */ + if (p->type != BNODE) { + dgap_err("unexpected Digi_2r_920 string"); + return -1; + } + p->u.board.type = APORT2_920P; + p->u.board.v_type = 1; + break; + + case APORT4_920P: /* AccelePort_4 */ + if (p->type != BNODE) { + dgap_err("unexpected Digi_4r_920 string"); + return -1; + } + p->u.board.type = APORT4_920P; + p->u.board.v_type = 1; + break; + + case APORT8_920P: /* AccelePort_8 */ + if (p->type != BNODE) { + dgap_err("unexpected Digi_8r_920 string"); + return -1; + } + p->u.board.type = APORT8_920P; + p->u.board.v_type = 1; + break; + + case PAPORT4: /* AccelePort_4 PCI */ + if (p->type != BNODE) { + dgap_err("unexpected Digi_4r(PCI) string"); + return -1; + } + p->u.board.type = PAPORT4; + p->u.board.v_type = 1; + break; + + case PAPORT8: /* AccelePort_8 PCI */ + if (p->type != BNODE) { + dgap_err("unexpected Digi_8r string"); + return -1; + } + p->u.board.type = PAPORT8; + p->u.board.v_type = 1; + break; + + case PCX: /* PCI C/X */ + if (p->type != BNODE) { + dgap_err("unexpected Digi_C/X_(PCI) string"); + return -1; + } + p->u.board.type = PCX; + p->u.board.v_type = 1; + p->u.board.conc1 = 0; + p->u.board.conc2 = 0; + p->u.board.module1 = 0; + p->u.board.module2 = 0; + break; + + case PEPC: /* PCI EPC/X */ + if (p->type != BNODE) { + dgap_err("unexpected \"Digi_EPC/X_(PCI)\" string"); + return -1; + } + p->u.board.type = PEPC; + p->u.board.v_type = 1; + p->u.board.conc1 = 0; + p->u.board.conc2 = 0; + p->u.board.module1 = 0; + p->u.board.module2 = 0; + break; + + case PPCM: /* PCI/Xem */ + if (p->type != BNODE) { + dgap_err("unexpected PCI/Xem string"); + return -1; + } + p->u.board.type = PPCM; + p->u.board.v_type = 1; + p->u.board.conc1 = 0; + p->u.board.conc2 = 0; + break; + + case IO: /* i/o port */ + if (p->type != BNODE) { + dgap_err("IO port only vaild for boards"); + return -1; + } + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.board.portstr = dgap_savestring(s); + if (kstrtol(s, 0, &p->u.board.port)) { + dgap_err("bad number for IO port"); + return -1; + } + p->u.board.v_port = 1; + break; + + case MEM: /* memory address */ + if (p->type != BNODE) { + dgap_err("memory address only vaild for boards"); + return -1; + } + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.board.addrstr = dgap_savestring(s); + if (kstrtoul(s, 0, &p->u.board.addr)) { + dgap_err("bad number for memory address"); + return -1; + } + p->u.board.v_addr = 1; + break; + + case PCIINFO: /* pci information */ + if (p->type != BNODE) { + dgap_err("memory address only vaild for boards"); + return -1; + } + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.board.pcibusstr = dgap_savestring(s); + if (kstrtoul(s, 0, &p->u.board.pcibus)) { + dgap_err("bad number for pci bus"); + return -1; + } + p->u.board.v_pcibus = 1; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.board.pcislotstr = dgap_savestring(s); + if (kstrtoul(s, 0, &p->u.board.pcislot)) { + dgap_err("bad number for pci slot"); + return -1; + } + p->u.board.v_pcislot = 1; + break; + + case METHOD: + if (p->type != BNODE) { + dgap_err("install method only vaild for boards"); + return -1; + } + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.board.method = dgap_savestring(s); + p->u.board.v_method = 1; + break; + + case STATUS: + if (p->type != BNODE) { + dgap_err("config status only vaild for boards"); + return -1; + } + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.board.status = dgap_savestring(s); + break; + + case NPORTS: /* number of ports */ + if (p->type == BNODE) { + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.board.nport)) { + dgap_err("bad number for number of ports"); + return -1; + } + p->u.board.v_nport = 1; + } else if (p->type == CNODE) { + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.conc.nport)) { + dgap_err("bad number for number of ports"); + return -1; + } + p->u.conc.v_nport = 1; + } else if (p->type == MNODE) { + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.module.nport)) { + dgap_err("bad number for number of ports"); + return -1; + } + p->u.module.v_nport = 1; + } else { + dgap_err("nports only valid for concentrators or modules"); + return -1; + } + break; + + case ID: /* letter ID used in tty name */ + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + + p->u.board.status = dgap_savestring(s); + + if (p->type == CNODE) { + p->u.conc.id = dgap_savestring(s); + p->u.conc.v_id = 1; + } else if (p->type == MNODE) { + p->u.module.id = dgap_savestring(s); + p->u.module.v_id = 1; + } else { + dgap_err("id only valid for concentrators or modules"); + return -1; + } + break; + + case STARTO: /* start offset of ID */ + if (p->type == BNODE) { + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.board.start)) { + dgap_err("bad number for start of tty count"); + return -1; + } + p->u.board.v_start = 1; + } else if (p->type == CNODE) { + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.conc.start)) { + dgap_err("bad number for start of tty count"); + return -1; + } + p->u.conc.v_start = 1; + } else if (p->type == MNODE) { + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.module.start)) { + dgap_err("bad number for start of tty count"); + return -1; + } + p->u.module.v_start = 1; + } else { + dgap_err("start only valid for concentrators or modules"); + return -1; + } + break; + + case TTYN: /* tty name prefix */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(TNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (!s) { + dgap_err("unexpeced end of file"); + return -1; + } + p->u.ttyname = dgap_savestring(s); + if (!p->u.ttyname) { + dgap_err("out of memory"); + return -1; + } + break; + + case CU: /* cu name prefix */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(CUNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (!s) { + dgap_err("unexpeced end of file"); + return -1; + } + p->u.cuname = dgap_savestring(s); + if (!p->u.cuname) { + dgap_err("out of memory"); + return -1; + } + break; + + case LINE: /* line information */ + if (dgap_checknode(p)) + return -1; + if (brd == NULL) { + dgap_err("must specify board before line info"); + return -1; + } + switch (brd->u.board.type) { + case PPCM: + dgap_err("line not vaild for PC/em"); + return -1; + } + p->next = dgap_newnode(LNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + conc = NULL; + line = p; + linecnt++; + break; + + case CONC: /* concentrator information */ + if (dgap_checknode(p)) + return -1; + if (line == NULL) { + dgap_err("must specify line info before concentrator"); + return -1; + } + p->next = dgap_newnode(CNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + conc = p; + if (linecnt) + brd->u.board.conc2++; + else + brd->u.board.conc1++; + + break; + + case CX: /* c/x type concentrator */ + if (p->type != CNODE) { + dgap_err("cx only valid for concentrators"); + return -1; + } + p->u.conc.type = CX; + p->u.conc.v_type = 1; + break; + + case EPC: /* epc type concentrator */ + if (p->type != CNODE) { + dgap_err("cx only valid for concentrators"); + return -1; + } + p->u.conc.type = EPC; + p->u.conc.v_type = 1; + break; + + case MOD: /* EBI module */ + if (dgap_checknode(p)) + return -1; + if (brd == NULL) { + dgap_err("must specify board info before EBI modules"); + return -1; + } + switch (brd->u.board.type) { + case PPCM: + linecnt = 0; + break; + default: + if (conc == NULL) { + dgap_err("must specify concentrator info before EBI module"); + return -1; + } + } + p->next = dgap_newnode(MNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + if (linecnt) + brd->u.board.module2++; + else + brd->u.board.module1++; + + break; + + case PORTS: /* ports type EBI module */ + if (p->type != MNODE) { + dgap_err("ports only valid for EBI modules"); + return -1; + } + p->u.module.type = PORTS; + p->u.module.v_type = 1; + break; + + case MODEM: /* ports type EBI module */ + if (p->type != MNODE) { + dgap_err("modem only valid for modem modules"); + return -1; + } + p->u.module.type = MODEM; + p->u.module.v_type = 1; + break; + + case CABLE: + if (p->type == LNODE) { + s = dgap_getword(in); + if (!s) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.line.cable = dgap_savestring(s); + p->u.line.v_cable = 1; + } + break; + + case SPEED: /* sync line speed indication */ + if (p->type == LNODE) { + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.line.speed)) { + dgap_err("bad number for line speed"); + return -1; + } + p->u.line.v_speed = 1; + } else if (p->type == CNODE) { + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.conc.speed)) { + dgap_err("bad number for line speed"); + return -1; + } + p->u.conc.v_speed = 1; + } else { + dgap_err("speed valid only for lines or concentrators."); + return -1; + } + break; + + case CONNECT: + if (p->type == CNODE) { + s = dgap_getword(in); + if (!s) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.conc.connect = dgap_savestring(s); + p->u.conc.v_connect = 1; + } + break; + case PRINT: /* transparent print name prefix */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(PNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (!s) { + dgap_err("unexpeced end of file"); + return -1; + } + p->u.printname = dgap_savestring(s); + if (!p->u.printname) { + dgap_err("out of memory"); + return -1; + } + break; + + case CMAJOR: /* major number */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(JNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.majornumber)) { + dgap_err("bad number for major number"); + return -1; + } + break; + + case ALTPIN: /* altpin setting */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(ANODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.altpin)) { + dgap_err("bad number for altpin"); + return -1; + } + break; + + case USEINTR: /* enable interrupt setting */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(INTRNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.useintr)) { + dgap_err("bad number for useintr"); + return -1; + } + break; + + case TTSIZ: /* size of tty structure */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(TSNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.ttysize)) { + dgap_err("bad number for ttysize"); + return -1; + } + break; + + case CHSIZ: /* channel structure size */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(CSNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.chsize)) { + dgap_err("bad number for chsize"); + return -1; + } + break; + + case BSSIZ: /* board structure size */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(BSNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.bssize)) { + dgap_err("bad number for bssize"); + return -1; + } + break; + + case UNTSIZ: /* sched structure size */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(USNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.unsize)) { + dgap_err("bad number for schedsize"); + return -1; + } + break; + + case F2SIZ: /* f2200 structure size */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(FSNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.f2size)) { + dgap_err("bad number for f2200size"); + return -1; + } + break; + + case VPSIZ: /* vpix structure size */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(VSNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + if (kstrtol(s, 0, &p->u.vpixsize)) { + dgap_err("bad number for vpixsize"); + return -1; + } + break; + } + } +} + +/* + * dgap_sindex: much like index(), but it looks for a match of any character in + * the group, and returns that position. If the first character is a ^, then + * this will match the first occurrence not in that group. + */ +static char *dgap_sindex(char *string, char *group) +{ + char *ptr; + + if (!string || !group) + return (char *) NULL; + + if (*group == '^') { + group++; + for (; *string; string++) { + for (ptr = group; *ptr; ptr++) { + if (*ptr == *string) + break; + } + if (*ptr == '\0') + return string; + } + } else { + for (; *string; string++) { + for (ptr = group; *ptr; ptr++) { + if (*ptr == *string) + return string; + } + } + } + + return (char *) NULL; +} + +/* + * Get a token from the input file; return 0 if end of file is reached + */ +static int dgap_gettok(char **in, struct cnode *p) +{ + char *w; + struct toklist *t; + + if (strstr(dgap_cword, "boar")) { + w = dgap_getword(in); + snprintf(dgap_cword, MAXCWORD, "%s", w); + for (t = dgap_tlist; t->token != 0; t++) { + if (!strcmp(w, t->string)) + return t->token; + } + dgap_err("board !!type not specified"); + return 1; + } else { + while ((w = dgap_getword(in))) { + snprintf(dgap_cword, MAXCWORD, "%s", w); + for (t = dgap_tlist; t->token != 0; t++) { + if (!strcmp(w, t->string)) + return t->token; + } + } + return 0; + } +} + +/* + * get a word from the input stream, also keep track of current line number. + * words are separated by whitespace. + */ +static char *dgap_getword(char **in) +{ + char *ret_ptr = *in; + + char *ptr = dgap_sindex(*in, " \t\n"); + + /* If no word found, return null */ + if (!ptr) + return NULL; + + /* Mark new location for our buffer */ + *ptr = '\0'; + *in = ptr + 1; + + /* Eat any extra spaces/tabs/newlines that might be present */ + while (*in && **in && ((**in == ' ') || + (**in == '\t') || + (**in == '\n'))) { + **in = '\0'; + *in = *in + 1; + } + + return ret_ptr; +} + +/* + * print an error message, giving the line number in the file where + * the error occurred. + */ +static void dgap_err(char *s) +{ + pr_err("dgap: parse: %s\n", s); +} + +/* + * allocate a new configuration node of type t + */ +static struct cnode *dgap_newnode(int t) +{ + struct cnode *n; + + n = kmalloc(sizeof(struct cnode), GFP_ATOMIC); + if (n != NULL) { + memset((char *)n, 0, sizeof(struct cnode)); + n->type = t; + } + return n; +} + +/* + * dgap_checknode: see if all the necessary info has been supplied for a node + * before creating the next node. + */ +static int dgap_checknode(struct cnode *p) +{ + switch (p->type) { + case BNODE: + if (p->u.board.v_type == 0) { + dgap_err("board type !not specified"); + return 1; + } + + return 0; + + case LNODE: + if (p->u.line.v_speed == 0) { + dgap_err("line speed not specified"); + return 1; + } + return 0; + + case CNODE: + if (p->u.conc.v_type == 0) { + dgap_err("concentrator type not specified"); + return 1; + } + if (p->u.conc.v_speed == 0) { + dgap_err("concentrator line speed not specified"); + return 1; + } + if (p->u.conc.v_nport == 0) { + dgap_err("number of ports on concentrator not specified"); + return 1; + } + if (p->u.conc.v_id == 0) { + dgap_err("concentrator id letter not specified"); + return 1; + } + return 0; + + case MNODE: + if (p->u.module.v_type == 0) { + dgap_err("EBI module type not specified"); + return 1; + } + if (p->u.module.v_nport == 0) { + dgap_err("number of ports on EBI module not specified"); + return 1; + } + if (p->u.module.v_id == 0) { + dgap_err("EBI module id letter not specified"); + return 1; + } + return 0; + } + return 0; +} + +/* + * save a string somewhere + */ +static char *dgap_savestring(char *s) +{ + char *p; + + p = kmalloc(strlen(s) + 1, GFP_ATOMIC); + if (p) + strcpy(p, s); + return p; +} + +/* + * Given a board pointer, returns whether we should use interrupts or not. + */ +static uint dgap_config_get_useintr(struct board_t *bd) +{ + struct cnode *p = NULL; + + if (!bd) + return 0; + + for (p = bd->bd_config; p; p = p->next) { + switch (p->type) { + case INTRNODE: + /* + * check for pcxr types. + */ + return p->u.useintr; + default: + break; + } + } + + /* If not found, then don't turn on interrupts. */ + return 0; +} + +/* + * Given a board pointer, returns whether we turn on altpin or not. + */ +static uint dgap_config_get_altpin(struct board_t *bd) +{ + struct cnode *p = NULL; + + if (!bd) + return 0; + + for (p = bd->bd_config; p; p = p->next) { + switch (p->type) { + case ANODE: + /* + * check for pcxr types. + */ + return p->u.altpin; + default: + break; + } + } + + /* If not found, then don't turn on interrupts. */ + return 0; +} + +/* + * Given a specific type of board, if found, detached link and + * returns the first occurrence in the list. + */ +static struct cnode *dgap_find_config(int type, int bus, int slot) +{ + struct cnode *p, *prev = NULL, *prev2 = NULL, *found = NULL; + + p = &dgap_head; + + while (p->next != NULL) { + prev = p; + p = p->next; + + if (p->type == BNODE) { + + if (p->u.board.type == type) { + + if (p->u.board.v_pcibus && + p->u.board.pcibus != bus) + continue; + if (p->u.board.v_pcislot && + p->u.board.pcislot != slot) + continue; + + found = p; + /* + * Keep walking thru the list till we + * find the next board. + */ + while (p->next != NULL) { + prev2 = p; + p = p->next; + if (p->type == BNODE) { + + /* + * Mark the end of our 1 board + * chain of configs. + */ + prev2->next = NULL; + + /* + * Link the "next" board to the + * previous board, effectively + * "unlinking" our board from + * the main config. + */ + prev->next = p; + + return found; + } + } + /* + * It must be the last board in the list. + */ + prev->next = NULL; + return found; + } + } + } + return NULL; +} + +/* + * Given a board pointer, walks the config link, counting up + * all ports user specified should be on the board. + * (This does NOT mean they are all actually present right now tho) + */ +static uint dgap_config_get_num_prts(struct board_t *bd) +{ + int count = 0; + struct cnode *p = NULL; + + if (!bd) + return 0; + + for (p = bd->bd_config; p; p = p->next) { + + switch (p->type) { + case BNODE: + /* + * check for pcxr types. + */ + if (p->u.board.type > EPCFE) + count += p->u.board.nport; + break; + case CNODE: + count += p->u.conc.nport; + break; + case MNODE: + count += p->u.module.nport; + break; + } + } + return count; +} + +static char *dgap_create_config_string(struct board_t *bd, char *string) +{ + char *ptr = string; + struct cnode *p = NULL; + struct cnode *q = NULL; + int speed; + + if (!bd) { + *ptr = 0xff; + return string; + } + + for (p = bd->bd_config; p; p = p->next) { + + switch (p->type) { + case LNODE: + *ptr = '\0'; + ptr++; + *ptr = p->u.line.speed; + ptr++; + break; + case CNODE: + /* + * Because the EPC/con concentrators can have EM modules + * hanging off of them, we have to walk ahead in the + * list and keep adding the number of ports on each EM + * to the config. UGH! + */ + speed = p->u.conc.speed; + q = p->next; + if ((q != NULL) && (q->type == MNODE)) { + *ptr = (p->u.conc.nport + 0x80); + ptr++; + p = q; + while ((q->next != NULL) && + (q->next->type) == MNODE) { + + *ptr = (q->u.module.nport + 0x80); + ptr++; + p = q; + q = q->next; + } + *ptr = q->u.module.nport; + ptr++; + } else { + *ptr = p->u.conc.nport; + ptr++; + } + + *ptr = speed; + ptr++; + break; + } + } + + *ptr = 0xff; + return string; +} diff --git a/drivers/staging/dgap/dgap.h b/drivers/staging/dgap/dgap.h new file mode 100644 index 000000000000..6b8f5f858327 --- /dev/null +++ b/drivers/staging/dgap/dgap.h @@ -0,0 +1,1322 @@ +/* + * Copyright 2003 Digi International (www.digi.com) + * Scott H Kilau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! + * + ************************************************************************* + * + * Driver includes + * + *************************************************************************/ + +#ifndef __DGAP_DRIVER_H +#define __DGAP_DRIVER_H + +#include /* To pick up the varions Linux types */ +#include /* To pick up the various tty structs/defines */ +#include /* For irqreturn_t type */ + +#ifndef TRUE +# define TRUE 1 +#endif + +#ifndef FALSE +# define FALSE 0 +#endif + +/* Required for our shared headers! */ +typedef unsigned char uchar; + +#if !defined(TTY_FLIPBUF_SIZE) +# define TTY_FLIPBUF_SIZE 512 +#endif + +/************************************************************************* + * + * Driver defines + * + *************************************************************************/ + +/* + * Driver identification + */ +#define DG_NAME "dgap-1.3-16" +#define DG_PART "40002347_C" +#define DRVSTR "dgap" + +/* + * defines from dgap_pci.h + */ +#define PCIMAX 32 /* maximum number of PCI boards */ + +#define DIGI_VID 0x114F + +#define PCI_DEV_EPC_DID 0x0002 +#define PCI_DEV_XEM_DID 0x0004 +#define PCI_DEV_XR_DID 0x0005 +#define PCI_DEV_CX_DID 0x0006 +#define PCI_DEV_XRJ_DID 0x0009 /* PLX-based Xr adapter */ +#define PCI_DEV_XR_IBM_DID 0x0011 /* IBM 8-port Async Adapter */ +#define PCI_DEV_XR_BULL_DID 0x0013 /* BULL 8-port Async Adapter */ +#define PCI_DEV_XR_SAIP_DID 0x001c /* SAIP card - Xr adapter */ +#define PCI_DEV_XR_422_DID 0x0012 /* Xr-422 */ +#define PCI_DEV_920_2_DID 0x0034 /* XR-Plus 920 K, 2 port */ +#define PCI_DEV_920_4_DID 0x0026 /* XR-Plus 920 K, 4 port */ +#define PCI_DEV_920_8_DID 0x0027 /* XR-Plus 920 K, 8 port */ +#define PCI_DEV_EPCJ_DID 0x000a /* PLX 9060 chip for PCI */ +#define PCI_DEV_CX_IBM_DID 0x001b /* IBM 128-port Async Adapter */ +#define PCI_DEV_920_8_HP_DID 0x0058 /* HP XR-Plus 920 K, 8 port */ +#define PCI_DEV_XEM_HP_DID 0x0059 /* HP Xem PCI */ + +#define PCI_DEV_XEM_NAME "AccelePort XEM" +#define PCI_DEV_CX_NAME "AccelePort CX" +#define PCI_DEV_XR_NAME "AccelePort Xr" +#define PCI_DEV_XRJ_NAME "AccelePort Xr (PLX)" +#define PCI_DEV_XR_SAIP_NAME "AccelePort Xr (SAIP)" +#define PCI_DEV_920_2_NAME "AccelePort Xr920 2 port" +#define PCI_DEV_920_4_NAME "AccelePort Xr920 4 port" +#define PCI_DEV_920_8_NAME "AccelePort Xr920 8 port" +#define PCI_DEV_XR_422_NAME "AccelePort Xr 422" +#define PCI_DEV_EPCJ_NAME "AccelePort EPC (PLX)" +#define PCI_DEV_XR_BULL_NAME "AccelePort Xr (BULL)" +#define PCI_DEV_XR_IBM_NAME "AccelePort Xr (IBM)" +#define PCI_DEV_CX_IBM_NAME "AccelePort CX (IBM)" +#define PCI_DEV_920_8_HP_NAME "AccelePort Xr920 8 port (HP)" +#define PCI_DEV_XEM_HP_NAME "AccelePort XEM (HP)" + +/* + * On the PCI boards, there is no IO space allocated + * The I/O registers will be in the first 3 bytes of the + * upper 2MB of the 4MB memory space. The board memory + * will be mapped into the low 2MB of the 4MB memory space + */ + +/* Potential location of PCI Bios from E0000 to FFFFF*/ +#define PCI_BIOS_SIZE 0x00020000 + +/* Size of Memory and I/O for PCI (4MB) */ +#define PCI_RAM_SIZE 0x00400000 + +/* Size of Memory (2MB) */ +#define PCI_MEM_SIZE 0x00200000 + +/* Max PCI Window Size (2MB) */ +#define PCI_WIN_SIZE 0x00200000 + +#define PCI_WIN_SHIFT 21 /* 21 bits max */ + +/* Offset of I/0 in Memory (2MB) */ +#define PCI_IO_OFFSET 0x00200000 + +/* Size of IO (2MB) */ +#define PCI_IO_SIZE 0x00200000 + +/* Number of boards we support at once. */ +#define MAXBOARDS 32 +#define MAXPORTS 224 +#define MAXTTYNAMELEN 200 + +/* Our 3 magic numbers for our board, channel and unit structs */ +#define DGAP_BOARD_MAGIC 0x5c6df104 +#define DGAP_CHANNEL_MAGIC 0x6c6df104 +#define DGAP_UNIT_MAGIC 0x7c6df104 + +/* Serial port types */ +#define DGAP_SERIAL 0 +#define DGAP_PRINT 1 + +#define SERIAL_TYPE_NORMAL 1 + +/* 4 extra for alignment play space */ +#define WRITEBUFLEN ((4096) + 4) +#define MYFLIPLEN N_TTY_BUF_SIZE + +#define SBREAK_TIME 0x25 +#define U2BSIZE 0x400 + +#define dgap_jiffies_from_ms(a) (((a) * HZ) / 1000) + +/* + * Our major for the mgmt devices. + * + * We can use 22, because Digi was allocated 22 and 23 for the epca driver. + * 22 has now become obsolete now that the "cu" devices have + * been removed from 2.6. + * Also, this *IS* the epca driver, just PCI only now. + */ +#ifndef DIGI_DGAP_MAJOR +# define DIGI_DGAP_MAJOR 22 +#endif + +/* + * The parameters we use to define the periods of the moving averages. + */ +#define MA_PERIOD (HZ / 10) +#define SMA_DUR (1 * HZ) +#define EMA_DUR (1 * HZ) +#define SMA_NPERIODS (SMA_DUR / MA_PERIOD) +#define EMA_NPERIODS (EMA_DUR / MA_PERIOD) + +/* + * Define a local default termios struct. All ports will be created + * with this termios initially. This is the same structure that is defined + * as the default in tty_io.c with the same settings overriden as in serial.c + * + * In short, this should match the internal serial ports' defaults. + */ +#define DEFAULT_IFLAGS (ICRNL | IXON) +#define DEFAULT_OFLAGS (OPOST | ONLCR) +#define DEFAULT_CFLAGS (B9600 | CS8 | CREAD | HUPCL | CLOCAL) +#define DEFAULT_LFLAGS (ISIG | ICANON | ECHO | ECHOE | ECHOK | \ + ECHOCTL | ECHOKE | IEXTEN) + +#ifndef _POSIX_VDISABLE +#define _POSIX_VDISABLE '\0' +#endif + +#define SNIFF_MAX 65536 /* Sniff buffer size (2^n) */ +#define SNIFF_MASK (SNIFF_MAX - 1) /* Sniff wrap mask */ + +#define VPDSIZE (512) + +/************************************************************************ + * FEP memory offsets + ************************************************************************/ +#define START 0x0004L /* Execution start address */ + +#define CMDBUF 0x0d10L /* Command (cm_t) structure offset */ +#define CMDSTART 0x0400L /* Start of command buffer */ +#define CMDMAX 0x0800L /* End of command buffer */ + +#define EVBUF 0x0d18L /* Event (ev_t) structure */ +#define EVSTART 0x0800L /* Start of event buffer */ +#define EVMAX 0x0c00L /* End of event buffer */ +#define FEP5_PLUS 0x0E40 /* ASCII '5' and ASCII 'A' is here */ +#define ECS_SEG 0x0E44 /* Segment of the extended channel structure */ +#define LINE_SPEED 0x10 /* Offset into ECS_SEG for line speed */ + /* if the fep has extended capabilities */ + +/* BIOS MAGIC SPOTS */ +#define ERROR 0x0C14L /* BIOS error code */ +#define SEQUENCE 0x0C12L /* BIOS sequence indicator */ +#define POSTAREA 0x0C00L /* POST complete message area */ + +/* FEP MAGIC SPOTS */ +#define FEPSTAT POSTAREA /* OS here when FEP comes up */ +#define NCHAN 0x0C02L /* number of ports FEP sees */ +#define PANIC 0x0C10L /* PANIC area for FEP */ +#define KMEMEM 0x0C30L /* Memory for KME use */ +#define CONFIG 0x0CD0L /* Concentrator configuration info */ +#define CONFIGSIZE 0x0030 /* configuration info size */ +#define DOWNREQ 0x0D00 /* Download request buffer pointer */ + +#define CHANBUF 0x1000L /* Async channel (bs_t) structs */ +#define FEPOSSIZE 0x1FFF /* 8K FEPOS */ + +#define XEMPORTS 0xC02 /* + * Offset in board memory where FEP5 stores + * how many ports it has detected. + * NOTE: FEP5 reports 64 ports when the user + * has the cable in EBI OUT instead of EBI IN. + */ + +#define FEPCLR 0x00 +#define FEPMEM 0x02 +#define FEPRST 0x04 +#define FEPINT 0x08 +#define FEPMASK 0x0e +#define FEPWIN 0x80 + +#define LOWMEM 0x0100 +#define HIGHMEM 0x7f00 + +#define FEPTIMEOUT 200000 + +#define ENABLE_INTR 0x0e04 /* Enable interrupts flag */ +#define FEPPOLL_MIN 1 /* minimum of 1 millisecond */ +#define FEPPOLL_MAX 20 /* maximum of 20 milliseconds */ +#define FEPPOLL 0x0c26 /* Fep event poll interval */ + +#define IALTPIN 0x0080 /* Input flag to swap DSR <-> DCD */ + +/************************************************************************ + * FEP supported functions + ************************************************************************/ +#define SRLOW 0xe0 /* Set receive low water */ +#define SRHIGH 0xe1 /* Set receive high water */ +#define FLUSHTX 0xe2 /* Flush transmit buffer */ +#define PAUSETX 0xe3 /* Pause data transmission */ +#define RESUMETX 0xe4 /* Resume data transmission */ +#define SMINT 0xe5 /* Set Modem Interrupt */ +#define SAFLOWC 0xe6 /* Set Aux. flow control chars */ +#define SBREAK 0xe8 /* Send break */ +#define SMODEM 0xe9 /* Set 8530 modem control lines */ +#define SIFLAG 0xea /* Set UNIX iflags */ +#define SFLOWC 0xeb /* Set flow control characters */ +#define STLOW 0xec /* Set transmit low water mark */ +#define RPAUSE 0xee /* Pause receive */ +#define RRESUME 0xef /* Resume receive */ +#define CHRESET 0xf0 /* Reset Channel */ +#define BUFSETALL 0xf2 /* Set Tx & Rx buffer size avail*/ +#define SOFLAG 0xf3 /* Set UNIX oflags */ +#define SHFLOW 0xf4 /* Set hardware handshake */ +#define SCFLAG 0xf5 /* Set UNIX cflags */ +#define SVNEXT 0xf6 /* Set VNEXT character */ +#define SPINTFC 0xfc /* Reserved */ +#define SCOMMODE 0xfd /* Set RS232/422 mode */ + + +/************************************************************************ + * Modes for SCOMMODE + ************************************************************************/ +#define MODE_232 0x00 +#define MODE_422 0x01 + + +/************************************************************************ + * Event flags. + ************************************************************************/ +#define IFBREAK 0x01 /* Break received */ +#define IFTLW 0x02 /* Transmit low water */ +#define IFTEM 0x04 /* Transmitter empty */ +#define IFDATA 0x08 /* Receive data present */ +#define IFMODEM 0x20 /* Modem status change */ + +/************************************************************************ + * Modem flags + ************************************************************************/ +# define DM_RTS 0x02 /* Request to send */ +# define DM_CD 0x80 /* Carrier detect */ +# define DM_DSR 0x20 /* Data set ready */ +# define DM_CTS 0x10 /* Clear to send */ +# define DM_RI 0x40 /* Ring indicator */ +# define DM_DTR 0x01 /* Data terminal ready */ + +/* + * defines from dgap_conf.h + */ +#define NULLNODE 0 /* header node, not used */ +#define BNODE 1 /* Board node */ +#define LNODE 2 /* Line node */ +#define CNODE 3 /* Concentrator node */ +#define MNODE 4 /* EBI Module node */ +#define TNODE 5 /* tty name prefix node */ +#define CUNODE 6 /* cu name prefix (non-SCO) */ +#define PNODE 7 /* trans. print prefix node */ +#define JNODE 8 /* maJor number node */ +#define ANODE 9 /* altpin */ +#define TSNODE 10 /* tty structure size */ +#define CSNODE 11 /* channel structure size */ +#define BSNODE 12 /* board structure size */ +#define USNODE 13 /* unit schedule structure size */ +#define FSNODE 14 /* f2200 structure size */ +#define VSNODE 15 /* size of VPIX structures */ +#define INTRNODE 16 /* enable interrupt */ + +/* Enumeration of tokens */ +#define BEGIN 1 +#define END 2 +#define BOARD 10 + +#define EPCFS 11 /* start of EPC family definitions */ +#define ICX 11 +#define MCX 13 +#define PCX 14 +#define IEPC 15 +#define EEPC 16 +#define MEPC 17 +#define IPCM 18 +#define EPCM 19 +#define MPCM 20 +#define PEPC 21 +#define PPCM 22 +#ifdef CP +#define ICP 23 +#define ECP 24 +#define MCP 25 +#endif +#define EPCFE 25 /* end of EPC family definitions */ +#define PC2E 26 +#define PC4E 27 +#define PC4E8K 28 +#define PC8E 29 +#define PC8E8K 30 +#define PC16E 31 +#define MC2E8K 34 +#define MC4E8K 35 +#define MC8E8K 36 + +#define AVANFS 42 /* start of Avanstar family definitions */ +#define A8P 42 +#define A16P 43 +#define AVANFE 43 /* end of Avanstar family definitions */ + +#define DA2000FS 44 /* start of AccelePort 2000 family definitions */ +#define DA22 44 /* AccelePort 2002 */ +#define DA24 45 /* AccelePort 2004 */ +#define DA28 46 /* AccelePort 2008 */ +#define DA216 47 /* AccelePort 2016 */ +#define DAR4 48 /* AccelePort RAS 4 port */ +#define DAR8 49 /* AccelePort RAS 8 port */ +#define DDR24 50 /* DataFire RAS 24 port */ +#define DDR30 51 /* DataFire RAS 30 port */ +#define DDR48 52 /* DataFire RAS 48 port */ +#define DDR60 53 /* DataFire RAS 60 port */ +#define DA2000FE 53 /* end of AccelePort 2000/RAS family definitions */ + +#define PCXRFS 106 /* start of PCXR family definitions */ +#define APORT4 106 +#define APORT8 107 +#define PAPORT4 108 +#define PAPORT8 109 +#define APORT4_920I 110 +#define APORT8_920I 111 +#define APORT4_920P 112 +#define APORT8_920P 113 +#define APORT2_920P 114 +#define PCXRFE 117 /* end of PCXR family definitions */ + +#define LINE 82 +#ifdef T1 +#define T1M 83 +#define E1M 84 +#endif +#define CONC 64 +#define CX 65 +#define EPC 66 +#define MOD 67 +#define PORTS 68 +#define METHOD 69 +#define CUSTOM 70 +#define BASIC 71 +#define STATUS 72 +#define MODEM 73 +/* The following tokens can appear in multiple places */ +#define SPEED 74 +#define NPORTS 75 +#define ID 76 +#define CABLE 77 +#define CONNECT 78 +#define IO 79 +#define MEM 80 +#define DPSZ 81 + +#define TTYN 90 +#define CU 91 +#define PRINT 92 +#define XPRINT 93 +#define CMAJOR 94 +#define ALTPIN 95 +#define STARTO 96 +#define USEINTR 97 +#define PCIINFO 98 + +#define TTSIZ 100 +#define CHSIZ 101 +#define BSSIZ 102 +#define UNTSIZ 103 +#define F2SIZ 104 +#define VPSIZ 105 + +#define TOTAL_BOARD 2 +#define CURRENT_BRD 4 +#define BOARD_TYPE 6 +#define IO_ADDRESS 8 +#define MEM_ADDRESS 10 + +#define FIELDS_PER_PAGE 18 + +#define TB_FIELD 1 +#define CB_FIELD 3 +#define BT_FIELD 5 +#define IO_FIELD 7 +#define ID_FIELD 8 +#define ME_FIELD 9 +#define TTY_FIELD 11 +#define CU_FIELD 13 +#define PR_FIELD 15 +#define MPR_FIELD 17 + +#define MAX_FIELD 512 + +#define INIT 0 +#define NITEMS 128 +#define MAX_ITEM 512 + +#define DSCRINST 1 +#define DSCRNUM 3 +#define ALTPINQ 5 +#define SSAVE 7 + +#define DSCR "32" +#define ONETONINE "123456789" +#define ALL "1234567890" + +/* + * All the possible states the driver can be while being loaded. + */ +enum { + DRIVER_INITIALIZED = 0, + DRIVER_READY +}; + +/* + * All the possible states the board can be while booting up. + */ +enum { + BOARD_FAILED = 0, + BOARD_READY +}; + +/* + * All the possible states that a requested concentrator image can be in. + */ +enum { + NO_PENDING_CONCENTRATOR_REQUESTS = 0, + NEED_CONCENTRATOR, + REQUESTED_CONCENTRATOR +}; + + + +/* + * Modem line constants are defined as macros because DSR and + * DCD are swapable using the ditty altpin option. + */ +#define D_CD(ch) ch->ch_cd /* Carrier detect */ +#define D_DSR(ch) ch->ch_dsr /* Data set ready */ +#define D_RTS(ch) DM_RTS /* Request to send */ +#define D_CTS(ch) DM_CTS /* Clear to send */ +#define D_RI(ch) DM_RI /* Ring indicator */ +#define D_DTR(ch) DM_DTR /* Data terminal ready */ + + +/************************************************************************* + * + * Structures and closely related defines. + * + *************************************************************************/ + + +/* + * A structure to hold a statistics counter. We also + * compute moving averages for this counter. + */ +struct macounter { + u32 cnt; /* Total count */ + ulong accum; /* Acuumulator per period */ + ulong sma; /* Simple moving average */ + ulong ema; /* Exponential moving average */ +}; + + +/************************************************************************ + * Device flag definitions for bd_flags. + ************************************************************************/ +#define BD_FEP5PLUS 0x0001 /* Supports FEP5 Plus commands */ +#define BD_HAS_VPD 0x0002 /* Board has VPD info available */ + +/* + * Per-board information + */ +struct board_t { + int magic; /* Board Magic number. */ + int boardnum; /* Board number: 0-3 */ + int firstminor; /* First minor, e.g. 0, 30, 60 */ + + int type; /* Type of board */ + char *name; /* Product Name */ + struct pci_dev *pdev; /* Pointer to the pci_dev struct */ + u16 vendor; /* PCI vendor ID */ + u16 device; /* PCI device ID */ + u16 subvendor; /* PCI subsystem vendor ID */ + u16 subdevice; /* PCI subsystem device ID */ + uchar rev; /* PCI revision ID */ + uint pci_bus; /* PCI bus value */ + uint pci_slot; /* PCI slot value */ + u16 maxports; /* MAX ports this board can handle */ + uchar vpd[VPDSIZE]; /* VPD of board, if found */ + u32 bd_flags; /* Board flags */ + + spinlock_t bd_lock; /* Used to protect board */ + + u32 state; /* State of card. */ + wait_queue_head_t state_wait; /* Place to sleep on for state change */ + + struct tasklet_struct helper_tasklet; /* Poll helper tasklet */ + + u32 wait_for_bios; + u32 wait_for_fep; + + struct cnode *bd_config; /* Config of board */ + + u16 nasync; /* Number of ports on card */ + + u32 use_interrupts; /* Should we be interrupt driven? */ + ulong irq; /* Interrupt request number */ + ulong intr_count; /* Count of interrupts */ + u32 intr_used; /* Non-zero if using interrupts */ + u32 intr_running; /* Non-zero if FEP knows its doing interrupts */ + + ulong port; /* Start of base io port of the card */ + ulong port_end; /* End of base io port of the card */ + ulong membase; /* Start of base memory of the card */ + ulong membase_end; /* End of base memory of the card */ + + uchar *re_map_port; /* Remapped io port of the card */ + uchar *re_map_membase;/* Remapped memory of the card */ + + uchar runwait; /* # Processes waiting for FEP */ + uchar inhibit_poller; /* Tells the poller to leave us alone */ + + struct channel_t *channels[MAXPORTS]; /* array of pointers to our channels. */ + + struct tty_driver *SerialDriver; + struct tty_port *SerialPorts; + char SerialName[200]; + struct tty_driver *PrintDriver; + struct tty_port *PrinterPorts; + char PrintName[200]; + + u32 dgap_Major_Serial_Registered; + u32 dgap_Major_TransparentPrint_Registered; + + u32 dgap_Serial_Major; + u32 dgap_TransparentPrint_Major; + + struct bs_t *bd_bs; /* Base structure pointer */ + + char *flipbuf; /* Our flip buffer, alloced if board is found */ + char *flipflagbuf; /* Our flip flag buffer, alloced if board is found */ + + u16 dpatype; /* The board "type", as defined by DPA */ + u16 dpastatus; /* The board "status", as defined by DPA */ + wait_queue_head_t kme_wait; /* Needed for DPA support */ + + u32 conc_dl_status; /* Status of any pending conc download */ +}; + + + +/************************************************************************ + * Unit flag definitions for un_flags. + ************************************************************************/ +#define UN_ISOPEN 0x0001 /* Device is open */ +#define UN_CLOSING 0x0002 /* Line is being closed */ +#define UN_IMM 0x0004 /* Service immediately */ +#define UN_BUSY 0x0008 /* Some work this channel */ +#define UN_BREAKI 0x0010 /* Input break received */ +#define UN_PWAIT 0x0020 /* Printer waiting for terminal */ +#define UN_TIME 0x0040 /* Waiting on time */ +#define UN_EMPTY 0x0080 /* Waiting output queue empty */ +#define UN_LOW 0x0100 /* Waiting output low water mark*/ +#define UN_EXCL_OPEN 0x0200 /* Open for exclusive use */ +#define UN_WOPEN 0x0400 /* Device waiting for open */ +#define UN_WIOCTL 0x0800 /* Device waiting for open */ +#define UN_HANGUP 0x8000 /* Carrier lost */ + +struct device; + +/************************************************************************ + * Structure for terminal or printer unit. + ************************************************************************/ +struct un_t { + int magic; /* Unit Magic Number. */ + struct channel_t *un_ch; + u32 un_time; + u32 un_type; + u32 un_open_count; /* Counter of opens to port */ + struct tty_struct *un_tty;/* Pointer to unit tty structure */ + u32 un_flags; /* Unit flags */ + wait_queue_head_t un_flags_wait; /* Place to sleep to wait on unit */ + u32 un_dev; /* Minor device number */ + tcflag_t un_oflag; /* oflags being done on board */ + tcflag_t un_lflag; /* lflags being done on board */ + struct device *un_sysfs; +}; + + +/************************************************************************ + * Device flag definitions for ch_flags. + ************************************************************************/ +#define CH_PRON 0x0001 /* Printer on string */ +#define CH_OUT 0x0002 /* Dial-out device open */ +#define CH_STOP 0x0004 /* Output is stopped */ +#define CH_STOPI 0x0008 /* Input is stopped */ +#define CH_CD 0x0010 /* Carrier is present */ +#define CH_FCAR 0x0020 /* Carrier forced on */ + +#define CH_RXBLOCK 0x0080 /* Enable rx blocked flag */ +#define CH_WLOW 0x0100 /* Term waiting low event */ +#define CH_WEMPTY 0x0200 /* Term waiting empty event */ +#define CH_RENABLE 0x0400 /* Buffer just emptied */ +#define CH_RACTIVE 0x0800 /* Process active in xxread() */ +#define CH_RWAIT 0x1000 /* Process waiting in xxread() */ +#define CH_BAUD0 0x2000 /* Used for checking B0 transitions */ +#define CH_HANGUP 0x8000 /* Hangup received */ + +/* + * Definitions for ch_sniff_flags + */ +#define SNIFF_OPEN 0x1 +#define SNIFF_WAIT_DATA 0x2 +#define SNIFF_WAIT_SPACE 0x4 + + +/************************************************************************ + *** Definitions for Digi ditty(1) command. + ************************************************************************/ + +/************************************************************************ + * This module provides application access to special Digi + * serial line enhancements which are not standard UNIX(tm) features. + ************************************************************************/ + +#if !defined(TIOCMODG) + +#define TIOCMODG (('d'<<8) | 250) /* get modem ctrl state */ +#define TIOCMODS (('d'<<8) | 251) /* set modem ctrl state */ + +#ifndef TIOCM_LE +#define TIOCM_LE 0x01 /* line enable */ +#define TIOCM_DTR 0x02 /* data terminal ready */ +#define TIOCM_RTS 0x04 /* request to send */ +#define TIOCM_ST 0x08 /* secondary transmit */ +#define TIOCM_SR 0x10 /* secondary receive */ +#define TIOCM_CTS 0x20 /* clear to send */ +#define TIOCM_CAR 0x40 /* carrier detect */ +#define TIOCM_RNG 0x80 /* ring indicator */ +#define TIOCM_DSR 0x100 /* data set ready */ +#define TIOCM_RI TIOCM_RNG /* ring (alternate) */ +#define TIOCM_CD TIOCM_CAR /* carrier detect (alt) */ +#endif + +#endif + +#if !defined(TIOCMSET) +#define TIOCMSET (('d'<<8) | 252) /* set modem ctrl state */ +#define TIOCMGET (('d'<<8) | 253) /* set modem ctrl state */ +#endif + +#if !defined(TIOCMBIC) +#define TIOCMBIC (('d'<<8) | 254) /* set modem ctrl state */ +#define TIOCMBIS (('d'<<8) | 255) /* set modem ctrl state */ +#endif + + +#if !defined(TIOCSDTR) +#define TIOCSDTR (('e'<<8) | 0) /* set DTR */ +#define TIOCCDTR (('e'<<8) | 1) /* clear DTR */ +#endif + +/************************************************************************ + * Ioctl command arguments for DIGI parameters. + ************************************************************************/ +#define DIGI_GETA (('e'<<8) | 94) /* Read params */ + +#define DIGI_SETA (('e'<<8) | 95) /* Set params */ +#define DIGI_SETAW (('e'<<8) | 96) /* Drain & set params */ +#define DIGI_SETAF (('e'<<8) | 97) /* Drain, flush & set params */ + +#define DIGI_KME (('e'<<8) | 98) /* Read/Write Host */ + /* Adapter Memory */ + +#define DIGI_GETFLOW (('e'<<8) | 99) /* Get startc/stopc flow */ + /* control characters */ +#define DIGI_SETFLOW (('e'<<8) | 100) /* Set startc/stopc flow */ + /* control characters */ +#define DIGI_GETAFLOW (('e'<<8) | 101) /* Get Aux. startc/stopc */ + /* flow control chars */ +#define DIGI_SETAFLOW (('e'<<8) | 102) /* Set Aux. startc/stopc */ + /* flow control chars */ + +#define DIGI_GEDELAY (('d'<<8) | 246) /* Get edelay */ +#define DIGI_SEDELAY (('d'<<8) | 247) /* Set edelay */ + +struct digiflow_t { + unsigned char startc; /* flow cntl start char */ + unsigned char stopc; /* flow cntl stop char */ +}; + + +#ifdef FLOW_2200 +#define F2200_GETA (('e'<<8) | 104) /* Get 2x36 flow cntl flags */ +#define F2200_SETAW (('e'<<8) | 105) /* Set 2x36 flow cntl flags */ +#define F2200_MASK 0x03 /* 2200 flow cntl bit mask */ +#define FCNTL_2200 0x01 /* 2x36 terminal flow cntl */ +#define PCNTL_2200 0x02 /* 2x36 printer flow cntl */ +#define F2200_XON 0xf8 +#define P2200_XON 0xf9 +#define F2200_XOFF 0xfa +#define P2200_XOFF 0xfb + +#define FXOFF_MASK 0x03 /* 2200 flow status mask */ +#define RCVD_FXOFF 0x01 /* 2x36 Terminal XOFF rcvd */ +#define RCVD_PXOFF 0x02 /* 2x36 Printer XOFF rcvd */ +#endif + +/************************************************************************ + * Values for digi_flags + ************************************************************************/ +#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */ +#define DIGI_FAST 0x0002 /* Fast baud rates */ +#define RTSPACE 0x0004 /* RTS input flow control */ +#define CTSPACE 0x0008 /* CTS output flow control */ +#define DSRPACE 0x0010 /* DSR output flow control */ +#define DCDPACE 0x0020 /* DCD output flow control */ +#define DTRPACE 0x0040 /* DTR input flow control */ +#define DIGI_COOK 0x0080 /* Cooked processing done in FEP */ +#define DIGI_FORCEDCD 0x0100 /* Force carrier */ +#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */ +#define DIGI_AIXON 0x0400 /* Aux flow control in fep */ +#define DIGI_PRINTER 0x0800 /* Hold port open for flow cntrl*/ +#define DIGI_PP_INPUT 0x1000 /* Change parallel port to input*/ +#define DIGI_DTR_TOGGLE 0x2000 /* Support DTR Toggle */ +#define DIGI_422 0x4000 /* for 422/232 selectable panel */ +#define DIGI_RTS_TOGGLE 0x8000 /* Support RTS Toggle */ + +/************************************************************************ + * These options are not supported on the comxi. + ************************************************************************/ +#define DIGI_COMXI (DIGI_FAST|DIGI_COOK|DSRPACE|DCDPACE|DTRPACE) + +#define DIGI_PLEN 28 /* String length */ +#define DIGI_TSIZ 10 /* Terminal string len */ + +/************************************************************************ + * Structure used with ioctl commands for DIGI parameters. + ************************************************************************/ +struct digi_t { + unsigned short digi_flags; /* Flags (see above) */ + unsigned short digi_maxcps; /* Max printer CPS */ + unsigned short digi_maxchar; /* Max chars in print queue */ + unsigned short digi_bufsize; /* Buffer size */ + unsigned char digi_onlen; /* Length of ON string */ + unsigned char digi_offlen; /* Length of OFF string */ + char digi_onstr[DIGI_PLEN]; /* Printer on string */ + char digi_offstr[DIGI_PLEN]; /* Printer off string */ + char digi_term[DIGI_TSIZ]; /* terminal string */ +}; + +/************************************************************************ + * KME definitions and structures. + ************************************************************************/ +#define RW_IDLE 0 /* Operation complete */ +#define RW_READ 1 /* Read Concentrator Memory */ +#define RW_WRITE 2 /* Write Concentrator Memory */ + +struct rw_t { + unsigned char rw_req; /* Request type */ + unsigned char rw_board; /* Host Adapter board number */ + unsigned char rw_conc; /* Concentrator number */ + unsigned char rw_reserved; /* Reserved for expansion */ + unsigned long rw_addr; /* Address in concentrator */ + unsigned short rw_size; /* Read/write request length */ + unsigned char rw_data[128]; /* Data to read/write */ +}; + +/*********************************************************************** + * Shrink Buffer and Board Information definitions and structures. + + ************************************************************************/ + /* Board type return codes */ +#define PCXI_TYPE 1 /* Board type at the designated port is a PC/Xi */ +#define PCXM_TYPE 2 /* Board type at the designated port is a PC/Xm */ +#define PCXE_TYPE 3 /* Board type at the designated port is a PC/Xe */ +#define MCXI_TYPE 4 /* Board type at the designated port is a MC/Xi */ +#define COMXI_TYPE 5 /* Board type at the designated port is a COM/Xi */ + + /* Non-Zero Result codes. */ +#define RESULT_NOBDFND 1 /* A Digi product at that port is not config installed */ +#define RESULT_NODESCT 2 /* A memory descriptor was not obtainable */ +#define RESULT_NOOSSIG 3 /* FEP/OS signature was not detected on the board */ +#define RESULT_TOOSML 4 /* Too small an area to shrink. */ +#define RESULT_NOCHAN 5 /* Channel structure for the board was not found */ + +struct shrink_buf_struct { + unsigned long shrink_buf_vaddr; /* Virtual address of board */ + unsigned long shrink_buf_phys; /* Physical address of board */ + unsigned long shrink_buf_bseg; /* Amount of board memory */ + unsigned long shrink_buf_hseg; /* '186 Beginning of Dual-Port */ + + unsigned long shrink_buf_lseg; /* '186 Beginning of freed memory */ + unsigned long shrink_buf_mseg; /* Linear address from start of + dual-port were freed memory + begins, host viewpoint. */ + + unsigned long shrink_buf_bdparam; /* Parameter for xxmemon and + xxmemoff */ + + unsigned long shrink_buf_reserva; /* Reserved */ + unsigned long shrink_buf_reservb; /* Reserved */ + unsigned long shrink_buf_reservc; /* Reserved */ + unsigned long shrink_buf_reservd; /* Reserved */ + + unsigned char shrink_buf_result; /* Reason for call failing + Zero is Good return */ + unsigned char shrink_buf_init; /* Non-Zero if it caused an + xxinit call. */ + + unsigned char shrink_buf_anports; /* Number of async ports */ + unsigned char shrink_buf_snports; /* Number of sync ports */ + unsigned char shrink_buf_type; /* Board type 1 = PC/Xi, + 2 = PC/Xm, + 3 = PC/Xe + 4 = MC/Xi + 5 = COMX/i */ + unsigned char shrink_buf_card; /* Card number */ + +}; + +/************************************************************************ + * Structure to get driver status information + ************************************************************************/ +struct digi_dinfo { + unsigned long dinfo_nboards; /* # boards configured */ + char dinfo_reserved[12]; /* for future expansion */ + char dinfo_version[16]; /* driver version */ +}; + +#define DIGI_GETDD (('d'<<8) | 248) /* get driver info */ + +/************************************************************************ + * Structure used with ioctl commands for per-board information + * + * physsize and memsize differ when board has "windowed" memory + ************************************************************************/ +struct digi_info { + unsigned long info_bdnum; /* Board number (0 based) */ + unsigned long info_ioport; /* io port address */ + unsigned long info_physaddr; /* memory address */ + unsigned long info_physsize; /* Size of host mem window */ + unsigned long info_memsize; /* Amount of dual-port mem */ + /* on board */ + unsigned short info_bdtype; /* Board type */ + unsigned short info_nports; /* number of ports */ + char info_bdstate; /* board state */ + char info_reserved[7]; /* for future expansion */ +}; + +#define DIGI_GETBD (('d'<<8) | 249) /* get board info */ + +struct digi_stat { + unsigned int info_chan; /* Channel number (0 based) */ + unsigned int info_brd; /* Board number (0 based) */ + unsigned long info_cflag; /* cflag for channel */ + unsigned long info_iflag; /* iflag for channel */ + unsigned long info_oflag; /* oflag for channel */ + unsigned long info_mstat; /* mstat for channel */ + unsigned long info_tx_data; /* tx_data for channel */ + unsigned long info_rx_data; /* rx_data for channel */ + unsigned long info_hflow; /* hflow for channel */ + unsigned long info_reserved[8]; /* for future expansion */ +}; + +#define DIGI_GETSTAT (('d'<<8) | 244) /* get board info */ +/************************************************************************ + * + * Structure used with ioctl commands for per-channel information + * + ************************************************************************/ +struct digi_ch { + unsigned long info_bdnum; /* Board number (0 based) */ + unsigned long info_channel; /* Channel index number */ + unsigned long info_ch_cflag; /* Channel cflag */ + unsigned long info_ch_iflag; /* Channel iflag */ + unsigned long info_ch_oflag; /* Channel oflag */ + unsigned long info_chsize; /* Channel structure size */ + unsigned long info_sleep_stat; /* sleep status */ + dev_t info_dev; /* device number */ + unsigned char info_initstate; /* Channel init state */ + unsigned char info_running; /* Channel running state */ + long reserved[8]; /* reserved for future use */ +}; + +/* +* This structure is used with the DIGI_FEPCMD ioctl to +* tell the driver which port to send the command for. +*/ +struct digi_cmd { + int cmd; + int word; + int ncmds; + int chan; /* channel index (zero based) */ + int bdid; /* board index (zero based) */ +}; + +/* +* info_sleep_stat defines +*/ +#define INFO_RUNWAIT 0x0001 +#define INFO_WOPEN 0x0002 +#define INFO_TTIOW 0x0004 +#define INFO_CH_RWAIT 0x0008 +#define INFO_CH_WEMPTY 0x0010 +#define INFO_CH_WLOW 0x0020 +#define INFO_XXBUF_BUSY 0x0040 + +#define DIGI_GETCH (('d'<<8) | 245) /* get board info */ + +/* Board type definitions */ + +#define SUBTYPE 0007 +#define T_PCXI 0000 +#define T_PCXM 0001 +#define T_PCXE 0002 +#define T_PCXR 0003 +#define T_SP 0004 +#define T_SP_PLUS 0005 +# define T_HERC 0000 +# define T_HOU 0001 +# define T_LON 0002 +# define T_CHA 0003 +#define FAMILY 0070 +#define T_COMXI 0000 +#define T_PCXX 0010 +#define T_CX 0020 +#define T_EPC 0030 +#define T_PCLITE 0040 +#define T_SPXX 0050 +#define T_AVXX 0060 +#define T_DXB 0070 +#define T_A2K_4_8 0070 +#define BUSTYPE 0700 +#define T_ISABUS 0000 +#define T_MCBUS 0100 +#define T_EISABUS 0200 +#define T_PCIBUS 0400 + +/* Board State Definitions */ + +#define BD_RUNNING 0x0 +#define BD_REASON 0x7f +#define BD_NOTFOUND 0x1 +#define BD_NOIOPORT 0x2 +#define BD_NOMEM 0x3 +#define BD_NOBIOS 0x4 +#define BD_NOFEP 0x5 +#define BD_FAILED 0x6 +#define BD_ALLOCATED 0x7 +#define BD_TRIBOOT 0x8 +#define BD_BADKME 0x80 + +#define DIGI_LOOPBACK (('d'<<8) | 252) /* Enable/disable UART internal loopback */ +#define DIGI_SPOLL (('d'<<8) | 254) /* change poller rate */ + +#define DIGI_SETCUSTOMBAUD _IOW('e', 106, int) /* Set integer baud rate */ +#define DIGI_GETCUSTOMBAUD _IOR('e', 107, int) /* Get integer baud rate */ +#define DIGI_RESET_PORT (('e'<<8) | 93) /* Reset port */ + +/************************************************************************ + * Channel information structure. + ************************************************************************/ +struct channel_t { + int magic; /* Channel Magic Number */ + struct bs_t *ch_bs; /* Base structure pointer */ + struct cm_t *ch_cm; /* Command queue pointer */ + struct board_t *ch_bd; /* Board structure pointer */ + unsigned char *ch_vaddr; /* FEP memory origin */ + unsigned char *ch_taddr; /* Write buffer origin */ + unsigned char *ch_raddr; /* Read buffer origin */ + struct digi_t ch_digi; /* Transparent Print structure */ + struct un_t ch_tun; /* Terminal unit info */ + struct un_t ch_pun; /* Printer unit info */ + + spinlock_t ch_lock; /* provide for serialization */ + wait_queue_head_t ch_flags_wait; + + u32 pscan_state; + uchar pscan_savechar; + + u32 ch_portnum; /* Port number, 0 offset. */ + u32 ch_open_count; /* open count */ + u32 ch_flags; /* Channel flags */ + + + u32 ch_close_delay; /* How long we should drop RTS/DTR for */ + + u32 ch_cpstime; /* Time for CPS calculations */ + + tcflag_t ch_c_iflag; /* channel iflags */ + tcflag_t ch_c_cflag; /* channel cflags */ + tcflag_t ch_c_oflag; /* channel oflags */ + tcflag_t ch_c_lflag; /* channel lflags */ + + u16 ch_fepiflag; /* FEP tty iflags */ + u16 ch_fepcflag; /* FEP tty cflags */ + u16 ch_fepoflag; /* FEP tty oflags */ + u16 ch_wopen; /* Waiting for open process cnt */ + u16 ch_tstart; /* Transmit buffer start */ + u16 ch_tsize; /* Transmit buffer size */ + u16 ch_rstart; /* Receive buffer start */ + u16 ch_rsize; /* Receive buffer size */ + u16 ch_rdelay; /* Receive delay time */ + + u16 ch_tlw; /* Our currently set low water mark */ + + u16 ch_cook; /* Output character mask */ + + uchar ch_card; /* Card channel is on */ + uchar ch_stopc; /* Stop character */ + uchar ch_startc; /* Start character */ + + uchar ch_mostat; /* FEP output modem status */ + uchar ch_mistat; /* FEP input modem status */ + uchar ch_mforce; /* Modem values to be forced */ + uchar ch_mval; /* Force values */ + uchar ch_fepstopc; /* FEP stop character */ + uchar ch_fepstartc; /* FEP start character */ + + uchar ch_astopc; /* Auxiliary Stop character */ + uchar ch_astartc; /* Auxiliary Start character */ + uchar ch_fepastopc; /* Auxiliary FEP stop char */ + uchar ch_fepastartc; /* Auxiliary FEP start char */ + + uchar ch_hflow; /* FEP hardware handshake */ + uchar ch_dsr; /* stores real dsr value */ + uchar ch_cd; /* stores real cd value */ + uchar ch_tx_win; /* channel tx buffer window */ + uchar ch_rx_win; /* channel rx buffer window */ + uint ch_custom_speed; /* Custom baud, if set */ + uint ch_baud_info; /* Current baud info for /proc output */ + ulong ch_rxcount; /* total of data received so far */ + ulong ch_txcount; /* total of data transmitted so far */ + ulong ch_err_parity; /* Count of parity errors on channel */ + ulong ch_err_frame; /* Count of framing errors on channel */ + ulong ch_err_break; /* Count of breaks on channel */ + ulong ch_err_overrun; /* Count of overruns on channel */ + + uint ch_sniff_in; + uint ch_sniff_out; + char *ch_sniff_buf; /* Sniff buffer for proc */ + ulong ch_sniff_flags; /* Channel flags */ + wait_queue_head_t ch_sniff_wait; +}; + +/************************************************************************ + * Command structure definition. + ************************************************************************/ +struct cm_t { + volatile unsigned short cm_head; /* Command buffer head offset */ + volatile unsigned short cm_tail; /* Command buffer tail offset */ + volatile unsigned short cm_start; /* start offset of buffer */ + volatile unsigned short cm_max; /* last offset of buffer */ +}; + +/************************************************************************ + * Event structure definition. + ************************************************************************/ +struct ev_t { + volatile unsigned short ev_head; /* Command buffer head offset */ + volatile unsigned short ev_tail; /* Command buffer tail offset */ + volatile unsigned short ev_start; /* start offset of buffer */ + volatile unsigned short ev_max; /* last offset of buffer */ +}; + +/************************************************************************ + * Download buffer structure. + ************************************************************************/ +struct downld_t { + uchar dl_type; /* Header */ + uchar dl_seq; /* Download sequence */ + ushort dl_srev; /* Software revision number */ + ushort dl_lrev; /* Low revision number */ + ushort dl_hrev; /* High revision number */ + ushort dl_seg; /* Start segment address */ + ushort dl_size; /* Number of bytes to download */ + uchar dl_data[1024]; /* Download data */ +}; + +/************************************************************************ + * Per channel buffer structure + ************************************************************************ + * Base Structure Entries Usage Meanings to Host * + * * + * W = read write R = read only * + * C = changed by commands only * + * U = unknown (may be changed w/o notice) * + ************************************************************************/ +struct bs_t { + volatile unsigned short tp_jmp; /* Transmit poll jump */ + volatile unsigned short tc_jmp; /* Cooked procedure jump */ + volatile unsigned short ri_jmp; /* Not currently used */ + volatile unsigned short rp_jmp; /* Receive poll jump */ + + volatile unsigned short tx_seg; /* W Tx segment */ + volatile unsigned short tx_head; /* W Tx buffer head offset */ + volatile unsigned short tx_tail; /* R Tx buffer tail offset */ + volatile unsigned short tx_max; /* W Tx buffer size - 1 */ + + volatile unsigned short rx_seg; /* W Rx segment */ + volatile unsigned short rx_head; /* W Rx buffer head offset */ + volatile unsigned short rx_tail; /* R Rx buffer tail offset */ + volatile unsigned short rx_max; /* W Rx buffer size - 1 */ + + volatile unsigned short tx_lw; /* W Tx buffer low water mark */ + volatile unsigned short rx_lw; /* W Rx buffer low water mark */ + volatile unsigned short rx_hw; /* W Rx buffer high water mark */ + volatile unsigned short incr; /* W Increment to next channel */ + + volatile unsigned short fepdev; /* U SCC device base address */ + volatile unsigned short edelay; /* W Exception delay */ + volatile unsigned short blen; /* W Break length */ + volatile unsigned short btime; /* U Break complete time */ + + volatile unsigned short iflag; /* C UNIX input flags */ + volatile unsigned short oflag; /* C UNIX output flags */ + volatile unsigned short cflag; /* C UNIX control flags */ + volatile unsigned short wfill[13]; /* U Reserved for expansion */ + + volatile unsigned char num; /* U Channel number */ + volatile unsigned char ract; /* U Receiver active counter */ + volatile unsigned char bstat; /* U Break status bits */ + volatile unsigned char tbusy; /* W Transmit busy */ + volatile unsigned char iempty; /* W Transmit empty event enable */ + volatile unsigned char ilow; /* W Transmit low-water event enable */ + volatile unsigned char idata; /* W Receive data interrupt enable */ + volatile unsigned char eflag; /* U Host event flags */ + + volatile unsigned char tflag; /* U Transmit flags */ + volatile unsigned char rflag; /* U Receive flags */ + volatile unsigned char xmask; /* U Transmit ready flags */ + volatile unsigned char xval; /* U Transmit ready value */ + volatile unsigned char m_stat; /* RC Modem status bits */ + volatile unsigned char m_change; /* U Modem bits which changed */ + volatile unsigned char m_int; /* W Modem interrupt enable bits */ + volatile unsigned char m_last; /* U Last modem status */ + + volatile unsigned char mtran; /* C Unreported modem trans */ + volatile unsigned char orun; /* C Buffer overrun occurred */ + volatile unsigned char astartc; /* W Auxiliary Xon char */ + volatile unsigned char astopc; /* W Auxiliary Xoff char */ + volatile unsigned char startc; /* W Xon character */ + volatile unsigned char stopc; /* W Xoff character */ + volatile unsigned char vnextc; /* W Vnext character */ + volatile unsigned char hflow; /* C Software flow control */ + + volatile unsigned char fillc; /* U Delay Fill character */ + volatile unsigned char ochar; /* U Saved output character */ + volatile unsigned char omask; /* U Output character mask */ + + volatile unsigned char bfill[13]; /* U Reserved for expansion */ + + volatile unsigned char scc[16]; /* U SCC registers */ +}; + +struct cnode { + struct cnode *next; + int type; + int numbrd; + + union { + struct { + char type; /* Board Type */ + long port; /* I/O Address */ + char *portstr; /* I/O Address in string */ + long addr; /* Memory Address */ + char *addrstr; /* Memory Address in string */ + long pcibus; /* PCI BUS */ + char *pcibusstr; /* PCI BUS in string */ + long pcislot; /* PCI SLOT */ + char *pcislotstr; /* PCI SLOT in string */ + long nport; /* Number of Ports */ + char *id; /* tty id */ + long start; /* start of tty counting */ + char *method; /* Install method */ + char v_type; + char v_port; + char v_addr; + char v_pcibus; + char v_pcislot; + char v_nport; + char v_id; + char v_start; + char v_method; + char line1; + char line2; + char conc1; /* total concs in line1 */ + char conc2; /* total concs in line2 */ + char module1; /* total modules for line1 */ + char module2; /* total modules for line2 */ + char *status; /* config status */ + char *dimstatus; /* Y/N */ + int status_index; /* field pointer */ + } board; + + struct { + char *cable; + char v_cable; + long speed; + char v_speed; + } line; + + struct { + char type; + char *connect; + long speed; + long nport; + char *id; + char *idstr; + long start; + char v_type; + char v_connect; + char v_speed; + char v_nport; + char v_id; + char v_start; + } conc; + + struct { + char type; + long nport; + char *id; + char *idstr; + long start; + char v_type; + char v_nport; + char v_id; + char v_start; + } module; + + char *ttyname; + + char *cuname; + + char *printname; + + long majornumber; + + long altpin; + + long ttysize; + + long chsize; + + long bssize; + + long unsize; + + long f2size; + + long vpixsize; + + long useintr; + } u; +}; + +#endif diff --git a/drivers/staging/dgap/dgap_conf.h b/drivers/staging/dgap/dgap_conf.h deleted file mode 100644 index 484ed726a4d6..000000000000 --- a/drivers/staging/dgap/dgap_conf.h +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ***************************************************************************** - * - * dgap_conf.h - Header file for installations and parse files. - * - * $Id: dgap_conf.h,v 1.1 2009/10/23 14:01:57 markh Exp $ - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - */ - -#ifndef _DGAP_CONF_H -#define _DGAP_CONF_H - -#define NULLNODE 0 /* header node, not used */ -#define BNODE 1 /* Board node */ -#define LNODE 2 /* Line node */ -#define CNODE 3 /* Concentrator node */ -#define MNODE 4 /* EBI Module node */ -#define TNODE 5 /* tty name prefix node */ -#define CUNODE 6 /* cu name prefix (non-SCO) */ -#define PNODE 7 /* trans. print prefix node */ -#define JNODE 8 /* maJor number node */ -#define ANODE 9 /* altpin */ -#define TSNODE 10 /* tty structure size */ -#define CSNODE 11 /* channel structure size */ -#define BSNODE 12 /* board structure size */ -#define USNODE 13 /* unit schedule structure size */ -#define FSNODE 14 /* f2200 structure size */ -#define VSNODE 15 /* size of VPIX structures */ -#define INTRNODE 16 /* enable interrupt */ - -/* Enumeration of tokens */ -#define BEGIN 1 -#define END 2 -#define BOARD 10 - -#define EPCFS 11 /* start of EPC family definitions */ -#define ICX 11 -#define MCX 13 -#define PCX 14 -#define IEPC 15 -#define EEPC 16 -#define MEPC 17 -#define IPCM 18 -#define EPCM 19 -#define MPCM 20 -#define PEPC 21 -#define PPCM 22 -#ifdef CP -#define ICP 23 -#define ECP 24 -#define MCP 25 -#endif -#define EPCFE 25 /* end of EPC family definitions */ -#define PC2E 26 -#define PC4E 27 -#define PC4E8K 28 -#define PC8E 29 -#define PC8E8K 30 -#define PC16E 31 -#define MC2E8K 34 -#define MC4E8K 35 -#define MC8E8K 36 - -#define AVANFS 42 /* start of Avanstar family definitions */ -#define A8P 42 -#define A16P 43 -#define AVANFE 43 /* end of Avanstar family definitions */ - -#define DA2000FS 44 /* start of AccelePort 2000 family definitions */ -#define DA22 44 /* AccelePort 2002 */ -#define DA24 45 /* AccelePort 2004 */ -#define DA28 46 /* AccelePort 2008 */ -#define DA216 47 /* AccelePort 2016 */ -#define DAR4 48 /* AccelePort RAS 4 port */ -#define DAR8 49 /* AccelePort RAS 8 port */ -#define DDR24 50 /* DataFire RAS 24 port */ -#define DDR30 51 /* DataFire RAS 30 port */ -#define DDR48 52 /* DataFire RAS 48 port */ -#define DDR60 53 /* DataFire RAS 60 port */ -#define DA2000FE 53 /* end of AccelePort 2000/RAS family definitions */ - -#define PCXRFS 106 /* start of PCXR family definitions */ -#define APORT4 106 -#define APORT8 107 -#define PAPORT4 108 -#define PAPORT8 109 -#define APORT4_920I 110 -#define APORT8_920I 111 -#define APORT4_920P 112 -#define APORT8_920P 113 -#define APORT2_920P 114 -#define PCXRFE 117 /* end of PCXR family definitions */ - -#define LINE 82 -#ifdef T1 -#define T1M 83 -#define E1M 84 -#endif -#define CONC 64 -#define CX 65 -#define EPC 66 -#define MOD 67 -#define PORTS 68 -#define METHOD 69 -#define CUSTOM 70 -#define BASIC 71 -#define STATUS 72 -#define MODEM 73 -/* The following tokens can appear in multiple places */ -#define SPEED 74 -#define NPORTS 75 -#define ID 76 -#define CABLE 77 -#define CONNECT 78 -#define IO 79 -#define MEM 80 -#define DPSZ 81 - -#define TTYN 90 -#define CU 91 -#define PRINT 92 -#define XPRINT 93 -#define CMAJOR 94 -#define ALTPIN 95 -#define STARTO 96 -#define USEINTR 97 -#define PCIINFO 98 - -#define TTSIZ 100 -#define CHSIZ 101 -#define BSSIZ 102 -#define UNTSIZ 103 -#define F2SIZ 104 -#define VPSIZ 105 - -#define TOTAL_BOARD 2 -#define CURRENT_BRD 4 -#define BOARD_TYPE 6 -#define IO_ADDRESS 8 -#define MEM_ADDRESS 10 - -#define FIELDS_PER_PAGE 18 - -#define TB_FIELD 1 -#define CB_FIELD 3 -#define BT_FIELD 5 -#define IO_FIELD 7 -#define ID_FIELD 8 -#define ME_FIELD 9 -#define TTY_FIELD 11 -#define CU_FIELD 13 -#define PR_FIELD 15 -#define MPR_FIELD 17 - -#define MAX_FIELD 512 - -#define INIT 0 -#define NITEMS 128 -#define MAX_ITEM 512 - -#define DSCRINST 1 -#define DSCRNUM 3 -#define ALTPINQ 5 -#define SSAVE 7 - -#define DSCR "32" -#define ONETONINE "123456789" -#define ALL "1234567890" - - -struct cnode { - struct cnode *next; - int type; - int numbrd; - - union { - struct { - char type; /* Board Type */ - short port; /* I/O Address */ - char *portstr; /* I/O Address in string */ - long addr; /* Memory Address */ - char *addrstr; /* Memory Address in string */ - long pcibus; /* PCI BUS */ - char *pcibusstr; /* PCI BUS in string */ - long pcislot; /* PCI SLOT */ - char *pcislotstr; /* PCI SLOT in string */ - char nport; /* Number of Ports */ - char *id; /* tty id */ - int start; /* start of tty counting */ - char *method; /* Install method */ - char v_type; - char v_port; - char v_addr; - char v_pcibus; - char v_pcislot; - char v_nport; - char v_id; - char v_start; - char v_method; - char line1; - char line2; - char conc1; /* total concs in line1 */ - char conc2; /* total concs in line2 */ - char module1; /* total modules for line1 */ - char module2; /* total modules for line2 */ - char *status; /* config status */ - char *dimstatus; /* Y/N */ - int status_index; /* field pointer */ - } board; - - struct { - char *cable; - char v_cable; - char speed; - char v_speed; - } line; - - struct { - char type; - char *connect; - char speed; - char nport; - char *id; - char *idstr; - int start; - char v_type; - char v_connect; - char v_speed; - char v_nport; - char v_id; - char v_start; - } conc; - - struct { - char type; - char nport; - char *id; - char *idstr; - int start; - char v_type; - char v_nport; - char v_id; - char v_start; - } module; - - char *ttyname; - - char *cuname; - - char *printname; - - int majornumber; - - int altpin; - - int ttysize; - - int chsize; - - int bssize; - - int unsize; - - int f2size; - - int vpixsize; - - int useintr; - } u; -}; - -#endif diff --git a/drivers/staging/dgap/dgap_downld.h b/drivers/staging/dgap/dgap_downld.h deleted file mode 100644 index 271ac19257f9..000000000000 --- a/drivers/staging/dgap/dgap_downld.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: dgap_downld.h,v 1.1 2009/10/23 14:01:57 markh Exp $ - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - * - */ - -/* -** downld.h -** - describes the interface between the user level download process -** and the concentrator download driver. -*/ - -#ifndef _DGAP_DOWNLD_H_ -#define _DGAP_DOWNLD_H_ - - -struct fepimg { - int type; /* board type */ - int len; /* length of image */ - char fepimage[1]; /* beginning of image */ -}; - -struct downldio { - unsigned int req_type; /* FEP or concentrator */ - unsigned int bdid; /* opaque board identifier */ - union { - struct downld_t dl; /* download structure */ - struct fepimg fi; /* fep/bios image structure */ - } image; -}; - -#define DIGI_DLREQ_GET (('d'<<8) | 220) -#define DIGI_DLREQ_SET (('d'<<8) | 221) - -#define DIGI_DL_NUKE (('d'<<8) | 222) /* Not really a dl request, but - dangerous enuff to not put in - digi.h */ -/* Packed bits of intarg for DIGI_DL_NUKE */ -#define DIGI_NUKE_RESET_ALL (1 << 31) -#define DIGI_NUKE_INHIBIT_POLLER (1 << 30) -#define DIGI_NUKE_BRD_NUMB 0x0f - - - -#define DLREQ_BIOS 0 -#define DLREQ_FEP 1 -#define DLREQ_CONC 2 -#define DLREQ_CONFIG 3 -#define DLREQ_DEVCREATE 4 - -#endif diff --git a/drivers/staging/dgap/dgap_driver.c b/drivers/staging/dgap/dgap_driver.c deleted file mode 100644 index 089d017fc291..000000000000 --- a/drivers/staging/dgap/dgap_driver.c +++ /dev/null @@ -1,1030 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! - * - * This is shared code between Digi's CVS archive and the - * Linux Kernel sources. - * Changing the source just for reformatting needlessly breaks - * our CVS diff history. - * - * Send any bug fixes/changes to: Eng.Linux at digi dot com. - * Thank you. - * - * $Id: dgap_driver.c,v 1.3 2011/06/21 10:35:16 markh Exp $ - */ - - -#include -#include -#include -#include /* For udelay */ -#include -#include /* For copy_from_user/copy_to_user */ -#include - -#include "dgap_driver.h" -#include "dgap_pci.h" -#include "dgap_fep5.h" -#include "dgap_tty.h" -#include "dgap_conf.h" -#include "dgap_parse.h" -#include "dgap_trace.h" -#include "dgap_sysfs.h" - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Digi International, http://www.digi.com"); -MODULE_DESCRIPTION("Driver for the Digi International EPCA PCI based product line"); -MODULE_SUPPORTED_DEVICE("dgap"); - -/* - * insmod command line overrideable parameters - * - * NOTE: we use a set of macros to create the variables, which allows - * us to specify the variable type, name, initial value, and description. - */ -PARM_INT(debug, 0x00, 0644, "Driver debugging level"); -PARM_INT(rawreadok, 1, 0644, "Bypass flip buffers on input"); -PARM_INT(trcbuf_size, 0x100000, 0644, "Debugging trace buffer size."); - - -/************************************************************************** - * - * protos for this file - * - */ - -static int dgap_start(void); -static void dgap_init_globals(void); -static int dgap_found_board(struct pci_dev *pdev, int id); -static void dgap_cleanup_board(struct board_t *brd); -static void dgap_poll_handler(ulong dummy); -static int dgap_init_pci(void); -static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); -static void dgap_remove_one(struct pci_dev *dev); -static int dgap_probe1(struct pci_dev *pdev, int card_type); -static void dgap_mbuf(struct board_t *brd, const char *fmt, ...); -static int dgap_do_remap(struct board_t *brd); -static irqreturn_t dgap_intr(int irq, void *voidbrd); - -/* Driver load/unload functions */ -int dgap_init_module(void); -void dgap_cleanup_module(void); - -module_init(dgap_init_module); -module_exit(dgap_cleanup_module); - - -/* - * File operations permitted on Control/Management major. - */ -static struct file_operations DgapBoardFops = -{ - .owner = THIS_MODULE, -}; - - -/* - * Globals - */ -uint dgap_NumBoards; -struct board_t *dgap_Board[MAXBOARDS]; -DEFINE_SPINLOCK(dgap_global_lock); -ulong dgap_poll_counter; -char *dgap_config_buf; -int dgap_driver_state = DRIVER_INITIALIZED; -DEFINE_SPINLOCK(dgap_dl_lock); -wait_queue_head_t dgap_dl_wait; -int dgap_dl_action; -int dgap_poll_tick = 20; /* Poll interval - 20 ms */ - -/* - * Static vars. - */ -static int dgap_Major_Control_Registered = FALSE; -static uint dgap_driver_start = FALSE; - -static struct class * dgap_class; - -/* - * Poller stuff - */ -static DEFINE_SPINLOCK(dgap_poll_lock); /* Poll scheduling lock */ -static ulong dgap_poll_time; /* Time of next poll */ -static uint dgap_poll_stop; /* Used to tell poller to stop */ -static struct timer_list dgap_poll_timer; - - -static struct pci_device_id dgap_pci_tbl[] = { - { DIGI_VID, PCI_DEVICE_XEM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { DIGI_VID, PCI_DEVICE_CX_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, - { DIGI_VID, PCI_DEVICE_CX_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, - { DIGI_VID, PCI_DEVICE_EPCJ_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, - { DIGI_VID, PCI_DEVICE_920_2_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, - { DIGI_VID, PCI_DEVICE_920_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, - { DIGI_VID, PCI_DEVICE_920_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, - { DIGI_VID, PCI_DEVICE_XR_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, - { DIGI_VID, PCI_DEVICE_XRJ_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, - { DIGI_VID, PCI_DEVICE_XR_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 }, - { DIGI_VID, PCI_DEVICE_XR_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 }, - { DIGI_VID, PCI_DEVICE_XR_SAIP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 }, - { DIGI_VID, PCI_DEVICE_XR_BULL_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 }, - { DIGI_VID, PCI_DEVICE_920_8_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 }, - { DIGI_VID, PCI_DEVICE_XEM_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, - {0,} /* 0 terminated list. */ -}; -MODULE_DEVICE_TABLE(pci, dgap_pci_tbl); - - -/* - * A generic list of Product names, PCI Vendor ID, and PCI Device ID. - */ -struct board_id { - uint config_type; - uchar *name; - uint maxports; - uint dpatype; -}; - -static struct board_id dgap_Ids[] = -{ - { PPCM, PCI_DEVICE_XEM_NAME, 64, (T_PCXM | T_PCLITE | T_PCIBUS) }, - { PCX, PCI_DEVICE_CX_NAME, 128, (T_CX | T_PCIBUS) }, - { PCX, PCI_DEVICE_CX_IBM_NAME, 128, (T_CX | T_PCIBUS) }, - { PEPC, PCI_DEVICE_EPCJ_NAME, 224, (T_EPC | T_PCIBUS) }, - { APORT2_920P, PCI_DEVICE_920_2_NAME, 2, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { APORT4_920P, PCI_DEVICE_920_4_NAME, 4, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { APORT8_920P, PCI_DEVICE_920_8_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { PAPORT8, PCI_DEVICE_XR_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { PAPORT8, PCI_DEVICE_XRJ_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { PAPORT8, PCI_DEVICE_XR_422_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { PAPORT8, PCI_DEVICE_XR_IBM_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { PAPORT8, PCI_DEVICE_XR_SAIP_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { PAPORT8, PCI_DEVICE_XR_BULL_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { APORT8_920P, PCI_DEVICE_920_8_HP_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { PPCM, PCI_DEVICE_XEM_HP_NAME, 64, (T_PCXM | T_PCLITE | T_PCIBUS) }, - {0,} /* 0 terminated list. */ -}; - -static struct pci_driver dgap_driver = { - .name = "dgap", - .probe = dgap_init_one, - .id_table = dgap_pci_tbl, - .remove = dgap_remove_one, -}; - - -char *dgap_state_text[] = { - "Board Failed", - "Configuration for board not found.\n\t\t\tRun mpi to configure board.", - "Board Found", - "Need Reset", - "Finished Reset", - "Need Config", - "Finished Config", - "Need Device Creation", - "Requested Device Creation", - "Finished Device Creation", - "Need BIOS Load", - "Requested BIOS", - "Doing BIOS Load", - "Finished BIOS Load", - "Need FEP Load", - "Requested FEP", - "Doing FEP Load", - "Finished FEP Load", - "Requested PROC creation", - "Finished PROC creation", - "Board READY", -}; - -char *dgap_driver_state_text[] = { - "Driver Initialized", - "Driver needs configuration load.", - "Driver requested configuration from download daemon.", - "Driver Ready." -}; - - - -/************************************************************************ - * - * Driver load/unload functions - * - ************************************************************************/ - -/* - * init_module() - * - * Module load. This is where it all starts. - */ -int dgap_init_module(void) -{ - int rc = 0; - - APR(("%s, Digi International Part Number %s\n", DG_NAME, DG_PART)); - - /* - * Initialize global stuff - */ - rc = dgap_start(); - - if (rc < 0) { - return(rc); - } - - /* - * Find and configure all the cards - */ - rc = dgap_init_pci(); - - /* - * If something went wrong in the scan, bail out of driver. - */ - if (rc < 0) { - /* Only unregister the pci driver if it was actually registered. */ - if (dgap_NumBoards) - pci_unregister_driver(&dgap_driver); - else - printk("WARNING: dgap driver load failed. No DGAP boards found.\n"); - - dgap_cleanup_module(); - } - else { - dgap_create_driver_sysfiles(&dgap_driver); - } - - DPR_INIT(("Finished init_module. Returning %d\n", rc)); - return (rc); -} - - -/* - * Start of driver. - */ -static int dgap_start(void) -{ - int rc = 0; - unsigned long flags; - - if (dgap_driver_start == FALSE) { - - dgap_driver_start = TRUE; - - /* make sure that the globals are init'd before we do anything else */ - dgap_init_globals(); - - dgap_NumBoards = 0; - - APR(("For the tools package or updated drivers please visit http://www.digi.com\n")); - - /* - * Register our base character device into the kernel. - * This allows the download daemon to connect to the downld device - * before any of the boards are init'ed. - */ - if (!dgap_Major_Control_Registered) { - /* - * Register management/dpa devices - */ - rc = register_chrdev(DIGI_DGAP_MAJOR, "dgap", &DgapBoardFops); - if (rc < 0) { - APR(("Can't register dgap driver device (%d)\n", rc)); - return (rc); - } - - dgap_class = class_create(THIS_MODULE, "dgap_mgmt"); - device_create(dgap_class, NULL, - MKDEV(DIGI_DGAP_MAJOR, 0), - NULL, "dgap_mgmt"); - device_create(dgap_class, NULL, - MKDEV(DIGI_DGAP_MAJOR, 1), - NULL, "dgap_downld"); - dgap_Major_Control_Registered = TRUE; - } - - /* - * Init any global tty stuff. - */ - rc = dgap_tty_preinit(); - - if (rc < 0) { - APR(("tty preinit - not enough memory (%d)\n", rc)); - return(rc); - } - - /* Start the poller */ - DGAP_LOCK(dgap_poll_lock, flags); - init_timer(&dgap_poll_timer); - dgap_poll_timer.function = dgap_poll_handler; - dgap_poll_timer.data = 0; - dgap_poll_time = jiffies + dgap_jiffies_from_ms(dgap_poll_tick); - dgap_poll_timer.expires = dgap_poll_time; - DGAP_UNLOCK(dgap_poll_lock, flags); - - add_timer(&dgap_poll_timer); - - dgap_driver_state = DRIVER_NEED_CONFIG_LOAD; - } - - return (rc); -} - - -/* - * Register pci driver, and return how many boards we have. - */ -static int dgap_init_pci(void) -{ - return pci_register_driver(&dgap_driver); -} - - -/* returns count (>= 0), or negative on error */ -static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int rc; - - /* wake up and enable device */ - rc = pci_enable_device(pdev); - - if (rc < 0) { - rc = -EIO; - } else { - rc = dgap_probe1(pdev, ent->driver_data); - if (rc == 0) { - dgap_NumBoards++; - DPR_INIT(("Incrementing numboards to %d\n", dgap_NumBoards)); - } - } - return rc; -} - - -static int dgap_probe1(struct pci_dev *pdev, int card_type) -{ - return dgap_found_board(pdev, card_type); -} - - -static void dgap_remove_one(struct pci_dev *dev) -{ - /* Do Nothing */ -} - - -/* - * dgap_cleanup_module() - * - * Module unload. This is where it all ends. - */ -void dgap_cleanup_module(void) -{ - int i; - ulong lock_flags; - - DGAP_LOCK(dgap_poll_lock, lock_flags); - dgap_poll_stop = 1; - DGAP_UNLOCK(dgap_poll_lock, lock_flags); - - /* Turn off poller right away. */ - del_timer_sync( &dgap_poll_timer); - - dgap_remove_driver_sysfiles(&dgap_driver); - - - if (dgap_Major_Control_Registered) { - device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 0)); - device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 1)); - class_destroy(dgap_class); - unregister_chrdev(DIGI_DGAP_MAJOR, "dgap"); - } - - kfree(dgap_config_buf); - - for (i = 0; i < dgap_NumBoards; ++i) { - dgap_remove_ports_sysfiles(dgap_Board[i]); - dgap_tty_uninit(dgap_Board[i]); - dgap_cleanup_board(dgap_Board[i]); - } - - dgap_tty_post_uninit(); - -#if defined(DGAP_TRACER) - /* last thing, make sure we release the tracebuffer */ - dgap_tracer_free(); -#endif - if (dgap_NumBoards) - pci_unregister_driver(&dgap_driver); -} - - -/* - * dgap_cleanup_board() - * - * Free all the memory associated with a board - */ -static void dgap_cleanup_board(struct board_t *brd) -{ - int i = 0; - - if(!brd || brd->magic != DGAP_BOARD_MAGIC) - return; - - if (brd->intr_used && brd->irq) - free_irq(brd->irq, brd); - - tasklet_kill(&brd->helper_tasklet); - - if (brd->re_map_port) { - release_mem_region(brd->membase + 0x200000, 0x200000); - iounmap(brd->re_map_port); - brd->re_map_port = NULL; - } - - if (brd->re_map_membase) { - release_mem_region(brd->membase, 0x200000); - iounmap(brd->re_map_membase); - brd->re_map_membase = NULL; - } - - if (brd->msgbuf_head) { - unsigned long flags; - - DGAP_LOCK(dgap_global_lock, flags); - brd->msgbuf = NULL; - printk("%s", brd->msgbuf_head); - kfree(brd->msgbuf_head); - brd->msgbuf_head = NULL; - DGAP_UNLOCK(dgap_global_lock, flags); - } - - /* Free all allocated channels structs */ - for (i = 0; i < MAXPORTS ; i++) { - if (brd->channels[i]) { - kfree(brd->channels[i]); - brd->channels[i] = NULL; - } - } - - kfree(brd->flipbuf); - kfree(brd->flipflagbuf); - - dgap_Board[brd->boardnum] = NULL; - - kfree(brd); -} - - -/* - * dgap_found_board() - * - * A board has been found, init it. - */ -static int dgap_found_board(struct pci_dev *pdev, int id) -{ - struct board_t *brd; - unsigned int pci_irq; - int i = 0; - unsigned long flags; - - /* get the board structure and prep it */ - brd = dgap_Board[dgap_NumBoards] = - (struct board_t *) kzalloc(sizeof(struct board_t), GFP_KERNEL); - if (!brd) { - APR(("memory allocation for board structure failed\n")); - return(-ENOMEM); - } - - /* make a temporary message buffer for the boot messages */ - brd->msgbuf = brd->msgbuf_head = - (char *) kzalloc(sizeof(char) * 8192, GFP_KERNEL); - if(!brd->msgbuf) { - kfree(brd); - APR(("memory allocation for board msgbuf failed\n")); - return(-ENOMEM); - } - - /* store the info for the board we've found */ - brd->magic = DGAP_BOARD_MAGIC; - brd->boardnum = dgap_NumBoards; - brd->firstminor = 0; - brd->vendor = dgap_pci_tbl[id].vendor; - brd->device = dgap_pci_tbl[id].device; - brd->pdev = pdev; - brd->pci_bus = pdev->bus->number; - brd->pci_slot = PCI_SLOT(pdev->devfn); - brd->name = dgap_Ids[id].name; - brd->maxports = dgap_Ids[id].maxports; - brd->type = dgap_Ids[id].config_type; - brd->dpatype = dgap_Ids[id].dpatype; - brd->dpastatus = BD_NOFEP; - init_waitqueue_head(&brd->state_wait); - - DGAP_SPINLOCK_INIT(brd->bd_lock); - - brd->state = BOARD_FOUND; - brd->runwait = 0; - brd->inhibit_poller = FALSE; - brd->wait_for_bios = 0; - brd->wait_for_fep = 0; - - for (i = 0; i < MAXPORTS; i++) { - brd->channels[i] = NULL; - } - - /* store which card & revision we have */ - pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &brd->subvendor); - pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &brd->subdevice); - pci_read_config_byte(pdev, PCI_REVISION_ID, &brd->rev); - - pci_irq = pdev->irq; - brd->irq = pci_irq; - - /* get the PCI Base Address Registers */ - - /* Xr Jupiter and EPC use BAR 2 */ - if (brd->device == PCI_DEVICE_XRJ_DID || brd->device == PCI_DEVICE_EPCJ_DID) { - brd->membase = pci_resource_start(pdev, 2); - brd->membase_end = pci_resource_end(pdev, 2); - } - /* Everyone else uses BAR 0 */ - else { - brd->membase = pci_resource_start(pdev, 0); - brd->membase_end = pci_resource_end(pdev, 0); - } - - if (!brd->membase) { - APR(("card has no PCI IO resources, failing board.\n")); - return -ENODEV; - } - - if (brd->membase & 1) - brd->membase &= ~3; - else - brd->membase &= ~15; - - /* - * On the PCI boards, there is no IO space allocated - * The I/O registers will be in the first 3 bytes of the - * upper 2MB of the 4MB memory space. The board memory - * will be mapped into the low 2MB of the 4MB memory space - */ - brd->port = brd->membase + PCI_IO_OFFSET; - brd->port_end = brd->port + PCI_IO_SIZE; - - - /* - * Special initialization for non-PLX boards - */ - if (brd->device != PCI_DEVICE_XRJ_DID && brd->device != PCI_DEVICE_EPCJ_DID) { - unsigned short cmd; - - pci_write_config_byte(pdev, 0x40, 0); - pci_write_config_byte(pdev, 0x46, 0); - - /* Limit burst length to 2 doubleword transactions */ - pci_write_config_byte(pdev, 0x42, 1); - - /* - * Enable IO and mem if not already done. - * This was needed for support on Itanium. - */ - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); - pci_write_config_word(pdev, PCI_COMMAND, cmd); - } - - /* init our poll helper tasklet */ - tasklet_init(&brd->helper_tasklet, dgap_poll_tasklet, (unsigned long) brd); - - /* Log the information about the board */ - dgap_mbuf(brd, DRVSTR": board %d: %s (rev %d), irq %d\n", - dgap_NumBoards, brd->name, brd->rev, brd->irq); - - DPR_INIT(("dgap_scan(%d) - printing out the msgbuf\n", i)); - DGAP_LOCK(dgap_global_lock, flags); - brd->msgbuf = NULL; - printk("%s", brd->msgbuf_head); - kfree(brd->msgbuf_head); - brd->msgbuf_head = NULL; - DGAP_UNLOCK(dgap_global_lock, flags); - - i = dgap_do_remap(brd); - if (i) - brd->state = BOARD_FAILED; - else - brd->state = NEED_RESET; - - return(0); -} - - -int dgap_finalize_board_init(struct board_t *brd) { - - int rc; - - DPR_INIT(("dgap_finalize_board_init() - start\n")); - - if (!brd || brd->magic != DGAP_BOARD_MAGIC) - return(-ENODEV); - - DPR_INIT(("dgap_finalize_board_init() - start #2\n")); - - brd->use_interrupts = dgap_config_get_useintr(brd); - - /* - * Set up our interrupt handler if we are set to do interrupts. - */ - if (brd->use_interrupts && brd->irq) { - - rc = request_irq(brd->irq, dgap_intr, IRQF_SHARED, "DGAP", brd); - - if (rc) { - dgap_mbuf(brd, DRVSTR": Failed to hook IRQ %d. Board will work in poll mode.\n", - brd->irq); - brd->intr_used = 0; - } - else - brd->intr_used = 1; - } else { - brd->intr_used = 0; - } - - return(0); -} - - -/* - * Remap PCI memory. - */ -static int dgap_do_remap(struct board_t *brd) -{ - if (!brd || brd->magic != DGAP_BOARD_MAGIC) - return -ENXIO; - - if (!request_mem_region(brd->membase, 0x200000, "dgap")) { - APR(("dgap: mem_region %lx already in use.\n", brd->membase)); - return -ENOMEM; - } - - if (!request_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000, "dgap")) { - APR(("dgap: mem_region IO %lx already in use.\n", - brd->membase + PCI_IO_OFFSET)); - release_mem_region(brd->membase, 0x200000); - return -ENOMEM; - } - - brd->re_map_membase = ioremap(brd->membase, 0x200000); - if (!brd->re_map_membase) { - APR(("dgap: ioremap mem %lx cannot be mapped.\n", brd->membase)); - release_mem_region(brd->membase, 0x200000); - release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000); - return -ENOMEM; - } - - brd->re_map_port = ioremap((brd->membase + PCI_IO_OFFSET), 0x200000); - if (!brd->re_map_port) { - release_mem_region(brd->membase, 0x200000); - release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000); - iounmap(brd->re_map_membase); - APR(("dgap: ioremap IO mem %lx cannot be mapped.\n", - brd->membase + PCI_IO_OFFSET)); - return -ENOMEM; - } - - DPR_INIT(("remapped io: 0x%p remapped mem: 0x%p\n", - brd->re_map_port, brd->re_map_membase)); - return 0; -} - - -/***************************************************************************** -* -* Function: -* -* dgap_poll_handler -* -* Author: -* -* Scott H Kilau -* -* Parameters: -* -* dummy -- ignored -* -* Return Values: -* -* none -* -* Description: -* -* As each timer expires, it determines (a) whether the "transmit" -* waiter needs to be woken up, and (b) whether the poller needs to -* be rescheduled. -* -******************************************************************************/ - -static void dgap_poll_handler(ulong dummy) -{ - int i; - struct board_t *brd; - unsigned long lock_flags; - unsigned long lock_flags2; - ulong new_time; - - dgap_poll_counter++; - - - /* - * If driver needs the config file still, - * keep trying to wake up the downloader to - * send us the file. - */ - if (dgap_driver_state == DRIVER_NEED_CONFIG_LOAD) { - /* - * Signal downloader, its got some work to do. - */ - DGAP_LOCK(dgap_dl_lock, lock_flags2); - if (dgap_dl_action != 1) { - dgap_dl_action = 1; - wake_up_interruptible(&dgap_dl_wait); - } - DGAP_UNLOCK(dgap_dl_lock, lock_flags2); - goto schedule_poller; - } - /* - * Do not start the board state machine until - * driver tells us its up and running, and has - * everything it needs. - */ - else if (dgap_driver_state != DRIVER_READY) { - goto schedule_poller; - } - - /* - * If we have just 1 board, or the system is not SMP, - * then use the typical old style poller. - * Otherwise, use our new tasklet based poller, which should - * speed things up for multiple boards. - */ - if ( (dgap_NumBoards == 1) || (num_online_cpus() <= 1) ) { - for (i = 0; i < dgap_NumBoards; i++) { - - brd = dgap_Board[i]; - - if (brd->state == BOARD_FAILED) { - continue; - } - if (!brd->intr_running) { - /* Call the real board poller directly */ - dgap_poll_tasklet((unsigned long) brd); - } - } - } - else { - /* Go thru each board, kicking off a tasklet for each if needed */ - for (i = 0; i < dgap_NumBoards; i++) { - brd = dgap_Board[i]; - - /* - * Attempt to grab the board lock. - * - * If we can't get it, no big deal, the next poll will get it. - * Basically, I just really don't want to spin in here, because I want - * to kick off my tasklets as fast as I can, and then get out the poller. - */ - if (!spin_trylock(&brd->bd_lock)) { - continue; - } - - /* If board is in a failed state, don't bother scheduling a tasklet */ - if (brd->state == BOARD_FAILED) { - spin_unlock(&brd->bd_lock); - continue; - } - - /* Schedule a poll helper task */ - if (!brd->intr_running) { - tasklet_schedule(&brd->helper_tasklet); - } - - /* - * Can't do DGAP_UNLOCK here, as we don't have - * lock_flags because we did a trylock above. - */ - spin_unlock(&brd->bd_lock); - } - } - -schedule_poller: - - /* - * Schedule ourself back at the nominal wakeup interval. - */ - DGAP_LOCK(dgap_poll_lock, lock_flags ); - dgap_poll_time += dgap_jiffies_from_ms(dgap_poll_tick); - - new_time = dgap_poll_time - jiffies; - - if ((ulong) new_time >= 2 * dgap_poll_tick) { - dgap_poll_time = jiffies + dgap_jiffies_from_ms(dgap_poll_tick); - } - - dgap_poll_timer.function = dgap_poll_handler; - dgap_poll_timer.data = 0; - dgap_poll_timer.expires = dgap_poll_time; - DGAP_UNLOCK(dgap_poll_lock, lock_flags ); - - if (!dgap_poll_stop) - add_timer(&dgap_poll_timer); -} - - - - -/* - * dgap_intr() - * - * Driver interrupt handler. - */ -static irqreturn_t dgap_intr(int irq, void *voidbrd) -{ - struct board_t *brd = (struct board_t *) voidbrd; - - if (!brd) { - APR(("Received interrupt (%d) with null board associated\n", irq)); - return IRQ_NONE; - } - - /* - * Check to make sure its for us. - */ - if (brd->magic != DGAP_BOARD_MAGIC) { - APR(("Received interrupt (%d) with a board pointer that wasn't ours!\n", irq)); - return IRQ_NONE; - } - - brd->intr_count++; - - /* - * Schedule tasklet to run at a better time. - */ - tasklet_schedule(&brd->helper_tasklet); - return IRQ_HANDLED; -} - - -/* - * dgap_init_globals() - * - * This is where we initialize the globals from the static insmod - * configuration variables. These are declared near the head of - * this file. - */ -static void dgap_init_globals(void) -{ - int i = 0; - - dgap_rawreadok = rawreadok; - dgap_trcbuf_size = trcbuf_size; - dgap_debug = debug; - - for (i = 0; i < MAXBOARDS; i++) { - dgap_Board[i] = NULL; - } - - init_timer( &dgap_poll_timer ); - - init_waitqueue_head(&dgap_dl_wait); - dgap_dl_action = 0; -} - - -/************************************************************************ - * - * Utility functions - * - ************************************************************************/ - - -/* - * dgap_mbuf() - * - * Used to print to the message buffer during board init. - */ -static void dgap_mbuf(struct board_t *brd, const char *fmt, ...) { - va_list ap; - char buf[1024]; - int i; - unsigned long flags; - size_t length; - - DGAP_LOCK(dgap_global_lock, flags); - - /* Format buf using fmt and arguments contained in ap. */ - va_start(ap, fmt); - i = vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - DPR((buf)); - - if (!brd || !brd->msgbuf) { - printk("%s", buf); - DGAP_UNLOCK(dgap_global_lock, flags); - return; - } - - length = strlen(buf) + 1; - if (brd->msgbuf - brd->msgbuf_head < length) - length = brd->msgbuf - brd->msgbuf_head; - memcpy(brd->msgbuf, buf, length); - brd->msgbuf += length; - - DGAP_UNLOCK(dgap_global_lock, flags); -} - - -/* - * dgap_ms_sleep() - * - * Put the driver to sleep for x ms's - * - * Returns 0 if timed out, !0 (showing signal) if interrupted by a signal. - */ -int dgap_ms_sleep(ulong ms) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((ms * HZ) / 1000); - return (signal_pending(current)); -} - - - -/* - * dgap_ioctl_name() : Returns a text version of each ioctl value. - */ -char *dgap_ioctl_name(int cmd) -{ - switch(cmd) { - - case TCGETA: return("TCGETA"); - case TCGETS: return("TCGETS"); - case TCSETA: return("TCSETA"); - case TCSETS: return("TCSETS"); - case TCSETAW: return("TCSETAW"); - case TCSETSW: return("TCSETSW"); - case TCSETAF: return("TCSETAF"); - case TCSETSF: return("TCSETSF"); - case TCSBRK: return("TCSBRK"); - case TCXONC: return("TCXONC"); - case TCFLSH: return("TCFLSH"); - case TIOCGSID: return("TIOCGSID"); - - case TIOCGETD: return("TIOCGETD"); - case TIOCSETD: return("TIOCSETD"); - case TIOCGWINSZ: return("TIOCGWINSZ"); - case TIOCSWINSZ: return("TIOCSWINSZ"); - - case TIOCMGET: return("TIOCMGET"); - case TIOCMSET: return("TIOCMSET"); - case TIOCMBIS: return("TIOCMBIS"); - case TIOCMBIC: return("TIOCMBIC"); - - /* from digi.h */ - case DIGI_SETA: return("DIGI_SETA"); - case DIGI_SETAW: return("DIGI_SETAW"); - case DIGI_SETAF: return("DIGI_SETAF"); - case DIGI_SETFLOW: return("DIGI_SETFLOW"); - case DIGI_SETAFLOW: return("DIGI_SETAFLOW"); - case DIGI_GETFLOW: return("DIGI_GETFLOW"); - case DIGI_GETAFLOW: return("DIGI_GETAFLOW"); - case DIGI_GETA: return("DIGI_GETA"); - case DIGI_GEDELAY: return("DIGI_GEDELAY"); - case DIGI_SEDELAY: return("DIGI_SEDELAY"); - case DIGI_GETCUSTOMBAUD: return("DIGI_GETCUSTOMBAUD"); - case DIGI_SETCUSTOMBAUD: return("DIGI_SETCUSTOMBAUD"); - case TIOCMODG: return("TIOCMODG"); - case TIOCMODS: return("TIOCMODS"); - case TIOCSDTR: return("TIOCSDTR"); - case TIOCCDTR: return("TIOCCDTR"); - - default: return("unknown"); - } -} diff --git a/drivers/staging/dgap/dgap_driver.h b/drivers/staging/dgap/dgap_driver.h deleted file mode 100644 index 2f7a55a7e40d..000000000000 --- a/drivers/staging/dgap/dgap_driver.h +++ /dev/null @@ -1,620 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - * - ************************************************************************* - * - * Driver includes - * - *************************************************************************/ - -#ifndef __DGAP_DRIVER_H -#define __DGAP_DRIVER_H - -#include /* To get the current Linux version */ -#include /* To pick up the varions Linux types */ -#include /* To pick up the various tty structs/defines */ -#include /* For irqreturn_t type */ - -#include "dgap_types.h" /* Additional types needed by the Digi header files */ -#include "digi.h" /* Digi specific ioctl header */ -#include "dgap_kcompat.h" /* Kernel 2.4/2.6 compat includes */ -#include "dgap_sysfs.h" /* Support for SYSFS */ - -/************************************************************************* - * - * Driver defines - * - *************************************************************************/ - -/* - * Driver identification, error and debugging statments - * - * In theory, you can change all occurrences of "digi" in the next - * three lines, and the driver printk's will all automagically change. - * - * APR((fmt, args, ...)); Always prints message - * DPR((fmt, args, ...)); Only prints if DGAP_TRACER is defined at - * compile time and dgap_debug!=0 - */ -#define DG_NAME "dgap-1.3-16" -#define DG_PART "40002347_C" - -#define PROCSTR "dgap" /* /proc entries */ -#define DEVSTR "/dev/dg/dgap" /* /dev entries */ -#define DRVSTR "dgap" /* Driver name string - * displayed by APR */ -#define APR(args) do { PRINTF_TO_KMEM(args); printk(DRVSTR": "); printk args; \ - } while (0) -#define RAPR(args) do { PRINTF_TO_KMEM(args); printk args; } while (0) - -#define TRC_TO_CONSOLE 1 - -/* - * Debugging levels can be set using debug insmod variable - * They can also be compiled out completely. - */ - -#define DBG_INIT (dgap_debug & 0x01) -#define DBG_BASIC (dgap_debug & 0x02) -#define DBG_CORE (dgap_debug & 0x04) - -#define DBG_OPEN (dgap_debug & 0x08) -#define DBG_CLOSE (dgap_debug & 0x10) -#define DBG_READ (dgap_debug & 0x20) -#define DBG_WRITE (dgap_debug & 0x40) - -#define DBG_IOCTL (dgap_debug & 0x80) - -#define DBG_PROC (dgap_debug & 0x100) -#define DBG_PARAM (dgap_debug & 0x200) -#define DBG_PSCAN (dgap_debug & 0x400) -#define DBG_EVENT (dgap_debug & 0x800) - -#define DBG_DRAIN (dgap_debug & 0x1000) -#define DBG_CARR (dgap_debug & 0x2000) - -#define DBG_MGMT (dgap_debug & 0x4000) - - -#if defined(DGAP_TRACER) - -# if defined(TRC_TO_KMEM) -/* Choose one: */ -# define TRC_ON_OVERFLOW_WRAP_AROUND -# undef TRC_ON_OVERFLOW_SHIFT_BUFFER -# endif //TRC_TO_KMEM - -# define TRC_MAXMSG 1024 -# define TRC_OVERFLOW "(OVERFLOW)" -# define TRC_DTRC "/usr/bin/dtrc" - -#if defined TRC_TO_CONSOLE -#define PRINTF_TO_CONSOLE(args) { printk(DRVSTR": "); printk args; } -#else //!defined TRACE_TO_CONSOLE -#define PRINTF_TO_CONSOLE(args) -#endif - -#if defined TRC_TO_KMEM -#define PRINTF_TO_KMEM(args) dgap_tracef args -#else //!defined TRC_TO_KMEM -#define PRINTF_TO_KMEM(args) -#endif - -#define TRC(args) { PRINTF_TO_KMEM(args); PRINTF_TO_CONSOLE(args) } - -# define DPR_INIT(ARGS) if (DBG_INIT) TRC(ARGS) -# define DPR_BASIC(ARGS) if (DBG_BASIC) TRC(ARGS) -# define DPR_CORE(ARGS) if (DBG_CORE) TRC(ARGS) -# define DPR_OPEN(ARGS) if (DBG_OPEN) TRC(ARGS) -# define DPR_CLOSE(ARGS) if (DBG_CLOSE) TRC(ARGS) -# define DPR_READ(ARGS) if (DBG_READ) TRC(ARGS) -# define DPR_WRITE(ARGS) if (DBG_WRITE) TRC(ARGS) -# define DPR_IOCTL(ARGS) if (DBG_IOCTL) TRC(ARGS) -# define DPR_PROC(ARGS) if (DBG_PROC) TRC(ARGS) -# define DPR_PARAM(ARGS) if (DBG_PARAM) TRC(ARGS) -# define DPR_PSCAN(ARGS) if (DBG_PSCAN) TRC(ARGS) -# define DPR_EVENT(ARGS) if (DBG_EVENT) TRC(ARGS) -# define DPR_DRAIN(ARGS) if (DBG_DRAIN) TRC(ARGS) -# define DPR_CARR(ARGS) if (DBG_CARR) TRC(ARGS) -# define DPR_MGMT(ARGS) if (DBG_MGMT) TRC(ARGS) - -# define DPR(ARGS) if (dgap_debug) TRC(ARGS) -# define P(X) dgap_tracef(#X "=%p\n", X) -# define X(X) dgap_tracef(#X "=%x\n", X) - -#else//!defined DGAP_TRACER - -#define PRINTF_TO_KMEM(args) -# define TRC(ARGS) -# define DPR_INIT(ARGS) -# define DPR_BASIC(ARGS) -# define DPR_CORE(ARGS) -# define DPR_OPEN(ARGS) -# define DPR_CLOSE(ARGS) -# define DPR_READ(ARGS) -# define DPR_WRITE(ARGS) -# define DPR_IOCTL(ARGS) -# define DPR_PROC(ARGS) -# define DPR_PARAM(ARGS) -# define DPR_PSCAN(ARGS) -# define DPR_EVENT(ARGS) -# define DPR_DRAIN(ARGS) -# define DPR_CARR(ARGS) -# define DPR_MGMT(ARGS) - -# define DPR(args) - -#endif//DGAP_TRACER - -/* Number of boards we support at once. */ -#define MAXBOARDS 32 -#define MAXPORTS 224 -#define MAXTTYNAMELEN 200 - -/* Our 3 magic numbers for our board, channel and unit structs */ -#define DGAP_BOARD_MAGIC 0x5c6df104 -#define DGAP_CHANNEL_MAGIC 0x6c6df104 -#define DGAP_UNIT_MAGIC 0x7c6df104 - -/* Serial port types */ -#define DGAP_SERIAL 0 -#define DGAP_PRINT 1 - -#define SERIAL_TYPE_NORMAL 1 - -/* 4 extra for alignment play space */ -#define WRITEBUFLEN ((4096) + 4) -#define MYFLIPLEN N_TTY_BUF_SIZE - -#define SBREAK_TIME 0x25 -#define U2BSIZE 0x400 - -#define dgap_jiffies_from_ms(a) (((a) * HZ) / 1000) - -/* - * Our major for the mgmt devices. - * - * We can use 22, because Digi was allocated 22 and 23 for the epca driver. - * 22 has now become obsolete now that the "cu" devices have - * been removed from 2.6. - * Also, this *IS* the epca driver, just PCI only now. - */ -#ifndef DIGI_DGAP_MAJOR -# define DIGI_DGAP_MAJOR 22 -#endif - -/* - * The parameters we use to define the periods of the moving averages. - */ -#define MA_PERIOD (HZ / 10) -#define SMA_DUR (1 * HZ) -#define EMA_DUR (1 * HZ) -#define SMA_NPERIODS (SMA_DUR / MA_PERIOD) -#define EMA_NPERIODS (EMA_DUR / MA_PERIOD) - -/* - * Define a local default termios struct. All ports will be created - * with this termios initially. This is the same structure that is defined - * as the default in tty_io.c with the same settings overriden as in serial.c - * - * In short, this should match the internal serial ports' defaults. - */ -#define DEFAULT_IFLAGS (ICRNL | IXON) -#define DEFAULT_OFLAGS (OPOST | ONLCR) -#define DEFAULT_CFLAGS (B9600 | CS8 | CREAD | HUPCL | CLOCAL) -#define DEFAULT_LFLAGS (ISIG | ICANON | ECHO | ECHOE | ECHOK | \ - ECHOCTL | ECHOKE | IEXTEN) - -#ifndef _POSIX_VDISABLE -#define _POSIX_VDISABLE '\0' -#endif - -#define SNIFF_MAX 65536 /* Sniff buffer size (2^n) */ -#define SNIFF_MASK (SNIFF_MAX - 1) /* Sniff wrap mask */ - -#define VPDSIZE (512) - -/* - * Lock function/defines. - * Makes spotting lock/unlock locations easier. - */ -# define DGAP_SPINLOCK_INIT(x) spin_lock_init(&(x)) -# define DGAP_LOCK(x,y) spin_lock_irqsave(&(x), y) -# define DGAP_UNLOCK(x,y) spin_unlock_irqrestore(&(x), y) -# define DGAP_TRYLOCK(x,y) spin_trylock(&(x)) - -/* - * All the possible states the driver can be while being loaded. - */ -enum { - DRIVER_INITIALIZED = 0, - DRIVER_NEED_CONFIG_LOAD, - DRIVER_REQUESTED_CONFIG, - DRIVER_READY -}; - -/* - * All the possible states the board can be while booting up. - */ -enum { - BOARD_FAILED = 0, - CONFIG_NOT_FOUND, - BOARD_FOUND, - NEED_RESET, - FINISHED_RESET, - NEED_CONFIG, - FINISHED_CONFIG, - NEED_DEVICE_CREATION, - REQUESTED_DEVICE_CREATION, - FINISHED_DEVICE_CREATION, - NEED_BIOS_LOAD, - REQUESTED_BIOS, - WAIT_BIOS_LOAD, - FINISHED_BIOS_LOAD, - NEED_FEP_LOAD, - REQUESTED_FEP, - WAIT_FEP_LOAD, - FINISHED_FEP_LOAD, - NEED_PROC_CREATION, - FINISHED_PROC_CREATION, - BOARD_READY -}; - -/* - * All the possible states that a requested concentrator image can be in. - */ -enum { - NO_PENDING_CONCENTRATOR_REQUESTS = 0, - NEED_CONCENTRATOR, - REQUESTED_CONCENTRATOR -}; - -extern char *dgap_state_text[]; -extern char *dgap_driver_state_text[]; - - -/* - * Modem line constants are defined as macros because DSR and - * DCD are swapable using the ditty altpin option. - */ -#define D_CD(ch) ch->ch_cd /* Carrier detect */ -#define D_DSR(ch) ch->ch_dsr /* Data set ready */ -#define D_RTS(ch) DM_RTS /* Request to send */ -#define D_CTS(ch) DM_CTS /* Clear to send */ -#define D_RI(ch) DM_RI /* Ring indicator */ -#define D_DTR(ch) DM_DTR /* Data terminal ready */ - - -/************************************************************************* - * - * Structures and closely related defines. - * - *************************************************************************/ - - -/* - * A structure to hold a statistics counter. We also - * compute moving averages for this counter. - */ -struct macounter -{ - u32 cnt; /* Total count */ - ulong accum; /* Acuumulator per period */ - ulong sma; /* Simple moving average */ - ulong ema; /* Exponential moving average */ -}; - - -/************************************************************************ - * Device flag definitions for bd_flags. - ************************************************************************/ -#define BD_FEP5PLUS 0x0001 /* Supports FEP5 Plus commands */ -#define BD_HAS_VPD 0x0002 /* Board has VPD info available */ - - -/* - * Per-board information - */ -struct board_t -{ - int magic; /* Board Magic number. */ - int boardnum; /* Board number: 0-3 */ - int firstminor; /* First minor, e.g. 0, 30, 60 */ - - int type; /* Type of board */ - char *name; /* Product Name */ - struct pci_dev *pdev; /* Pointer to the pci_dev struct */ - u16 vendor; /* PCI vendor ID */ - u16 device; /* PCI device ID */ - u16 subvendor; /* PCI subsystem vendor ID */ - u16 subdevice; /* PCI subsystem device ID */ - uchar rev; /* PCI revision ID */ - uint pci_bus; /* PCI bus value */ - uint pci_slot; /* PCI slot value */ - u16 maxports; /* MAX ports this board can handle */ - uchar vpd[VPDSIZE]; /* VPD of board, if found */ - u32 bd_flags; /* Board flags */ - - spinlock_t bd_lock; /* Used to protect board */ - - u32 state; /* State of card. */ - wait_queue_head_t state_wait; /* Place to sleep on for state change */ - - struct tasklet_struct helper_tasklet; /* Poll helper tasklet */ - - u32 wait_for_bios; - u32 wait_for_fep; - - struct cnode * bd_config; /* Config of board */ - - u16 nasync; /* Number of ports on card */ - - u32 use_interrupts; /* Should we be interrupt driven? */ - ulong irq; /* Interrupt request number */ - ulong intr_count; /* Count of interrupts */ - u32 intr_used; /* Non-zero if using interrupts */ - u32 intr_running; /* Non-zero if FEP knows its doing interrupts */ - - ulong port; /* Start of base io port of the card */ - ulong port_end; /* End of base io port of the card */ - ulong membase; /* Start of base memory of the card */ - ulong membase_end; /* End of base memory of the card */ - - uchar *re_map_port; /* Remapped io port of the card */ - uchar *re_map_membase;/* Remapped memory of the card */ - - uchar runwait; /* # Processes waiting for FEP */ - uchar inhibit_poller; /* Tells the poller to leave us alone */ - - struct channel_t *channels[MAXPORTS]; /* array of pointers to our channels. */ - - struct tty_driver *SerialDriver; - char SerialName[200]; - struct tty_driver *PrintDriver; - char PrintName[200]; - - u32 dgap_Major_Serial_Registered; - u32 dgap_Major_TransparentPrint_Registered; - - u32 dgap_Serial_Major; - u32 dgap_TransparentPrint_Major; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) - u32 TtyRefCnt; -#endif - - struct bs_t *bd_bs; /* Base structure pointer */ - - char *flipbuf; /* Our flip buffer, alloced if board is found */ - char *flipflagbuf; /* Our flip flag buffer, alloced if board is found */ - - u16 dpatype; /* The board "type", as defined by DPA */ - u16 dpastatus; /* The board "status", as defined by DPA */ - wait_queue_head_t kme_wait; /* Needed for DPA support */ - - u32 conc_dl_status; /* Status of any pending conc download */ - /* - * Mgmt data. - */ - char *msgbuf_head; - char *msgbuf; -}; - - - -/************************************************************************ - * Unit flag definitions for un_flags. - ************************************************************************/ -#define UN_ISOPEN 0x0001 /* Device is open */ -#define UN_CLOSING 0x0002 /* Line is being closed */ -#define UN_IMM 0x0004 /* Service immediately */ -#define UN_BUSY 0x0008 /* Some work this channel */ -#define UN_BREAKI 0x0010 /* Input break received */ -#define UN_PWAIT 0x0020 /* Printer waiting for terminal */ -#define UN_TIME 0x0040 /* Waiting on time */ -#define UN_EMPTY 0x0080 /* Waiting output queue empty */ -#define UN_LOW 0x0100 /* Waiting output low water mark*/ -#define UN_EXCL_OPEN 0x0200 /* Open for exclusive use */ -#define UN_WOPEN 0x0400 /* Device waiting for open */ -#define UN_WIOCTL 0x0800 /* Device waiting for open */ -#define UN_HANGUP 0x8000 /* Carrier lost */ - -struct device; - -/************************************************************************ - * Structure for terminal or printer unit. - ************************************************************************/ -struct un_t { - int magic; /* Unit Magic Number. */ - struct channel_t *un_ch; - u32 un_time; - u32 un_type; - u32 un_open_count; /* Counter of opens to port */ - struct tty_struct *un_tty;/* Pointer to unit tty structure */ - u32 un_flags; /* Unit flags */ - wait_queue_head_t un_flags_wait; /* Place to sleep to wait on unit */ - u32 un_dev; /* Minor device number */ - tcflag_t un_oflag; /* oflags being done on board */ - tcflag_t un_lflag; /* lflags being done on board */ - struct device *un_sysfs; -}; - - -/************************************************************************ - * Device flag definitions for ch_flags. - ************************************************************************/ -#define CH_PRON 0x0001 /* Printer on string */ -#define CH_OUT 0x0002 /* Dial-out device open */ -#define CH_STOP 0x0004 /* Output is stopped */ -#define CH_STOPI 0x0008 /* Input is stopped */ -#define CH_CD 0x0010 /* Carrier is present */ -#define CH_FCAR 0x0020 /* Carrier forced on */ - -#define CH_RXBLOCK 0x0080 /* Enable rx blocked flag */ -#define CH_WLOW 0x0100 /* Term waiting low event */ -#define CH_WEMPTY 0x0200 /* Term waiting empty event */ -#define CH_RENABLE 0x0400 /* Buffer just emptied */ -#define CH_RACTIVE 0x0800 /* Process active in xxread() */ -#define CH_RWAIT 0x1000 /* Process waiting in xxread() */ -#define CH_BAUD0 0x2000 /* Used for checking B0 transitions */ -#define CH_HANGUP 0x8000 /* Hangup received */ - -/* - * Definitions for ch_sniff_flags - */ -#define SNIFF_OPEN 0x1 -#define SNIFF_WAIT_DATA 0x2 -#define SNIFF_WAIT_SPACE 0x4 - - -/************************************************************************ - * Channel information structure. - ************************************************************************/ -struct channel_t { - int magic; /* Channel Magic Number */ - struct bs_t *ch_bs; /* Base structure pointer */ - struct cm_t *ch_cm; /* Command queue pointer */ - struct board_t *ch_bd; /* Board structure pointer */ - unsigned char *ch_vaddr; /* FEP memory origin */ - unsigned char *ch_taddr; /* Write buffer origin */ - unsigned char *ch_raddr; /* Read buffer origin */ - struct digi_t ch_digi; /* Transparent Print structure */ - struct un_t ch_tun; /* Terminal unit info */ - struct un_t ch_pun; /* Printer unit info */ - - spinlock_t ch_lock; /* provide for serialization */ - wait_queue_head_t ch_flags_wait; - - u32 pscan_state; - uchar pscan_savechar; - - u32 ch_portnum; /* Port number, 0 offset. */ - u32 ch_open_count; /* open count */ - u32 ch_flags; /* Channel flags */ - - - u32 ch_close_delay; /* How long we should drop RTS/DTR for */ - - u32 ch_cpstime; /* Time for CPS calculations */ - - tcflag_t ch_c_iflag; /* channel iflags */ - tcflag_t ch_c_cflag; /* channel cflags */ - tcflag_t ch_c_oflag; /* channel oflags */ - tcflag_t ch_c_lflag; /* channel lflags */ - - u16 ch_fepiflag; /* FEP tty iflags */ - u16 ch_fepcflag; /* FEP tty cflags */ - u16 ch_fepoflag; /* FEP tty oflags */ - u16 ch_wopen; /* Waiting for open process cnt */ - u16 ch_tstart; /* Transmit buffer start */ - u16 ch_tsize; /* Transmit buffer size */ - u16 ch_rstart; /* Receive buffer start */ - u16 ch_rsize; /* Receive buffer size */ - u16 ch_rdelay; /* Receive delay time */ - - u16 ch_tlw; /* Our currently set low water mark */ - - u16 ch_cook; /* Output character mask */ - - uchar ch_card; /* Card channel is on */ - uchar ch_stopc; /* Stop character */ - uchar ch_startc; /* Start character */ - - uchar ch_mostat; /* FEP output modem status */ - uchar ch_mistat; /* FEP input modem status */ - uchar ch_mforce; /* Modem values to be forced */ - uchar ch_mval; /* Force values */ - uchar ch_fepstopc; /* FEP stop character */ - uchar ch_fepstartc; /* FEP start character */ - - uchar ch_astopc; /* Auxiliary Stop character */ - uchar ch_astartc; /* Auxiliary Start character */ - uchar ch_fepastopc; /* Auxiliary FEP stop char */ - uchar ch_fepastartc; /* Auxiliary FEP start char */ - - uchar ch_hflow; /* FEP hardware handshake */ - uchar ch_dsr; /* stores real dsr value */ - uchar ch_cd; /* stores real cd value */ - uchar ch_tx_win; /* channel tx buffer window */ - uchar ch_rx_win; /* channel rx buffer window */ - uint ch_custom_speed; /* Custom baud, if set */ - uint ch_baud_info; /* Current baud info for /proc output */ - ulong ch_rxcount; /* total of data received so far */ - ulong ch_txcount; /* total of data transmitted so far */ - ulong ch_err_parity; /* Count of parity errors on channel */ - ulong ch_err_frame; /* Count of framing errors on channel */ - ulong ch_err_break; /* Count of breaks on channel */ - ulong ch_err_overrun; /* Count of overruns on channel */ - - uint ch_sniff_in; - uint ch_sniff_out; - char *ch_sniff_buf; /* Sniff buffer for proc */ - ulong ch_sniff_flags; /* Channel flags */ - wait_queue_head_t ch_sniff_wait; -}; - - -/************************************************************************* - * - * Prototypes for non-static functions used in more than one module - * - *************************************************************************/ - -extern int dgap_ms_sleep(ulong ms); -extern char *dgap_ioctl_name(int cmd); -extern void dgap_do_bios_load(struct board_t *brd, uchar __user *ubios, int len); -extern void dgap_do_fep_load(struct board_t *brd, uchar __user *ufep, int len); -extern void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len); -extern void dgap_do_config_load(uchar __user *uaddr, int len); -extern int dgap_after_config_loaded(void); -extern int dgap_finalize_board_init(struct board_t *brd); - -/* - * Our Global Variables. - */ -extern int dgap_driver_state; /* The state of the driver */ -extern int dgap_debug; /* Debug variable */ -extern int dgap_rawreadok; /* Set if user wants rawreads */ -extern int dgap_poll_tick; /* Poll interval - 20 ms */ -extern spinlock_t dgap_global_lock; /* Driver global spinlock */ -extern uint dgap_NumBoards; /* Total number of boards */ -extern struct board_t *dgap_Board[MAXBOARDS]; /* Array of board structs */ -extern ulong dgap_poll_counter; /* Times the poller has run */ -extern char *dgap_config_buf; /* The config file buffer */ -extern spinlock_t dgap_dl_lock; /* Downloader spinlock */ -extern wait_queue_head_t dgap_dl_wait; /* Wait queue for downloader */ -extern int dgap_dl_action; /* Action flag for downloader */ -extern int dgap_registerttyswithsysfs; /* Should we register the */ - /* ttys with sysfs or not */ - -/* - * Global functions declared in dgap_fep5.c, but must be hidden from - * user space programs. - */ -extern void dgap_poll_tasklet(unsigned long data); -extern void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, uchar byte2, uint ncmds); -extern void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds); -extern void dgap_wmove(struct channel_t *ch, char *buf, uint cnt); -extern int dgap_param(struct tty_struct *tty); -extern void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf, unsigned char *fbuf, int *len); -extern uint dgap_get_custom_baud(struct channel_t *ch); -extern void dgap_firmware_reset_port(struct channel_t *ch); - -#endif diff --git a/drivers/staging/dgap/dgap_fep5.c b/drivers/staging/dgap/dgap_fep5.c deleted file mode 100644 index f75831a422e8..000000000000 --- a/drivers/staging/dgap/dgap_fep5.c +++ /dev/null @@ -1,1938 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! - * - * This is shared code between Digi's CVS archive and the - * Linux Kernel sources. - * Changing the source just for reformatting needlessly breaks - * our CVS diff history. - * - * Send any bug fixes/changes to: Eng.Linux at digi dot com. - * Thank you. - * - * $Id: dgap_fep5.c,v 1.2 2011/06/21 10:35:40 markh Exp $ - */ - - -#include -#include -#include -#include -#include /* For udelay */ -#include /* For copy_from_user/copy_to_user */ -#include -#include /* For tty_schedule_flip */ -#include - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) -#include -#endif - -#include "dgap_driver.h" -#include "dgap_pci.h" -#include "dgap_fep5.h" -#include "dgap_tty.h" -#include "dgap_conf.h" -#include "dgap_parse.h" -#include "dgap_trace.h" - -/* - * Our function prototypes - */ -static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds); -static int dgap_event(struct board_t *bd); - -/* - * internal variables - */ -static uint dgap_count = 500; - - -/* - * Loads the dgap.conf config file from the user. - */ -void dgap_do_config_load(uchar __user *uaddr, int len) -{ - int orig_len = len; - char *to_addr; - uchar __user *from_addr = uaddr; - char buf[U2BSIZE]; - int n; - - to_addr = dgap_config_buf = kzalloc(len + 1, GFP_ATOMIC); - if (!dgap_config_buf) { - DPR_INIT(("dgap_do_config_load - unable to allocate memory for file\n")); - dgap_driver_state = DRIVER_NEED_CONFIG_LOAD; - return; - } - - n = U2BSIZE; - while (len) { - - if (n > len) - n = len; - - if (copy_from_user((char *) &buf, from_addr, n) == -1 ) - return; - - /* Copy data from buffer to kernel memory */ - memcpy(to_addr, buf, n); - - /* increment counts */ - len -= n; - to_addr += n; - from_addr += n; - n = U2BSIZE; - } - - dgap_config_buf[orig_len] = '\0'; - - to_addr = dgap_config_buf; - dgap_parsefile(&to_addr, TRUE); - - DPR_INIT(("dgap_config_load() finish\n")); - - return; -} - - -int dgap_after_config_loaded(void) -{ - int i = 0; - int rc = 0; - - /* - * Register our ttys, now that we have the config loaded. - */ - for (i = 0; i < dgap_NumBoards; ++i) { - - /* - * Initialize KME waitqueues... - */ - init_waitqueue_head(&(dgap_Board[i]->kme_wait)); - - /* - * allocate flip buffer for board. - */ - dgap_Board[i]->flipbuf = kzalloc(MYFLIPLEN, GFP_ATOMIC); - dgap_Board[i]->flipflagbuf = kzalloc(MYFLIPLEN, GFP_ATOMIC); - } - - return rc; -} - - - -/*======================================================================= - * - * usertoboard - copy from user space to board space. - * - *=======================================================================*/ -static int dgap_usertoboard(struct board_t *brd, char *to_addr, char __user *from_addr, int len) -{ - char buf[U2BSIZE]; - int n = U2BSIZE; - - if (!brd || brd->magic != DGAP_BOARD_MAGIC) - return -EFAULT; - - while (len) { - if (n > len) - n = len; - - if (copy_from_user((char *) &buf, from_addr, n) == -1 ) { - return -EFAULT; - } - - /* Copy data from buffer to card memory */ - memcpy_toio(to_addr, buf, n); - - /* increment counts */ - len -= n; - to_addr += n; - from_addr += n; - n = U2BSIZE; - } - return 0; -} - - -/* - * Copies the BIOS code from the user to the board, - * and starts the BIOS running. - */ -void dgap_do_bios_load(struct board_t *brd, uchar __user *ubios, int len) -{ - uchar *addr; - uint offset; - int i; - - if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) - return; - - DPR_INIT(("dgap_do_bios_load() start\n")); - - addr = brd->re_map_membase; - - /* - * clear POST area - */ - for (i = 0; i < 16; i++) - writeb(0, addr + POSTAREA + i); - - /* - * Download bios - */ - offset = 0x1000; - if (dgap_usertoboard(brd, addr + offset, ubios, len) == -1 ) { - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - return; - } - - writel(0x0bf00401, addr); - writel(0, (addr + 4)); - - /* Clear the reset, and change states. */ - writeb(FEPCLR, brd->re_map_port); - brd->state = WAIT_BIOS_LOAD; -} - - -/* - * Checks to see if the BIOS completed running on the card. - */ -static void dgap_do_wait_for_bios(struct board_t *brd) -{ - uchar *addr; - u16 word; - - if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) - return; - - addr = brd->re_map_membase; - word = readw(addr + POSTAREA); - - /* Check to see if BIOS thinks board is good. (GD). */ - if (word == *(u16 *) "GD") { - DPR_INIT(("GOT GD in memory, moving states.\n")); - brd->state = FINISHED_BIOS_LOAD; - return; - } - - /* Give up on board after too long of time taken */ - if (brd->wait_for_bios++ > 5000) { - u16 err1 = readw(addr + SEQUENCE); - u16 err2 = readw(addr + ERROR); - APR(("***WARNING*** %s failed diagnostics. Error #(%x,%x).\n", - brd->name, err1, err2)); - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - } -} - - -/* - * Copies the FEP code from the user to the board, - * and starts the FEP running. - */ -void dgap_do_fep_load(struct board_t *brd, uchar __user *ufep, int len) -{ - uchar *addr; - uint offset; - - if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) - return; - - addr = brd->re_map_membase; - - DPR_INIT(("dgap_do_fep_load() for board %s : start\n", brd->name)); - - /* - * Download FEP - */ - offset = 0x1000; - if (dgap_usertoboard(brd, addr + offset, ufep, len) == -1 ) { - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - return; - } - - /* - * If board is a concentrator product, we need to give - * it its config string describing how the concentrators look. - */ - if ((brd->type == PCX) || (brd->type == PEPC)) { - uchar string[100]; - uchar *config, *xconfig; - int i = 0; - - xconfig = dgap_create_config_string(brd, string); - - /* Write string to board memory */ - config = addr + CONFIG; - for (; i < CONFIGSIZE; i++, config++, xconfig++) { - writeb(*xconfig, config); - if ((*xconfig & 0xff) == 0xff) - break; - } - } - - writel(0xbfc01004, (addr + 0xc34)); - writel(0x3, (addr + 0xc30)); - - /* change states. */ - brd->state = WAIT_FEP_LOAD; - - DPR_INIT(("dgap_do_fep_load() for board %s : finish\n", brd->name)); - -} - - -/* - * Waits for the FEP to report thats its ready for us to use. - */ -static void dgap_do_wait_for_fep(struct board_t *brd) -{ - uchar *addr; - u16 word; - - if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) - return; - - addr = brd->re_map_membase; - - DPR_INIT(("dgap_do_wait_for_fep() for board %s : start. addr: %p\n", brd->name, addr)); - - word = readw(addr + FEPSTAT); - - /* Check to see if FEP is up and running now. */ - if (word == *(u16 *) "OS") { - DPR_INIT(("GOT OS in memory for board %s, moving states.\n", brd->name)); - brd->state = FINISHED_FEP_LOAD; - - /* - * Check to see if the board can support FEP5+ commands. - */ - word = readw(addr + FEP5_PLUS); - if (word == *(u16 *) "5A") { - DPR_INIT(("GOT 5A in memory for board %s, board supports extended FEP5 commands.\n", brd->name)); - brd->bd_flags |= BD_FEP5PLUS; - } - - return; - } - - /* Give up on board after too long of time taken */ - if (brd->wait_for_fep++ > 5000) { - u16 err1 = readw(addr + SEQUENCE); - u16 err2 = readw(addr + ERROR); - APR(("***WARNING*** FEPOS for %s not functioning. Error #(%x,%x).\n", - brd->name, err1, err2)); - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - } - - DPR_INIT(("dgap_do_wait_for_fep() for board %s : finish\n", brd->name)); -} - - -/* - * Physically forces the FEP5 card to reset itself. - */ -static void dgap_do_reset_board(struct board_t *brd) -{ - uchar check; - u32 check1; - u32 check2; - int i = 0; - - if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase || !brd->re_map_port) { - DPR_INIT(("dgap_do_reset_board() start. bad values. brd: %p mem: %p io: %p\n", - brd, brd ? brd->re_map_membase : 0, brd ? brd->re_map_port : 0)); - return; - } - - DPR_INIT(("dgap_do_reset_board() start. io: %p\n", brd->re_map_port)); - - /* FEPRST does not vary among supported boards */ - writeb(FEPRST, brd->re_map_port); - - for (i = 0; i <= 1000; i++) { - check = readb(brd->re_map_port) & 0xe; - if (check == FEPRST) - break; - udelay(10); - - } - if (i > 1000) { - APR(("*** WARNING *** Board not resetting... Failing board.\n")); - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - goto failed; - } - - /* - * Make sure there really is memory out there. - */ - writel(0xa55a3cc3, (brd->re_map_membase + LOWMEM)); - writel(0x5aa5c33c, (brd->re_map_membase + HIGHMEM)); - check1 = readl(brd->re_map_membase + LOWMEM); - check2 = readl(brd->re_map_membase + HIGHMEM); - - if ((check1 != 0xa55a3cc3) || (check2 != 0x5aa5c33c)) { - APR(("*** Warning *** No memory at %p for board.\n", brd->re_map_membase)); - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - goto failed; - } - - if (brd->state != BOARD_FAILED) - brd->state = FINISHED_RESET; - -failed: - DPR_INIT(("dgap_do_reset_board() finish\n")); -} - - -/* - * Sends a concentrator image into the FEP5 board. - */ -void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len) -{ - char *vaddr; - u16 offset = 0; - struct downld_t *to_dp; - - if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) - return; - - vaddr = brd->re_map_membase; - - offset = readw((u16 *) (vaddr + DOWNREQ)); - to_dp = (struct downld_t *) (vaddr + (int) offset); - - /* - * The image was already read into kernel space, - * we do NOT need a user space read here - */ - memcpy_toio((char *) to_dp, uaddr, sizeof(struct downld_t)); - - /* Tell card we have data for it */ - writew(0, vaddr + (DOWNREQ)); - - brd->conc_dl_status = NO_PENDING_CONCENTRATOR_REQUESTS; -} - - -#define EXPANSION_ROM_SIZE (64 * 1024) -#define FEP5_ROM_MAGIC (0xFEFFFFFF) - -static void dgap_get_vpd(struct board_t *brd) -{ - u32 magic; - u32 base_offset; - u16 rom_offset; - u16 vpd_offset; - u16 image_length; - u16 i; - uchar byte1; - uchar byte2; - - /* - * Poke the magic number at the PCI Rom Address location. - * If VPD is supported, the value read from that address - * will be non-zero. - */ - magic = FEP5_ROM_MAGIC; - pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic); - pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic); - - /* VPD not supported, bail */ - if (!magic) - return; - - /* - * To get to the OTPROM memory, we have to send the boards base - * address or'ed with 1 into the PCI Rom Address location. - */ - magic = brd->membase | 0x01; - pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic); - pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic); - - byte1 = readb(brd->re_map_membase); - byte2 = readb(brd->re_map_membase + 1); - - /* - * If the board correctly swapped to the OTPROM memory, - * the first 2 bytes (header) should be 0x55, 0xAA - */ - if (byte1 == 0x55 && byte2 == 0xAA) { - - base_offset = 0; - - /* - * We have to run through all the OTPROM memory looking - * for the VPD offset. - */ - while (base_offset <= EXPANSION_ROM_SIZE) { - - /* - * Lots of magic numbers here. - * - * The VPD offset is located inside the ROM Data Structure. - * We also have to remember the length of each - * ROM Data Structure, so we can "hop" to the next - * entry if the VPD isn't in the current - * ROM Data Structure. - */ - rom_offset = readw(brd->re_map_membase + base_offset + 0x18); - image_length = readw(brd->re_map_membase + rom_offset + 0x10) * 512; - vpd_offset = readw(brd->re_map_membase + rom_offset + 0x08); - - /* Found the VPD entry */ - if (vpd_offset) - break; - - /* We didn't find a VPD entry, go to next ROM entry. */ - base_offset += image_length; - - byte1 = readb(brd->re_map_membase + base_offset); - byte2 = readb(brd->re_map_membase + base_offset + 1); - - /* - * If the new ROM offset doesn't have 0x55, 0xAA - * as its header, we have run out of ROM. - */ - if (byte1 != 0x55 || byte2 != 0xAA) - break; - } - - /* - * If we have a VPD offset, then mark the board - * as having a valid VPD, and copy VPDSIZE (512) bytes of - * that VPD to the buffer we have in our board structure. - */ - if (vpd_offset) { - brd->bd_flags |= BD_HAS_VPD; - for (i = 0; i < VPDSIZE; i++) - brd->vpd[i] = readb(brd->re_map_membase + vpd_offset + i); - } - } - - /* - * We MUST poke the magic number at the PCI Rom Address location again. - * This makes the card report the regular board memory back to us, - * rather than the OTPROM memory. - */ - magic = FEP5_ROM_MAGIC; - pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic); -} - - -/* - * Our board poller function. - */ -void dgap_poll_tasklet(unsigned long data) -{ - struct board_t *bd = (struct board_t *) data; - ulong lock_flags; - ulong lock_flags2; - char *vaddr; - u16 head, tail; - u16 *chk_addr; - u16 check = 0; - - if (!bd || (bd->magic != DGAP_BOARD_MAGIC)) { - APR(("dgap_poll_tasklet() - NULL or bad bd.\n")); - return; - } - - if (bd->inhibit_poller) - return; - - DGAP_LOCK(bd->bd_lock, lock_flags); - - vaddr = bd->re_map_membase; - - /* - * If board is ready, parse deeper to see if there is anything to do. - */ - if (bd->state == BOARD_READY) { - - struct ev_t *eaddr = NULL; - - if (!bd->re_map_membase) { - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return; - } - if (!bd->re_map_port) { - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return; - } - - if (!bd->nasync) { - goto out; - } - - /* - * If this is a CX or EPCX, we need to see if the firmware - * is requesting a concentrator image from us. - */ - if ((bd->type == PCX) || (bd->type == PEPC)) { - chk_addr = (u16 *) (vaddr + DOWNREQ); - check = readw(chk_addr); - /* Nonzero if FEP is requesting concentrator image. */ - if (check) { - if (bd->conc_dl_status == NO_PENDING_CONCENTRATOR_REQUESTS) - bd->conc_dl_status = NEED_CONCENTRATOR; - /* - * Signal downloader, its got some work to do. - */ - DGAP_LOCK(dgap_dl_lock, lock_flags2); - if (dgap_dl_action != 1) { - dgap_dl_action = 1; - wake_up_interruptible(&dgap_dl_wait); - } - DGAP_UNLOCK(dgap_dl_lock, lock_flags2); - - } - } - - eaddr = (struct ev_t *) (vaddr + EVBUF); - - /* Get our head and tail */ - head = readw(&(eaddr->ev_head)); - tail = readw(&(eaddr->ev_tail)); - - /* - * If there is an event pending. Go service it. - */ - if (head != tail) { - DGAP_UNLOCK(bd->bd_lock, lock_flags); - dgap_event(bd); - DGAP_LOCK(bd->bd_lock, lock_flags); - } - -out: - /* - * If board is doing interrupts, ACK the interrupt. - */ - if (bd && bd->intr_running) { - readb(bd->re_map_port + 2); - } - - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return; - } - - /* Our state machine to get the board up and running */ - - /* Reset board */ - if (bd->state == NEED_RESET) { - - /* Get VPD info */ - dgap_get_vpd(bd); - - dgap_do_reset_board(bd); - } - - /* Move to next state */ - if (bd->state == FINISHED_RESET) { - bd->state = NEED_CONFIG; - } - - if (bd->state == NEED_CONFIG) { - /* - * Match this board to a config the user created for us. - */ - bd->bd_config = dgap_find_config(bd->type, bd->pci_bus, bd->pci_slot); - - /* - * Because the 4 port Xr products share the same PCI ID - * as the 8 port Xr products, if we receive a NULL config - * back, and this is a PAPORT8 board, retry with a - * PAPORT4 attempt as well. - */ - if (bd->type == PAPORT8 && !bd->bd_config) { - bd->bd_config = dgap_find_config(PAPORT4, bd->pci_bus, bd->pci_slot); - } - - /* - * Register the ttys (if any) into the kernel. - */ - if (bd->bd_config) { - bd->state = FINISHED_CONFIG; - } - else { - bd->state = CONFIG_NOT_FOUND; - } - } - - /* Move to next state */ - if (bd->state == FINISHED_CONFIG) { - bd->state = NEED_DEVICE_CREATION; - } - - /* Move to next state */ - if (bd->state == NEED_DEVICE_CREATION) { - /* - * Signal downloader, its got some work to do. - */ - DGAP_LOCK(dgap_dl_lock, lock_flags2); - if (dgap_dl_action != 1) { - dgap_dl_action = 1; - wake_up_interruptible(&dgap_dl_wait); - } - DGAP_UNLOCK(dgap_dl_lock, lock_flags2); - } - - /* Move to next state */ - if (bd->state == FINISHED_DEVICE_CREATION) { - bd->state = NEED_BIOS_LOAD; - } - - /* Move to next state */ - if (bd->state == NEED_BIOS_LOAD) { - /* - * Signal downloader, its got some work to do. - */ - DGAP_LOCK(dgap_dl_lock, lock_flags2); - if (dgap_dl_action != 1) { - dgap_dl_action = 1; - wake_up_interruptible(&dgap_dl_wait); - } - DGAP_UNLOCK(dgap_dl_lock, lock_flags2); - } - - /* Wait for BIOS to test board... */ - if (bd->state == WAIT_BIOS_LOAD) { - dgap_do_wait_for_bios(bd); - } - - /* Move to next state */ - if (bd->state == FINISHED_BIOS_LOAD) { - bd->state = NEED_FEP_LOAD; - - /* - * Signal downloader, its got some work to do. - */ - DGAP_LOCK(dgap_dl_lock, lock_flags2); - if (dgap_dl_action != 1) { - dgap_dl_action = 1; - wake_up_interruptible(&dgap_dl_wait); - } - DGAP_UNLOCK(dgap_dl_lock, lock_flags2); - } - - /* Wait for FEP to load on board... */ - if (bd->state == WAIT_FEP_LOAD) { - dgap_do_wait_for_fep(bd); - } - - - /* Move to next state */ - if (bd->state == FINISHED_FEP_LOAD) { - - /* - * Do tty device initialization. - */ - int rc = dgap_tty_init(bd); - - if (rc < 0) { - dgap_tty_uninit(bd); - APR(("Can't init tty devices (%d)\n", rc)); - bd->state = BOARD_FAILED; - bd->dpastatus = BD_NOFEP; - } - else { - bd->state = NEED_PROC_CREATION; - - /* - * Signal downloader, its got some work to do. - */ - DGAP_LOCK(dgap_dl_lock, lock_flags2); - if (dgap_dl_action != 1) { - dgap_dl_action = 1; - wake_up_interruptible(&dgap_dl_wait); - } - DGAP_UNLOCK(dgap_dl_lock, lock_flags2); - } - } - - /* Move to next state */ - if (bd->state == FINISHED_PROC_CREATION) { - - bd->state = BOARD_READY; - bd->dpastatus = BD_RUNNING; - - /* - * If user requested the board to run in interrupt mode, - * go and set it up on the board. - */ - if (bd->intr_used) { - writew(1, (bd->re_map_membase + ENABLE_INTR)); - /* - * Tell the board to poll the UARTS as fast as possible. - */ - writew(FEPPOLL_MIN, (bd->re_map_membase + FEPPOLL)); - bd->intr_running = 1; - } - - /* Wake up anyone waiting for board state to change to ready */ - wake_up_interruptible(&bd->state_wait); - } - - DGAP_UNLOCK(bd->bd_lock, lock_flags); -} - - -/*======================================================================= - * - * dgap_cmdb - Sends a 2 byte command to the FEP. - * - * ch - Pointer to channel structure. - * cmd - Command to be sent. - * byte1 - Integer containing first byte to be sent. - * byte2 - Integer containing second byte to be sent. - * ncmds - Wait until ncmds or fewer cmds are left - * in the cmd buffer before returning. - * - *=======================================================================*/ -void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, uchar byte2, uint ncmds) -{ - char *vaddr = NULL; - struct cm_t *cm_addr = NULL; - uint count; - uint n; - u16 head; - u16 tail; - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - /* - * Check if board is still alive. - */ - if (ch->ch_bd->state == BOARD_FAILED) { - DPR_CORE(("%s:%d board is in failed state.\n", __FILE__, __LINE__)); - return; - } - - /* - * Make sure the pointers are in range before - * writing to the FEP memory. - */ - vaddr = ch->ch_bd->re_map_membase; - - if (!vaddr) - return; - - cm_addr = (struct cm_t *) (vaddr + CMDBUF); - head = readw(&(cm_addr->cm_head)); - - /* - * Forget it if pointers out of range. - */ - if (head >= (CMDMAX - CMDSTART) || (head & 03)) { - DPR_CORE(("%s:%d pointers out of range, failing board!\n", __FILE__, __LINE__)); - ch->ch_bd->state = BOARD_FAILED; - return; - } - - /* - * Put the data in the circular command buffer. - */ - writeb(cmd, (char *) (vaddr + head + CMDSTART + 0)); - writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1)); - writeb(byte1, (char *) (vaddr + head + CMDSTART + 2)); - writeb(byte2, (char *) (vaddr + head + CMDSTART + 3)); - - head = (head + 4) & (CMDMAX - CMDSTART - 4); - - writew(head, &(cm_addr->cm_head)); - - /* - * Wait if necessary before updating the head - * pointer to limit the number of outstanding - * commands to the FEP. If the time spent waiting - * is outlandish, declare the FEP dead. - */ - for (count = dgap_count ;;) { - - head = readw(&(cm_addr->cm_head)); - tail = readw(&(cm_addr->cm_tail)); - - n = (head - tail) & (CMDMAX - CMDSTART - 4); - - if (n <= ncmds * sizeof(struct cm_t)) - break; - - if (--count == 0) { - DPR_CORE(("%s:%d failing board.\n",__FILE__, __LINE__)); - ch->ch_bd->state = BOARD_FAILED; - return; - } - udelay(10); - } -} - - -/*======================================================================= - * - * dgap_cmdw - Sends a 1 word command to the FEP. - * - * ch - Pointer to channel structure. - * cmd - Command to be sent. - * word - Integer containing word to be sent. - * ncmds - Wait until ncmds or fewer cmds are left - * in the cmd buffer before returning. - * - *=======================================================================*/ -void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds) -{ - char *vaddr = NULL; - struct cm_t *cm_addr = NULL; - uint count; - uint n; - u16 head; - u16 tail; - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - /* - * Check if board is still alive. - */ - if (ch->ch_bd->state == BOARD_FAILED) { - DPR_CORE(("%s:%d board is failed!\n", __FILE__, __LINE__)); - return; - } - - /* - * Make sure the pointers are in range before - * writing to the FEP memory. - */ - vaddr = ch->ch_bd->re_map_membase; - if (!vaddr) - return; - - cm_addr = (struct cm_t *) (vaddr + CMDBUF); - head = readw(&(cm_addr->cm_head)); - - /* - * Forget it if pointers out of range. - */ - if (head >= (CMDMAX - CMDSTART) || (head & 03)) { - DPR_CORE(("%s:%d Pointers out of range. Failing board.\n",__FILE__, __LINE__)); - ch->ch_bd->state = BOARD_FAILED; - return; - } - - /* - * Put the data in the circular command buffer. - */ - writeb(cmd, (char *) (vaddr + head + CMDSTART + 0)); - writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1)); - writew((u16) word, (char *) (vaddr + head + CMDSTART + 2)); - - head = (head + 4) & (CMDMAX - CMDSTART - 4); - - writew(head, &(cm_addr->cm_head)); - - /* - * Wait if necessary before updating the head - * pointer to limit the number of outstanding - * commands to the FEP. If the time spent waiting - * is outlandish, declare the FEP dead. - */ - for (count = dgap_count ;;) { - - head = readw(&(cm_addr->cm_head)); - tail = readw(&(cm_addr->cm_tail)); - - n = (head - tail) & (CMDMAX - CMDSTART - 4); - - if (n <= ncmds * sizeof(struct cm_t)) - break; - - if (--count == 0) { - DPR_CORE(("%s:%d Failing board.\n",__FILE__, __LINE__)); - ch->ch_bd->state = BOARD_FAILED; - return; - } - udelay(10); - } -} - - - -/*======================================================================= - * - * dgap_cmdw_ext - Sends a extended word command to the FEP. - * - * ch - Pointer to channel structure. - * cmd - Command to be sent. - * word - Integer containing word to be sent. - * ncmds - Wait until ncmds or fewer cmds are left - * in the cmd buffer before returning. - * - *=======================================================================*/ -static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds) -{ - char *vaddr = NULL; - struct cm_t *cm_addr = NULL; - uint count; - uint n; - u16 head; - u16 tail; - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - /* - * Check if board is still alive. - */ - if (ch->ch_bd->state == BOARD_FAILED) { - DPR_CORE(("%s:%d board is failed!\n", __FILE__, __LINE__)); - return; - } - - /* - * Make sure the pointers are in range before - * writing to the FEP memory. - */ - vaddr = ch->ch_bd->re_map_membase; - if (!vaddr) - return; - - cm_addr = (struct cm_t *) (vaddr + CMDBUF); - head = readw(&(cm_addr->cm_head)); - - /* - * Forget it if pointers out of range. - */ - if (head >= (CMDMAX - CMDSTART) || (head & 03)) { - DPR_CORE(("%s:%d Pointers out of range. Failing board.\n",__FILE__, __LINE__)); - ch->ch_bd->state = BOARD_FAILED; - return; - } - - /* - * Put the data in the circular command buffer. - */ - - /* Write an FF to tell the FEP that we want an extended command */ - writeb((uchar) 0xff, (char *) (vaddr + head + CMDSTART + 0)); - - writeb((uchar) ch->ch_portnum, (uchar *) (vaddr + head + CMDSTART + 1)); - writew((u16) cmd, (char *) (vaddr + head + CMDSTART + 2)); - - /* - * If the second part of the command won't fit, - * put it at the beginning of the circular buffer. - */ - if (((head + 4) >= ((CMDMAX - CMDSTART)) || (head & 03))) { - writew((u16) word, (char *) (vaddr + CMDSTART)); - } else { - writew((u16) word, (char *) (vaddr + head + CMDSTART + 4)); - } - - head = (head + 8) & (CMDMAX - CMDSTART - 4); - - writew(head, &(cm_addr->cm_head)); - - /* - * Wait if necessary before updating the head - * pointer to limit the number of outstanding - * commands to the FEP. If the time spent waiting - * is outlandish, declare the FEP dead. - */ - for (count = dgap_count ;;) { - - head = readw(&(cm_addr->cm_head)); - tail = readw(&(cm_addr->cm_tail)); - - n = (head - tail) & (CMDMAX - CMDSTART - 4); - - if (n <= ncmds * sizeof(struct cm_t)) - break; - - if (--count == 0) { - DPR_CORE(("%s:%d Failing board.\n",__FILE__, __LINE__)); - ch->ch_bd->state = BOARD_FAILED; - return; - } - udelay(10); - } -} - - -/*======================================================================= - * - * dgap_wmove - Write data to FEP buffer. - * - * ch - Pointer to channel structure. - * buf - Poiter to characters to be moved. - * cnt - Number of characters to move. - * - *=======================================================================*/ -void dgap_wmove(struct channel_t *ch, char *buf, uint cnt) -{ - int n; - char *taddr; - struct bs_t *bs; - u16 head; - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - /* - * Check parameters. - */ - bs = ch->ch_bs; - head = readw(&(bs->tx_head)); - - /* - * If pointers are out of range, just return. - */ - if ((cnt > ch->ch_tsize) || (unsigned)(head - ch->ch_tstart) >= ch->ch_tsize) { - DPR_CORE(("%s:%d pointer out of range", __FILE__, __LINE__)); - return; - } - - /* - * If the write wraps over the top of the circular buffer, - * move the portion up to the wrap point, and reset the - * pointers to the bottom. - */ - n = ch->ch_tstart + ch->ch_tsize - head; - - if (cnt >= n) { - cnt -= n; - taddr = ch->ch_taddr + head; - memcpy_toio(taddr, buf, n); - head = ch->ch_tstart; - buf += n; - } - - /* - * Move rest of data. - */ - taddr = ch->ch_taddr + head; - n = cnt; - memcpy_toio(taddr, buf, n); - head += cnt; - - writew(head, &(bs->tx_head)); -} - -/* - * Retrives the current custom baud rate from FEP memory, - * and returns it back to the user. - * Returns 0 on error. - */ -uint dgap_get_custom_baud(struct channel_t *ch) -{ - uchar *vaddr; - ulong offset = 0; - uint value = 0; - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) { - return 0; - } - - if (!ch->ch_bd || ch->ch_bd->magic != DGAP_BOARD_MAGIC) { - return 0; - } - - if (!(ch->ch_bd->bd_flags & BD_FEP5PLUS)) - return 0; - - vaddr = ch->ch_bd->re_map_membase; - - if (!vaddr) - return 0; - - /* - * Go get from fep mem, what the fep - * believes the custom baud rate is. - */ - offset = ((((*(unsigned short *)(vaddr + ECS_SEG)) << 4) + - (ch->ch_portnum * 0x28) + LINE_SPEED)); - - value = readw(vaddr + offset); - return value; -} - - -/* - * Calls the firmware to reset this channel. - */ -void dgap_firmware_reset_port(struct channel_t *ch) -{ - dgap_cmdb(ch, CHRESET, 0, 0, 0); - - /* - * Now that the channel is reset, we need to make sure - * all the current settings get reapplied to the port - * in the firmware. - * - * So we will set the driver's cache of firmware - * settings all to 0, and then call param. - */ - ch->ch_fepiflag = 0; - ch->ch_fepcflag = 0; - ch->ch_fepoflag = 0; - ch->ch_fepstartc = 0; - ch->ch_fepstopc = 0; - ch->ch_fepastartc = 0; - ch->ch_fepastopc = 0; - ch->ch_mostat = 0; - ch->ch_hflow = 0; -} - - -/*======================================================================= - * - * dgap_param - Set Digi parameters. - * - * struct tty_struct * - TTY for port. - * - *=======================================================================*/ -int dgap_param(struct tty_struct *tty) -{ - struct ktermios *ts; - struct board_t *bd; - struct channel_t *ch; - struct bs_t *bs; - struct un_t *un; - u16 head; - u16 cflag; - u16 iflag; - uchar mval; - uchar hflow; - - if (!tty || tty->magic != TTY_MAGIC) - return -ENXIO; - - un = (struct un_t *) tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return -ENXIO; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return -ENXIO; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return -ENXIO; - - bs = ch->ch_bs; - if (!bs) - return -ENXIO; - - DPR_PARAM(("param start: tdev: %x cflags: %x oflags: %x iflags: %x\n", - ch->ch_tun.un_dev, ch->ch_c_cflag, ch->ch_c_oflag, ch->ch_c_iflag)); - - ts = &tty->termios; - - /* - * If baud rate is zero, flush queues, and set mval to drop DTR. - */ - if ((ch->ch_c_cflag & (CBAUD)) == 0) { - - /* flush rx */ - head = readw(&(ch->ch_bs->rx_head)); - writew(head, &(ch->ch_bs->rx_tail)); - - /* flush tx */ - head = readw(&(ch->ch_bs->tx_head)); - writew(head, &(ch->ch_bs->tx_tail)); - - ch->ch_flags |= (CH_BAUD0); - - /* Drop RTS and DTR */ - ch->ch_mval &= ~(D_RTS(ch)|D_DTR(ch)); - mval = D_DTR(ch) | D_RTS(ch); - ch->ch_baud_info = 0; - - } else if (ch->ch_custom_speed && (bd->bd_flags & BD_FEP5PLUS)) { - /* - * Tell the fep to do the command - */ - - DPR_PARAM(("param: Want %d speed\n", ch->ch_custom_speed)); - - dgap_cmdw_ext(ch, 0xff01, ch->ch_custom_speed, 0); - - /* - * Now go get from fep mem, what the fep - * believes the custom baud rate is. - */ - ch->ch_baud_info = ch->ch_custom_speed = dgap_get_custom_baud(ch); - - DPR_PARAM(("param: Got %d speed\n", ch->ch_custom_speed)); - - /* Handle transition from B0 */ - if (ch->ch_flags & CH_BAUD0) { - ch->ch_flags &= ~(CH_BAUD0); - ch->ch_mval |= (D_RTS(ch)|D_DTR(ch)); - } - mval = D_DTR(ch) | D_RTS(ch); - - } else { - /* - * Set baud rate, character size, and parity. - */ - - - int iindex = 0; - int jindex = 0; - int baud = 0; - - ulong bauds[4][16] = { - { /* slowbaud */ - 0, 50, 75, 110, - 134, 150, 200, 300, - 600, 1200, 1800, 2400, - 4800, 9600, 19200, 38400 }, - { /* slowbaud & CBAUDEX */ - 0, 57600, 115200, 230400, - 460800, 150, 200, 921600, - 600, 1200, 1800, 2400, - 4800, 9600, 19200, 38400 }, - { /* fastbaud */ - 0, 57600, 76800, 115200, - 14400, 57600, 230400, 76800, - 115200, 230400, 28800, 460800, - 921600, 9600, 19200, 38400 }, - { /* fastbaud & CBAUDEX */ - 0, 57600, 115200, 230400, - 460800, 150, 200, 921600, - 600, 1200, 1800, 2400, - 4800, 9600, 19200, 38400 } - }; - - /* Only use the TXPrint baud rate if the terminal unit is NOT open */ - if (!(ch->ch_tun.un_flags & UN_ISOPEN) && (un->un_type == DGAP_PRINT)) - baud = C_BAUD(ch->ch_pun.un_tty) & 0xff; - else - baud = C_BAUD(ch->ch_tun.un_tty) & 0xff; - - if (ch->ch_c_cflag & CBAUDEX) - iindex = 1; - - if (ch->ch_digi.digi_flags & DIGI_FAST) - iindex += 2; - - jindex = baud; - - if ((iindex >= 0) && (iindex < 4) && (jindex >= 0) && (jindex < 16)) { - baud = bauds[iindex][jindex]; - } else { - DPR_IOCTL(("baud indices were out of range (%d)(%d)", - iindex, jindex)); - baud = 0; - } - - if (baud == 0) - baud = 9600; - - ch->ch_baud_info = baud; - - - /* - * CBAUD has bit position 0x1000 set these days to indicate Linux - * baud rate remap. - * We use a different bit assignment for high speed. Clear this - * bit out while grabbing the parts of "cflag" we want. - */ - cflag = ch->ch_c_cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE); - - /* - * HUPCL bit is used by FEP to indicate fast baud - * table is to be used. - */ - if ((ch->ch_digi.digi_flags & DIGI_FAST) || (ch->ch_c_cflag & CBAUDEX)) - cflag |= HUPCL; - - - if ((ch->ch_c_cflag & CBAUDEX) && !(ch->ch_digi.digi_flags & DIGI_FAST)) { - /* - * The below code is trying to guarantee that only baud rates - * 115200, 230400, 460800, 921600 are remapped. We use exclusive or - * because the various baud rates share common bit positions - * and therefore can't be tested for easily. - */ - tcflag_t tcflag = (ch->ch_c_cflag & CBAUD) | CBAUDEX; - int baudpart = 0; - - /* Map high speed requests to index into FEP's baud table */ - switch (tcflag) { - case B57600 : - baudpart = 1; - break; -#ifdef B76800 - case B76800 : - baudpart = 2; - break; -#endif - case B115200 : - baudpart = 3; - break; - case B230400 : - baudpart = 9; - break; - case B460800 : - baudpart = 11; - break; -#ifdef B921600 - case B921600 : - baudpart = 12; - break; -#endif - default: - baudpart = 0; - } - - if (baudpart) - cflag = (cflag & ~(CBAUD | CBAUDEX)) | baudpart; - } - - cflag &= 0xffff; - - if (cflag != ch->ch_fepcflag) { - ch->ch_fepcflag = (u16) (cflag & 0xffff); - - /* Okay to have channel and board locks held calling this */ - dgap_cmdw(ch, SCFLAG, (u16) cflag, 0); - } - - /* Handle transition from B0 */ - if (ch->ch_flags & CH_BAUD0) { - ch->ch_flags &= ~(CH_BAUD0); - ch->ch_mval |= (D_RTS(ch)|D_DTR(ch)); - } - mval = D_DTR(ch) | D_RTS(ch); - } - - /* - * Get input flags. - */ - iflag = ch->ch_c_iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | IXON | IXANY | IXOFF); - - if ((ch->ch_startc == _POSIX_VDISABLE) || (ch->ch_stopc == _POSIX_VDISABLE)) { - iflag &= ~(IXON | IXOFF); - ch->ch_c_iflag &= ~(IXON | IXOFF); - } - - /* - * Only the IBM Xr card can switch between - * 232 and 422 modes on the fly - */ - if (bd->device == PCI_DEVICE_XR_IBM_DID) { - if (ch->ch_digi.digi_flags & DIGI_422) - dgap_cmdb(ch, SCOMMODE, MODE_422, 0, 0); - else - dgap_cmdb(ch, SCOMMODE, MODE_232, 0, 0); - } - - if (ch->ch_digi.digi_flags & DIGI_ALTPIN) - iflag |= IALTPIN ; - - if (iflag != ch->ch_fepiflag) { - ch->ch_fepiflag = iflag; - - /* Okay to have channel and board locks held calling this */ - dgap_cmdw(ch, SIFLAG, (u16) ch->ch_fepiflag, 0); - } - - /* - * Select hardware handshaking. - */ - hflow = 0; - - if (ch->ch_c_cflag & CRTSCTS) { - hflow |= (D_RTS(ch) | D_CTS(ch)); - } - if (ch->ch_digi.digi_flags & RTSPACE) - hflow |= D_RTS(ch); - if (ch->ch_digi.digi_flags & DTRPACE) - hflow |= D_DTR(ch); - if (ch->ch_digi.digi_flags & CTSPACE) - hflow |= D_CTS(ch); - if (ch->ch_digi.digi_flags & DSRPACE) - hflow |= D_DSR(ch); - if (ch->ch_digi.digi_flags & DCDPACE) - hflow |= D_CD(ch); - - if (hflow != ch->ch_hflow) { - ch->ch_hflow = hflow; - - /* Okay to have channel and board locks held calling this */ - dgap_cmdb(ch, SHFLOW, (uchar) hflow, 0xff, 0); - } - - - /* - * Set RTS and/or DTR Toggle if needed, but only if product is FEP5+ based. - */ - if (bd->bd_flags & BD_FEP5PLUS) { - u16 hflow2 = 0; - if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) { - hflow2 |= (D_RTS(ch)); - } - if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) { - hflow2 |= (D_DTR(ch)); - } - - dgap_cmdw_ext(ch, 0xff03, hflow2, 0); - } - - /* - * Set modem control lines. - */ - - mval ^= ch->ch_mforce & (mval ^ ch->ch_mval); - - DPR_PARAM(("dgap_param: mval: %x ch_mforce: %x ch_mval: %x ch_mostat: %x\n", - mval, ch->ch_mforce, ch->ch_mval, ch->ch_mostat)); - - if (ch->ch_mostat ^ mval) { - ch->ch_mostat = mval; - - /* Okay to have channel and board locks held calling this */ - DPR_PARAM(("dgap_param: Sending SMODEM mval: %x\n", mval)); - dgap_cmdb(ch, SMODEM, (uchar) mval, D_RTS(ch)|D_DTR(ch), 0); - } - - /* - * Read modem signals, and then call carrier function. - */ - ch->ch_mistat = readb(&(bs->m_stat)); - dgap_carrier(ch); - - /* - * Set the start and stop characters. - */ - if (ch->ch_startc != ch->ch_fepstartc || ch->ch_stopc != ch->ch_fepstopc) { - ch->ch_fepstartc = ch->ch_startc; - ch->ch_fepstopc = ch->ch_stopc; - - /* Okay to have channel and board locks held calling this */ - dgap_cmdb(ch, SFLOWC, ch->ch_fepstartc, ch->ch_fepstopc, 0); - } - - /* - * Set the Auxiliary start and stop characters. - */ - if (ch->ch_astartc != ch->ch_fepastartc || ch->ch_astopc != ch->ch_fepastopc) { - ch->ch_fepastartc = ch->ch_astartc; - ch->ch_fepastopc = ch->ch_astopc; - - /* Okay to have channel and board locks held calling this */ - dgap_cmdb(ch, SAFLOWC, ch->ch_fepastartc, ch->ch_fepastopc, 0); - } - - DPR_PARAM(("param finish\n")); - - return 0; -} - - -/* - * dgap_parity_scan() - * - * Convert the FEP5 way of reporting parity errors and breaks into - * the Linux line discipline way. - */ -void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf, unsigned char *fbuf, int *len) -{ - int l = *len; - int count = 0; - unsigned char *in, *cout, *fout; - unsigned char c; - - in = cbuf; - cout = cbuf; - fout = fbuf; - - DPR_PSCAN(("dgap_parity_scan start\n")); - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - while (l--) { - c = *in++; - switch (ch->pscan_state) { - default: - /* reset to sanity and fall through */ - ch->pscan_state = 0; - - case 0: - /* No FF seen yet */ - if (c == (unsigned char) '\377') { - /* delete this character from stream */ - ch->pscan_state = 1; - } else { - *cout++ = c; - *fout++ = TTY_NORMAL; - count += 1; - } - break; - - case 1: - /* first FF seen */ - if (c == (unsigned char) '\377') { - /* doubled ff, transform to single ff */ - *cout++ = c; - *fout++ = TTY_NORMAL; - count += 1; - ch->pscan_state = 0; - } else { - /* save value examination in next state */ - ch->pscan_savechar = c; - ch->pscan_state = 2; - } - break; - - case 2: - /* third character of ff sequence */ - - *cout++ = c; - - if (ch->pscan_savechar == 0x0) { - - if (c == 0x0) { - DPR_PSCAN(("dgap_parity_scan in 3rd char of ff seq. c: %x setting break.\n", c)); - ch->ch_err_break++; - *fout++ = TTY_BREAK; - } - else { - DPR_PSCAN(("dgap_parity_scan in 3rd char of ff seq. c: %x setting parity.\n", c)); - ch->ch_err_parity++; - *fout++ = TTY_PARITY; - } - } - else { - DPR_PSCAN(("%s:%d Logic Error.\n", __FILE__, __LINE__)); - } - - count += 1; - ch->pscan_state = 0; - } - } - *len = count; - DPR_PSCAN(("dgap_parity_scan finish\n")); -} - - - - -/*======================================================================= - * - * dgap_event - FEP to host event processing routine. - * - * bd - Board of current event. - * - *=======================================================================*/ -static int dgap_event(struct board_t *bd) -{ - struct channel_t *ch; - ulong lock_flags; - ulong lock_flags2; - struct bs_t *bs; - uchar *event; - uchar *vaddr = NULL; - struct ev_t *eaddr = NULL; - uint head; - uint tail; - int port; - int reason; - int modem; - int b1; - - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return -ENXIO; - - DGAP_LOCK(bd->bd_lock, lock_flags); - - vaddr = bd->re_map_membase; - - if (!vaddr) { - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return -ENXIO; - } - - eaddr = (struct ev_t *) (vaddr + EVBUF); - - /* Get our head and tail */ - head = readw(&(eaddr->ev_head)); - tail = readw(&(eaddr->ev_tail)); - - /* - * Forget it if pointers out of range. - */ - - if (head >= EVMAX - EVSTART || tail >= EVMAX - EVSTART || - (head | tail) & 03) { - DPR_EVENT(("should be calling xxfail %d\n", __LINE__)); - /* Let go of board lock */ - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return -ENXIO; - } - - /* - * Loop to process all the events in the buffer. - */ - while (tail != head) { - - /* - * Get interrupt information. - */ - - event = bd->re_map_membase + tail + EVSTART; - - port = event[0]; - reason = event[1]; - modem = event[2]; - b1 = event[3]; - - DPR_EVENT(("event: jiffies: %ld port: %d reason: %x modem: %x\n", - jiffies, port, reason, modem)); - - /* - * Make sure the interrupt is valid. - */ - if (port >= bd->nasync) - goto next; - - if (!(reason & (IFMODEM | IFBREAK | IFTLW | IFTEM | IFDATA))) { - goto next; - } - - ch = bd->channels[port]; - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) { - goto next; - } - - /* - * If we have made it here, the event was valid. - * Lock down the channel. - */ - DGAP_LOCK(ch->ch_lock, lock_flags2); - - bs = ch->ch_bs; - - if (!bs) { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - goto next; - } - - /* - * Process received data. - */ - if (reason & IFDATA) { - - /* - * ALL LOCKS *MUST* BE DROPPED BEFORE CALLING INPUT! - * input could send some data to ld, which in turn - * could do a callback to one of our other functions. - */ - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - dgap_input(ch); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - if (ch->ch_flags & CH_RACTIVE) - ch->ch_flags |= CH_RENABLE; - else - writeb(1, &(bs->idata)); - - if (ch->ch_flags & CH_RWAIT) { - ch->ch_flags &= ~CH_RWAIT; - - wake_up_interruptible(&ch->ch_tun.un_flags_wait); - } - } - - /* - * Process Modem change signals. - */ - if (reason & IFMODEM) { - ch->ch_mistat = modem; - dgap_carrier(ch); - } - - /* - * Process break. - */ - if (reason & IFBREAK) { - - DPR_EVENT(("got IFBREAK\n")); - - if (ch->ch_tun.un_tty) { - /* A break has been indicated */ - ch->ch_err_break++; - tty_buffer_request_room(ch->ch_tun.un_tty->port, 1); - tty_insert_flip_char(ch->ch_tun.un_tty->port, 0, TTY_BREAK); - tty_flip_buffer_push(ch->ch_tun.un_tty->port); - } - } - - /* - * Process Transmit low. - */ - if (reason & IFTLW) { - - DPR_EVENT(("event: got low event\n")); - - if (ch->ch_tun.un_flags & UN_LOW) { - ch->ch_tun.un_flags &= ~UN_LOW; - - if (ch->ch_tun.un_flags & UN_ISOPEN) { - if ((ch->ch_tun.un_tty->flags & - (1 << TTY_DO_WRITE_WAKEUP)) && -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) - ch->ch_tun.un_tty->ldisc->ops->write_wakeup) -#else - ch->ch_tun.un_tty->ldisc.ops->write_wakeup) -#endif - { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) - (ch->ch_tun.un_tty->ldisc->ops->write_wakeup)(ch->ch_tun.un_tty); -#else - (ch->ch_tun.un_tty->ldisc.ops->write_wakeup)(ch->ch_tun.un_tty); -#endif - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - } - wake_up_interruptible(&ch->ch_tun.un_tty->write_wait); - wake_up_interruptible(&ch->ch_tun.un_flags_wait); - - DPR_EVENT(("event: Got low event. jiffies: %lu\n", jiffies)); - } - } - - if (ch->ch_pun.un_flags & UN_LOW) { - ch->ch_pun.un_flags &= ~UN_LOW; - if (ch->ch_pun.un_flags & UN_ISOPEN) { - if ((ch->ch_pun.un_tty->flags & - (1 << TTY_DO_WRITE_WAKEUP)) && -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) - ch->ch_pun.un_tty->ldisc->ops->write_wakeup) -#else - ch->ch_pun.un_tty->ldisc.ops->write_wakeup) -#endif - { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) - (ch->ch_pun.un_tty->ldisc->ops->write_wakeup)(ch->ch_pun.un_tty); -#else - (ch->ch_pun.un_tty->ldisc.ops->write_wakeup)(ch->ch_pun.un_tty); -#endif - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - } - wake_up_interruptible(&ch->ch_pun.un_tty->write_wait); - wake_up_interruptible(&ch->ch_pun.un_flags_wait); - } - } - - if (ch->ch_flags & CH_WLOW) { - ch->ch_flags &= ~CH_WLOW; - wake_up_interruptible(&ch->ch_flags_wait); - } - } - - /* - * Process Transmit empty. - */ - if (reason & IFTEM) { - DPR_EVENT(("event: got empty event\n")); - - if (ch->ch_tun.un_flags & UN_EMPTY) { - ch->ch_tun.un_flags &= ~UN_EMPTY; - if (ch->ch_tun.un_flags & UN_ISOPEN) { - if ((ch->ch_tun.un_tty->flags & - (1 << TTY_DO_WRITE_WAKEUP)) && -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) - ch->ch_tun.un_tty->ldisc->ops->write_wakeup) -#else - ch->ch_tun.un_tty->ldisc.ops->write_wakeup) -#endif - { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) - (ch->ch_tun.un_tty->ldisc->ops->write_wakeup)(ch->ch_tun.un_tty); -#else - (ch->ch_tun.un_tty->ldisc.ops->write_wakeup)(ch->ch_tun.un_tty); -#endif - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - } - wake_up_interruptible(&ch->ch_tun.un_tty->write_wait); - wake_up_interruptible(&ch->ch_tun.un_flags_wait); - } - } - - if (ch->ch_pun.un_flags & UN_EMPTY) { - ch->ch_pun.un_flags &= ~UN_EMPTY; - if (ch->ch_pun.un_flags & UN_ISOPEN) { - if ((ch->ch_pun.un_tty->flags & - (1 << TTY_DO_WRITE_WAKEUP)) && -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) - ch->ch_pun.un_tty->ldisc->ops->write_wakeup) -#else - ch->ch_pun.un_tty->ldisc.ops->write_wakeup) -#endif - { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) - (ch->ch_pun.un_tty->ldisc->ops->write_wakeup)(ch->ch_pun.un_tty); -#else - (ch->ch_pun.un_tty->ldisc.ops->write_wakeup)(ch->ch_pun.un_tty); -#endif - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - } - wake_up_interruptible(&ch->ch_pun.un_tty->write_wait); - wake_up_interruptible(&ch->ch_pun.un_flags_wait); - } - } - - - if (ch->ch_flags & CH_WEMPTY) { - ch->ch_flags &= ~CH_WEMPTY; - wake_up_interruptible(&ch->ch_flags_wait); - } - } - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - -next: - tail = (tail + 4) & (EVMAX - EVSTART - 4); - } - - writew(tail, &(eaddr->ev_tail)); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - return 0; -} diff --git a/drivers/staging/dgap/dgap_fep5.h b/drivers/staging/dgap/dgap_fep5.h deleted file mode 100644 index c9abc406a1e0..000000000000 --- a/drivers/staging/dgap/dgap_fep5.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - * - ************************************************************************ - *** FEP Version 5 dependent definitions - ************************************************************************/ - -#ifndef __DGAP_FEP5_H -#define __DGAP_FEP5_H - -/************************************************************************ - * FEP memory offsets - ************************************************************************/ -#define START 0x0004L /* Execution start address */ - -#define CMDBUF 0x0d10L /* Command (cm_t) structure offset */ -#define CMDSTART 0x0400L /* Start of command buffer */ -#define CMDMAX 0x0800L /* End of command buffer */ - -#define EVBUF 0x0d18L /* Event (ev_t) structure */ -#define EVSTART 0x0800L /* Start of event buffer */ -#define EVMAX 0x0c00L /* End of event buffer */ -#define FEP5_PLUS 0x0E40 /* ASCII '5' and ASCII 'A' is here */ -#define ECS_SEG 0x0E44 /* Segment of the extended channel structure */ -#define LINE_SPEED 0x10 /* Offset into ECS_SEG for line speed */ - /* if the fep has extended capabilities */ - -/* BIOS MAGIC SPOTS */ -#define ERROR 0x0C14L /* BIOS error code */ -#define SEQUENCE 0x0C12L /* BIOS sequence indicator */ -#define POSTAREA 0x0C00L /* POST complete message area */ - -/* FEP MAGIC SPOTS */ -#define FEPSTAT POSTAREA /* OS here when FEP comes up */ -#define NCHAN 0x0C02L /* number of ports FEP sees */ -#define PANIC 0x0C10L /* PANIC area for FEP */ -#define KMEMEM 0x0C30L /* Memory for KME use */ -#define CONFIG 0x0CD0L /* Concentrator configuration info */ -#define CONFIGSIZE 0x0030 /* configuration info size */ -#define DOWNREQ 0x0D00 /* Download request buffer pointer */ - -#define CHANBUF 0x1000L /* Async channel (bs_t) structs */ -#define FEPOSSIZE 0x1FFF /* 8K FEPOS */ - -#define XEMPORTS 0xC02 /* - * Offset in board memory where FEP5 stores - * how many ports it has detected. - * NOTE: FEP5 reports 64 ports when the user - * has the cable in EBI OUT instead of EBI IN. - */ - -#define FEPCLR 0x00 -#define FEPMEM 0x02 -#define FEPRST 0x04 -#define FEPINT 0x08 -#define FEPMASK 0x0e -#define FEPWIN 0x80 - -#define LOWMEM 0x0100 -#define HIGHMEM 0x7f00 - -#define FEPTIMEOUT 200000 - -#define ENABLE_INTR 0x0e04 /* Enable interrupts flag */ -#define FEPPOLL_MIN 1 /* minimum of 1 millisecond */ -#define FEPPOLL_MAX 20 /* maximum of 20 milliseconds */ -#define FEPPOLL 0x0c26 /* Fep event poll interval */ - -#define IALTPIN 0x0080 /* Input flag to swap DSR <-> DCD */ - -/************************************************************************ - * Command structure definition. - ************************************************************************/ -struct cm_t { - volatile unsigned short cm_head; /* Command buffer head offset */ - volatile unsigned short cm_tail; /* Command buffer tail offset */ - volatile unsigned short cm_start; /* start offset of buffer */ - volatile unsigned short cm_max; /* last offset of buffer */ -}; - -/************************************************************************ - * Event structure definition. - ************************************************************************/ -struct ev_t { - volatile unsigned short ev_head; /* Command buffer head offset */ - volatile unsigned short ev_tail; /* Command buffer tail offset */ - volatile unsigned short ev_start; /* start offset of buffer */ - volatile unsigned short ev_max; /* last offset of buffer */ -}; - -/************************************************************************ - * Download buffer structure. - ************************************************************************/ -struct downld_t { - uchar dl_type; /* Header */ - uchar dl_seq; /* Download sequence */ - ushort dl_srev; /* Software revision number */ - ushort dl_lrev; /* Low revision number */ - ushort dl_hrev; /* High revision number */ - ushort dl_seg; /* Start segment address */ - ushort dl_size; /* Number of bytes to download */ - uchar dl_data[1024]; /* Download data */ -}; - -/************************************************************************ - * Per channel buffer structure - ************************************************************************ - * Base Structure Entries Usage Meanings to Host * - * * - * W = read write R = read only * - * C = changed by commands only * - * U = unknown (may be changed w/o notice) * - ************************************************************************/ -struct bs_t { - volatile unsigned short tp_jmp; /* Transmit poll jump */ - volatile unsigned short tc_jmp; /* Cooked procedure jump */ - volatile unsigned short ri_jmp; /* Not currently used */ - volatile unsigned short rp_jmp; /* Receive poll jump */ - - volatile unsigned short tx_seg; /* W Tx segment */ - volatile unsigned short tx_head; /* W Tx buffer head offset */ - volatile unsigned short tx_tail; /* R Tx buffer tail offset */ - volatile unsigned short tx_max; /* W Tx buffer size - 1 */ - - volatile unsigned short rx_seg; /* W Rx segment */ - volatile unsigned short rx_head; /* W Rx buffer head offset */ - volatile unsigned short rx_tail; /* R Rx buffer tail offset */ - volatile unsigned short rx_max; /* W Rx buffer size - 1 */ - - volatile unsigned short tx_lw; /* W Tx buffer low water mark */ - volatile unsigned short rx_lw; /* W Rx buffer low water mark */ - volatile unsigned short rx_hw; /* W Rx buffer high water mark */ - volatile unsigned short incr; /* W Increment to next channel */ - - volatile unsigned short fepdev; /* U SCC device base address */ - volatile unsigned short edelay; /* W Exception delay */ - volatile unsigned short blen; /* W Break length */ - volatile unsigned short btime; /* U Break complete time */ - - volatile unsigned short iflag; /* C UNIX input flags */ - volatile unsigned short oflag; /* C UNIX output flags */ - volatile unsigned short cflag; /* C UNIX control flags */ - volatile unsigned short wfill[13]; /* U Reserved for expansion */ - - volatile unsigned char num; /* U Channel number */ - volatile unsigned char ract; /* U Receiver active counter */ - volatile unsigned char bstat; /* U Break status bits */ - volatile unsigned char tbusy; /* W Transmit busy */ - volatile unsigned char iempty; /* W Transmit empty event enable */ - volatile unsigned char ilow; /* W Transmit low-water event enable */ - volatile unsigned char idata; /* W Receive data interrupt enable */ - volatile unsigned char eflag; /* U Host event flags */ - - volatile unsigned char tflag; /* U Transmit flags */ - volatile unsigned char rflag; /* U Receive flags */ - volatile unsigned char xmask; /* U Transmit ready flags */ - volatile unsigned char xval; /* U Transmit ready value */ - volatile unsigned char m_stat; /* RC Modem status bits */ - volatile unsigned char m_change; /* U Modem bits which changed */ - volatile unsigned char m_int; /* W Modem interrupt enable bits */ - volatile unsigned char m_last; /* U Last modem status */ - - volatile unsigned char mtran; /* C Unreported modem trans */ - volatile unsigned char orun; /* C Buffer overrun occurred */ - volatile unsigned char astartc; /* W Auxiliary Xon char */ - volatile unsigned char astopc; /* W Auxiliary Xoff char */ - volatile unsigned char startc; /* W Xon character */ - volatile unsigned char stopc; /* W Xoff character */ - volatile unsigned char vnextc; /* W Vnext character */ - volatile unsigned char hflow; /* C Software flow control */ - - volatile unsigned char fillc; /* U Delay Fill character */ - volatile unsigned char ochar; /* U Saved output character */ - volatile unsigned char omask; /* U Output character mask */ - - volatile unsigned char bfill[13]; /* U Reserved for expansion */ - - volatile unsigned char scc[16]; /* U SCC registers */ -}; - - -/************************************************************************ - * FEP supported functions - ************************************************************************/ -#define SRLOW 0xe0 /* Set receive low water */ -#define SRHIGH 0xe1 /* Set receive high water */ -#define FLUSHTX 0xe2 /* Flush transmit buffer */ -#define PAUSETX 0xe3 /* Pause data transmission */ -#define RESUMETX 0xe4 /* Resume data transmission */ -#define SMINT 0xe5 /* Set Modem Interrupt */ -#define SAFLOWC 0xe6 /* Set Aux. flow control chars */ -#define SBREAK 0xe8 /* Send break */ -#define SMODEM 0xe9 /* Set 8530 modem control lines */ -#define SIFLAG 0xea /* Set UNIX iflags */ -#define SFLOWC 0xeb /* Set flow control characters */ -#define STLOW 0xec /* Set transmit low water mark */ -#define RPAUSE 0xee /* Pause receive */ -#define RRESUME 0xef /* Resume receive */ -#define CHRESET 0xf0 /* Reset Channel */ -#define BUFSETALL 0xf2 /* Set Tx & Rx buffer size avail*/ -#define SOFLAG 0xf3 /* Set UNIX oflags */ -#define SHFLOW 0xf4 /* Set hardware handshake */ -#define SCFLAG 0xf5 /* Set UNIX cflags */ -#define SVNEXT 0xf6 /* Set VNEXT character */ -#define SPINTFC 0xfc /* Reserved */ -#define SCOMMODE 0xfd /* Set RS232/422 mode */ - - -/************************************************************************ - * Modes for SCOMMODE - ************************************************************************/ -#define MODE_232 0x00 -#define MODE_422 0x01 - - -/************************************************************************ - * Event flags. - ************************************************************************/ -#define IFBREAK 0x01 /* Break received */ -#define IFTLW 0x02 /* Transmit low water */ -#define IFTEM 0x04 /* Transmitter empty */ -#define IFDATA 0x08 /* Receive data present */ -#define IFMODEM 0x20 /* Modem status change */ - -/************************************************************************ - * Modem flags - ************************************************************************/ -# define DM_RTS 0x02 /* Request to send */ -# define DM_CD 0x80 /* Carrier detect */ -# define DM_DSR 0x20 /* Data set ready */ -# define DM_CTS 0x10 /* Clear to send */ -# define DM_RI 0x40 /* Ring indicator */ -# define DM_DTR 0x01 /* Data terminal ready */ - - -#endif diff --git a/drivers/staging/dgap/dgap_kcompat.h b/drivers/staging/dgap/dgap_kcompat.h deleted file mode 100644 index 0dc2404922ff..000000000000 --- a/drivers/staging/dgap/dgap_kcompat.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2004 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - * - ************************************************************************* - * - * This file is intended to contain all the kernel "differences" between the - * various kernels that we support. - * - *************************************************************************/ - -#ifndef __DGAP_KCOMPAT_H -#define __DGAP_KCOMPAT_H - -#if !defined(TTY_FLIPBUF_SIZE) -# define TTY_FLIPBUF_SIZE 512 -#endif - - -/* Sparse stuff */ -# ifndef __user -# define __user -# define __kernel -# define __safe -# define __force -# define __chk_user_ptr(x) (void)0 -# endif - - -# define PARM_STR(VAR, INIT, PERM, DESC) \ - static char *VAR = INIT; \ - char *dgap_##VAR; \ - module_param(VAR, charp, PERM); \ - MODULE_PARM_DESC(VAR, DESC); - -# define PARM_INT(VAR, INIT, PERM, DESC) \ - static int VAR = INIT; \ - int dgap_##VAR; \ - module_param(VAR, int, PERM); \ - MODULE_PARM_DESC(VAR, DESC); - -# define PARM_ULONG(VAR, INIT, PERM, DESC) \ - static ulong VAR = INIT; \ - ulong dgap_##VAR; \ - module_param(VAR, long, PERM); \ - MODULE_PARM_DESC(VAR, DESC); - -#endif /* ! __DGAP_KCOMPAT_H */ diff --git a/drivers/staging/dgap/dgap_parse.c b/drivers/staging/dgap/dgap_parse.c deleted file mode 100644 index 36fd93d3f5f6..000000000000 --- a/drivers/staging/dgap/dgap_parse.c +++ /dev/null @@ -1,1374 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! - * - * This is shared code between Digi's CVS archive and the - * Linux Kernel sources. - * Changing the source just for reformatting needlessly breaks - * our CVS diff history. - * - * Send any bug fixes/changes to: Eng.Linux at digi dot com. - * Thank you. - * - * - ***************************************************************************** - * - * dgap_parse.c - Parses the configuration information from the input file. - * - * $Id: dgap_parse.c,v 1.1 2009/10/23 14:01:57 markh Exp $ - * - */ -#include -#include -#include - -#include "dgap_types.h" -#include "dgap_fep5.h" -#include "dgap_driver.h" -#include "dgap_parse.h" -#include "dgap_conf.h" - - -/* - * Function prototypes. - */ -static int dgap_gettok(char **in, struct cnode *p); -static char *dgap_getword(char **in); -static char *dgap_savestring(char *s); -static struct cnode *dgap_newnode(int t); -static int dgap_checknode(struct cnode *p); -static void dgap_err(char *s); - -/* - * Our needed internal static variables... - */ -static struct cnode dgap_head; -#define MAXCWORD 200 -static char dgap_cword[MAXCWORD]; - -struct toklist { - int token; - char *string; -}; - -static struct toklist dgap_tlist[] = { - { BEGIN, "config_begin" }, - { END, "config_end" }, - { BOARD, "board" }, - { PCX, "Digi_AccelePort_C/X_PCI" }, /* C/X_PCI */ - { PEPC, "Digi_AccelePort_EPC/X_PCI" }, /* EPC/X_PCI */ - { PPCM, "Digi_AccelePort_Xem_PCI" }, /* PCI/Xem */ - { APORT2_920P, "Digi_AccelePort_2r_920_PCI" }, - { APORT4_920P, "Digi_AccelePort_4r_920_PCI" }, - { APORT8_920P, "Digi_AccelePort_8r_920_PCI" }, - { PAPORT4, "Digi_AccelePort_4r_PCI(EIA-232/RS-422)" }, - { PAPORT8, "Digi_AccelePort_8r_PCI(EIA-232/RS-422)" }, - { IO, "io" }, - { PCIINFO, "pciinfo" }, - { LINE, "line" }, - { CONC, "conc" }, - { CONC, "concentrator" }, - { CX, "cx" }, - { CX, "ccon" }, - { EPC, "epccon" }, - { EPC, "epc" }, - { MOD, "module" }, - { ID, "id" }, - { STARTO, "start" }, - { SPEED, "speed" }, - { CABLE, "cable" }, - { CONNECT, "connect" }, - { METHOD, "method" }, - { STATUS, "status" }, - { CUSTOM, "Custom" }, - { BASIC, "Basic" }, - { MEM, "mem" }, - { MEM, "memory" }, - { PORTS, "ports" }, - { MODEM, "modem" }, - { NPORTS, "nports" }, - { TTYN, "ttyname" }, - { CU, "cuname" }, - { PRINT, "prname" }, - { CMAJOR, "major" }, - { ALTPIN, "altpin" }, - { USEINTR, "useintr" }, - { TTSIZ, "ttysize" }, - { CHSIZ, "chsize" }, - { BSSIZ, "boardsize" }, - { UNTSIZ, "schedsize" }, - { F2SIZ, "f2200size" }, - { VPSIZ, "vpixsize" }, - { 0, NULL } -}; - - -/* - * Parse a configuration file read into memory as a string. - */ -int dgap_parsefile(char **in, int Remove) -{ - struct cnode *p, *brd, *line, *conc; - int rc; - char *s = NULL, *s2 = NULL; - int linecnt = 0; - - p = &dgap_head; - brd = line = conc = NULL; - - /* perhaps we are adding to an existing list? */ - while (p->next != NULL) { - p = p->next; - } - - /* file must start with a BEGIN */ - while ( (rc = dgap_gettok(in,p)) != BEGIN ) { - if (rc == 0) { - dgap_err("unexpected EOF"); - return(-1); - } - } - - for (; ; ) { - rc = dgap_gettok(in,p); - if (rc == 0) { - dgap_err("unexpected EOF"); - return(-1); - } - - switch (rc) { - case 0: - dgap_err("unexpected end of file"); - return(-1); - - case BEGIN: /* should only be 1 begin */ - dgap_err("unexpected config_begin\n"); - return(-1); - - case END: - return(0); - - case BOARD: /* board info */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(BNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - - p->u.board.status = dgap_savestring("No"); - line = conc = NULL; - brd = p; - linecnt = -1; - break; - - case APORT2_920P: /* AccelePort_4 */ - if (p->type != BNODE) { - dgap_err("unexpected Digi_2r_920 string"); - return(-1); - } - p->u.board.type = APORT2_920P; - p->u.board.v_type = 1; - DPR_INIT(("Adding Digi_2r_920 PCI to config...\n")); - break; - - case APORT4_920P: /* AccelePort_4 */ - if (p->type != BNODE) { - dgap_err("unexpected Digi_4r_920 string"); - return(-1); - } - p->u.board.type = APORT4_920P; - p->u.board.v_type = 1; - DPR_INIT(("Adding Digi_4r_920 PCI to config...\n")); - break; - - case APORT8_920P: /* AccelePort_8 */ - if (p->type != BNODE) { - dgap_err("unexpected Digi_8r_920 string"); - return(-1); - } - p->u.board.type = APORT8_920P; - p->u.board.v_type = 1; - DPR_INIT(("Adding Digi_8r_920 PCI to config...\n")); - break; - - case PAPORT4: /* AccelePort_4 PCI */ - if (p->type != BNODE) { - dgap_err("unexpected Digi_4r(PCI) string"); - return(-1); - } - p->u.board.type = PAPORT4; - p->u.board.v_type = 1; - DPR_INIT(("Adding Digi_4r PCI to config...\n")); - break; - - case PAPORT8: /* AccelePort_8 PCI */ - if (p->type != BNODE) { - dgap_err("unexpected Digi_8r string"); - return(-1); - } - p->u.board.type = PAPORT8; - p->u.board.v_type = 1; - DPR_INIT(("Adding Digi_8r PCI to config...\n")); - break; - - case PCX: /* PCI C/X */ - if (p->type != BNODE) { - dgap_err("unexpected Digi_C/X_(PCI) string"); - return(-1); - } - p->u.board.type = PCX; - p->u.board.v_type = 1; - p->u.board.conc1 = 0; - p->u.board.conc2 = 0; - p->u.board.module1 = 0; - p->u.board.module2 = 0; - DPR_INIT(("Adding PCI C/X to config...\n")); - break; - - case PEPC: /* PCI EPC/X */ - if (p->type != BNODE) { - dgap_err("unexpected \"Digi_EPC/X_(PCI)\" string"); - return(-1); - } - p->u.board.type = PEPC; - p->u.board.v_type = 1; - p->u.board.conc1 = 0; - p->u.board.conc2 = 0; - p->u.board.module1 = 0; - p->u.board.module2 = 0; - DPR_INIT(("Adding PCI EPC/X to config...\n")); - break; - - case PPCM: /* PCI/Xem */ - if (p->type != BNODE) { - dgap_err("unexpected PCI/Xem string"); - return(-1); - } - p->u.board.type = PPCM; - p->u.board.v_type = 1; - p->u.board.conc1 = 0; - p->u.board.conc2 = 0; - DPR_INIT(("Adding PCI XEM to config...\n")); - break; - - case IO: /* i/o port */ - if (p->type != BNODE) { - dgap_err("IO port only vaild for boards"); - return(-1); - } - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.board.portstr = dgap_savestring(s); - p->u.board.port = (short)simple_strtol(s, &s2, 0); - if ((short)strlen(s) > (short)(s2 - s)) { - dgap_err("bad number for IO port"); - return(-1); - } - p->u.board.v_port = 1; - DPR_INIT(("Adding IO (%s) to config...\n", s)); - break; - - case MEM: /* memory address */ - if (p->type != BNODE) { - dgap_err("memory address only vaild for boards"); - return(-1); - } - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.board.addrstr = dgap_savestring(s); - p->u.board.addr = simple_strtoul(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for memory address"); - return(-1); - } - p->u.board.v_addr = 1; - DPR_INIT(("Adding MEM (%s) to config...\n", s)); - break; - - case PCIINFO: /* pci information */ - if (p->type != BNODE) { - dgap_err("memory address only vaild for boards"); - return(-1); - } - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.board.pcibusstr = dgap_savestring(s); - p->u.board.pcibus = simple_strtoul(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for pci bus"); - return(-1); - } - p->u.board.v_pcibus = 1; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.board.pcislotstr = dgap_savestring(s); - p->u.board.pcislot = simple_strtoul(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for pci slot"); - return(-1); - } - p->u.board.v_pcislot = 1; - - DPR_INIT(("Adding PCIINFO (%s %s) to config...\n", p->u.board.pcibusstr, - p->u.board.pcislotstr)); - break; - - case METHOD: - if (p->type != BNODE) { - dgap_err("install method only vaild for boards"); - return(-1); - } - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.board.method = dgap_savestring(s); - p->u.board.v_method = 1; - DPR_INIT(("Adding METHOD (%s) to config...\n", s)); - break; - - case STATUS: - if (p->type != BNODE) { - dgap_err("config status only vaild for boards"); - return(-1); - } - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.board.status = dgap_savestring(s); - DPR_INIT(("Adding STATUS (%s) to config...\n", s)); - break; - - case NPORTS: /* number of ports */ - if (p->type == BNODE) { - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.board.nport = (char)simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for number of ports"); - return(-1); - } - p->u.board.v_nport = 1; - } else if (p->type == CNODE) { - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.conc.nport = (char)simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for number of ports"); - return(-1); - } - p->u.conc.v_nport = 1; - } else if (p->type == MNODE) { - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.module.nport = (char)simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for number of ports"); - return(-1); - } - p->u.module.v_nport = 1; - } else { - dgap_err("nports only valid for concentrators or modules"); - return(-1); - } - DPR_INIT(("Adding NPORTS (%s) to config...\n", s)); - break; - - case ID: /* letter ID used in tty name */ - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - - p->u.board.status = dgap_savestring(s); - - if (p->type == CNODE) { - p->u.conc.id = dgap_savestring(s); - p->u.conc.v_id = 1; - } else if (p->type == MNODE) { - p->u.module.id = dgap_savestring(s); - p->u.module.v_id = 1; - } else { - dgap_err("id only valid for concentrators or modules"); - return(-1); - } - DPR_INIT(("Adding ID (%s) to config...\n", s)); - break; - - case STARTO: /* start offset of ID */ - if (p->type == BNODE) { - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.board.start = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for start of tty count"); - return(-1); - } - p->u.board.v_start = 1; - } else if (p->type == CNODE) { - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.conc.start = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for start of tty count"); - return(-1); - } - p->u.conc.v_start = 1; - } else if (p->type == MNODE) { - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.module.start = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for start of tty count"); - return(-1); - } - p->u.module.v_start = 1; - } else { - dgap_err("start only valid for concentrators or modules"); - return(-1); - } - DPR_INIT(("Adding START (%s) to config...\n", s)); - break; - - case TTYN: /* tty name prefix */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(TNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - if ( (s = dgap_getword(in)) == NULL ) { - dgap_err("unexpeced end of file"); - return(-1); - } - if ( (p->u.ttyname = dgap_savestring(s)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - DPR_INIT(("Adding TTY (%s) to config...\n", s)); - break; - - case CU: /* cu name prefix */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(CUNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - if ( (s = dgap_getword(in)) == NULL ) { - dgap_err("unexpeced end of file"); - return(-1); - } - if ( (p->u.cuname = dgap_savestring(s)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - DPR_INIT(("Adding CU (%s) to config...\n", s)); - break; - - case LINE: /* line information */ - if (dgap_checknode(p)) - return(-1); - if (brd == NULL) { - dgap_err("must specify board before line info"); - return(-1); - } - switch (brd->u.board.type) { - case PPCM: - dgap_err("line not vaild for PC/em"); - return(-1); - } - if ( (p->next = dgap_newnode(LNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - conc = NULL; - line = p; - linecnt++; - DPR_INIT(("Adding LINE to config...\n")); - break; - - case CONC: /* concentrator information */ - if (dgap_checknode(p)) - return(-1); - if (line == NULL) { - dgap_err("must specify line info before concentrator"); - return(-1); - } - if ( (p->next = dgap_newnode(CNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - conc = p; - if (linecnt) - brd->u.board.conc2++; - else - brd->u.board.conc1++; - - DPR_INIT(("Adding CONC to config...\n")); - break; - - case CX: /* c/x type concentrator */ - if (p->type != CNODE) { - dgap_err("cx only valid for concentrators"); - return(-1); - } - p->u.conc.type = CX; - p->u.conc.v_type = 1; - DPR_INIT(("Adding CX to config...\n")); - break; - - case EPC: /* epc type concentrator */ - if (p->type != CNODE) { - dgap_err("cx only valid for concentrators"); - return(-1); - } - p->u.conc.type = EPC; - p->u.conc.v_type = 1; - DPR_INIT(("Adding EPC to config...\n")); - break; - - case MOD: /* EBI module */ - if (dgap_checknode(p)) - return(-1); - if (brd == NULL) { - dgap_err("must specify board info before EBI modules"); - return(-1); - } - switch (brd->u.board.type) { - case PPCM: - linecnt = 0; - break; - default: - if (conc == NULL) { - dgap_err("must specify concentrator info before EBI module"); - return(-1); - } - } - if ( (p->next = dgap_newnode(MNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - if (linecnt) - brd->u.board.module2++; - else - brd->u.board.module1++; - - DPR_INIT(("Adding MOD to config...\n")); - break; - - case PORTS: /* ports type EBI module */ - if (p->type != MNODE) { - dgap_err("ports only valid for EBI modules"); - return(-1); - } - p->u.module.type = PORTS; - p->u.module.v_type = 1; - DPR_INIT(("Adding PORTS to config...\n")); - break; - - case MODEM: /* ports type EBI module */ - if (p->type != MNODE) { - dgap_err("modem only valid for modem modules"); - return(-1); - } - p->u.module.type = MODEM; - p->u.module.v_type = 1; - DPR_INIT(("Adding MODEM to config...\n")); - break; - - case CABLE: - if (p->type == LNODE) { - if ((s = dgap_getword(in)) == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.line.cable = dgap_savestring(s); - p->u.line.v_cable = 1; - } - DPR_INIT(("Adding CABLE (%s) to config...\n", s)); - break; - - case SPEED: /* sync line speed indication */ - if (p->type == LNODE) { - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.line.speed = (char)simple_strtol(s, &s2, 0); - if ((short)strlen(s) > (short)(s2 - s)) { - dgap_err("bad number for line speed"); - return(-1); - } - p->u.line.v_speed = 1; - } else if (p->type == CNODE) { - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.conc.speed = (char)simple_strtol(s, &s2, 0); - if ((short)strlen(s) > (short)(s2 - s)) { - dgap_err("bad number for line speed"); - return(-1); - } - p->u.conc.v_speed = 1; - } else { - dgap_err("speed valid only for lines or concentrators."); - return(-1); - } - DPR_INIT(("Adding SPEED (%s) to config...\n", s)); - break; - - case CONNECT: - if (p->type == CNODE) { - if ((s = dgap_getword(in)) == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.conc.connect = dgap_savestring(s); - p->u.conc.v_connect = 1; - } - DPR_INIT(("Adding CONNECT (%s) to config...\n", s)); - break; - case PRINT: /* transparent print name prefix */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(PNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - if ( (s = dgap_getword(in)) == NULL ) { - dgap_err("unexpeced end of file"); - return(-1); - } - if ( (p->u.printname = dgap_savestring(s)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - DPR_INIT(("Adding PRINT (%s) to config...\n", s)); - break; - - case CMAJOR: /* major number */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(JNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.majornumber = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for major number"); - return(-1); - } - DPR_INIT(("Adding CMAJOR (%s) to config...\n", s)); - break; - - case ALTPIN: /* altpin setting */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(ANODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.altpin = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for altpin"); - return(-1); - } - DPR_INIT(("Adding ALTPIN (%s) to config...\n", s)); - break; - - case USEINTR: /* enable interrupt setting */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(INTRNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.useintr = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for useintr"); - return(-1); - } - DPR_INIT(("Adding USEINTR (%s) to config...\n", s)); - break; - - case TTSIZ: /* size of tty structure */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(TSNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.ttysize = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for ttysize"); - return(-1); - } - DPR_INIT(("Adding TTSIZ (%s) to config...\n", s)); - break; - - case CHSIZ: /* channel structure size */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(CSNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.chsize = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for chsize"); - return(-1); - } - DPR_INIT(("Adding CHSIZE (%s) to config...\n", s)); - break; - - case BSSIZ: /* board structure size */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(BSNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.bssize = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for bssize"); - return(-1); - } - DPR_INIT(("Adding BSSIZ (%s) to config...\n", s)); - break; - - case UNTSIZ: /* sched structure size */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(USNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.unsize = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for schedsize"); - return(-1); - } - DPR_INIT(("Adding UNTSIZ (%s) to config...\n", s)); - break; - - case F2SIZ: /* f2200 structure size */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(FSNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.f2size = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for f2200size"); - return(-1); - } - DPR_INIT(("Adding F2SIZ (%s) to config...\n", s)); - break; - - case VPSIZ: /* vpix structure size */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(VSNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.vpixsize = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for vpixsize"); - return(-1); - } - DPR_INIT(("Adding VPSIZ (%s) to config...\n", s)); - break; - } - } -} - - -/* - * dgap_sindex: much like index(), but it looks for a match of any character in - * the group, and returns that position. If the first character is a ^, then - * this will match the first occurrence not in that group. - */ -static char *dgap_sindex (char *string, char *group) -{ - char *ptr; - - if (!string || !group) - return (char *) NULL; - - if (*group == '^') { - group++; - for (; *string; string++) { - for (ptr = group; *ptr; ptr++) { - if (*ptr == *string) - break; - } - if (*ptr == '\0') - return string; - } - } - else { - for (; *string; string++) { - for (ptr = group; *ptr; ptr++) { - if (*ptr == *string) - return string; - } - } - } - - return (char *) NULL; -} - - -/* - * Get a token from the input file; return 0 if end of file is reached - */ -static int dgap_gettok(char **in, struct cnode *p) -{ - char *w; - struct toklist *t; - - if (strstr(dgap_cword, "boar")) { - w = dgap_getword(in); - snprintf(dgap_cword, MAXCWORD, "%s", w); - for (t = dgap_tlist; t->token != 0; t++) { - if ( !strcmp(w, t->string)) { - return(t->token); - } - } - dgap_err("board !!type not specified"); - return(1); - } - else { - while ( (w = dgap_getword(in)) != NULL ) { - snprintf(dgap_cword, MAXCWORD, "%s", w); - for (t = dgap_tlist; t->token != 0; t++) { - if ( !strcmp(w, t->string) ) - return(t->token); - } - } - return(0); - } -} - - -/* - * get a word from the input stream, also keep track of current line number. - * words are separated by whitespace. - */ -static char *dgap_getword(char **in) -{ - char *ret_ptr = *in; - - char *ptr = dgap_sindex(*in, " \t\n"); - - /* If no word found, return null */ - if (!ptr) - return NULL; - - /* Mark new location for our buffer */ - *ptr = '\0'; - *in = ptr + 1; - - /* Eat any extra spaces/tabs/newlines that might be present */ - while (*in && **in && ((**in == ' ') || (**in == '\t') || (**in == '\n'))) { - **in = '\0'; - *in = *in + 1; - } - - return ret_ptr; -} - - -/* - * print an error message, giving the line number in the file where - * the error occurred. - */ -static void dgap_err(char *s) -{ - printk("DGAP: parse: %s\n", s); -} - - -/* - * allocate a new configuration node of type t - */ -static struct cnode *dgap_newnode(int t) -{ - struct cnode *n; - - n = kmalloc(sizeof(struct cnode), GFP_ATOMIC); - if (n != NULL) { - memset((char *)n, 0, sizeof(struct cnode)); - n->type = t; - } - return(n); -} - - -/* - * dgap_checknode: see if all the necessary info has been supplied for a node - * before creating the next node. - */ -static int dgap_checknode(struct cnode *p) -{ - switch (p->type) { - case BNODE: - if (p->u.board.v_type == 0) { - dgap_err("board type !not specified"); - return(1); - } - - return(0); - - case LNODE: - if (p->u.line.v_speed == 0) { - dgap_err("line speed not specified"); - return(1); - } - return(0); - - case CNODE: - if (p->u.conc.v_type == 0) { - dgap_err("concentrator type not specified"); - return(1); - } - if (p->u.conc.v_speed == 0) { - dgap_err("concentrator line speed not specified"); - return(1); - } - if (p->u.conc.v_nport == 0) { - dgap_err("number of ports on concentrator not specified"); - return(1); - } - if (p->u.conc.v_id == 0) { - dgap_err("concentrator id letter not specified"); - return(1); - } - return(0); - - case MNODE: - if (p->u.module.v_type == 0) { - dgap_err("EBI module type not specified"); - return(1); - } - if (p->u.module.v_nport == 0) { - dgap_err("number of ports on EBI module not specified"); - return(1); - } - if (p->u.module.v_id == 0) { - dgap_err("EBI module id letter not specified"); - return(1); - } - return(0); - } - return(0); -} - -/* - * save a string somewhere - */ -static char *dgap_savestring(char *s) -{ - char *p; - if ( (p = kmalloc(strlen(s) + 1, GFP_ATOMIC) ) != NULL) { - strcpy(p, s); - } - return(p); -} - - -/* - * Given a board pointer, returns whether we should use interrupts or not. - */ -uint dgap_config_get_useintr(struct board_t *bd) -{ - struct cnode *p = NULL; - - if (!bd) - return(0); - - for (p = bd->bd_config; p; p = p->next) { - switch (p->type) { - case INTRNODE: - /* - * check for pcxr types. - */ - return p->u.useintr; - default: - break; - } - } - - /* If not found, then don't turn on interrupts. */ - return 0; -} - - -/* - * Given a board pointer, returns whether we turn on altpin or not. - */ -uint dgap_config_get_altpin(struct board_t *bd) -{ - struct cnode *p = NULL; - - if (!bd) - return(0); - - for (p = bd->bd_config; p; p = p->next) { - switch (p->type) { - case ANODE: - /* - * check for pcxr types. - */ - return p->u.altpin; - default: - break; - } - } - - /* If not found, then don't turn on interrupts. */ - return 0; -} - - - -/* - * Given a specific type of board, if found, detached link and - * returns the first occurrence in the list. - */ -struct cnode *dgap_find_config(int type, int bus, int slot) -{ - struct cnode *p, *prev = NULL, *prev2 = NULL, *found = NULL; - - p = &dgap_head; - - while (p->next != NULL) { - prev = p; - p = p->next; - - if (p->type == BNODE) { - - if (p->u.board.type == type) { - - if (p->u.board.v_pcibus && p->u.board.pcibus != bus) { - DPR(("Found matching board, but wrong bus position. System says bus %d, we want bus %ld\n", - bus, p->u.board.pcibus)); - continue; - } - if (p->u.board.v_pcislot && p->u.board.pcislot != slot) { - DPR_INIT(("Found matching board, but wrong slot position. System says slot %d, we want slot %ld\n", - slot, p->u.board.pcislot)); - continue; - } - - DPR_INIT(("Matched type in config file\n")); - - found = p; - /* - * Keep walking thru the list till we find the next board. - */ - while (p->next != NULL) { - prev2 = p; - p = p->next; - if (p->type == BNODE) { - - /* - * Mark the end of our 1 board chain of configs. - */ - prev2->next = NULL; - - /* - * Link the "next" board to the previous board, - * effectively "unlinking" our board from the main config. - */ - prev->next = p; - - return found; - } - } - /* - * It must be the last board in the list. - */ - prev->next = NULL; - return found; - } - } - } - return NULL; -} - -/* - * Given a board pointer, walks the config link, counting up - * all ports user specified should be on the board. - * (This does NOT mean they are all actually present right now tho) - */ -uint dgap_config_get_number_of_ports(struct board_t *bd) -{ - int count = 0; - struct cnode *p = NULL; - - if (!bd) - return(0); - - for (p = bd->bd_config; p; p = p->next) { - - switch (p->type) { - case BNODE: - /* - * check for pcxr types. - */ - if (p->u.board.type > EPCFE) - count += p->u.board.nport; - break; - case CNODE: - count += p->u.conc.nport; - break; - case MNODE: - count += p->u.module.nport; - break; - } - } - return (count); -} - -char *dgap_create_config_string(struct board_t *bd, char *string) -{ - char *ptr = string; - struct cnode *p = NULL; - struct cnode *q = NULL; - int speed; - - if (!bd) { - *ptr = 0xff; - return string; - } - - for (p = bd->bd_config; p; p = p->next) { - - switch (p->type) { - case LNODE: - *ptr = '\0'; - ptr++; - *ptr = p->u.line.speed; - ptr++; - break; - case CNODE: - /* - * Because the EPC/con concentrators can have EM modules - * hanging off of them, we have to walk ahead in the list - * and keep adding the number of ports on each EM to the config. - * UGH! - */ - speed = p->u.conc.speed; - q = p->next; - if ((q != NULL) && (q->type == MNODE) ) { - *ptr = (p->u.conc.nport + 0x80); - ptr++; - p = q; - while ((q->next != NULL) && (q->next->type) == MNODE) { - *ptr = (q->u.module.nport + 0x80); - ptr++; - p = q; - q = q->next; - } - *ptr = q->u.module.nport; - ptr++; - } else { - *ptr = p->u.conc.nport; - ptr++; - } - - *ptr = speed; - ptr++; - break; - } - } - - *ptr = 0xff; - return string; -} - - - -char *dgap_get_config_letters(struct board_t *bd, char *string) -{ - int found = FALSE; - char *ptr = string; - struct cnode *cptr = NULL; - int len = 0; - int left = MAXTTYNAMELEN; - - if (!bd) { - return ""; - } - - for (cptr = bd->bd_config; cptr; cptr = cptr->next) { - - if ((cptr->type == BNODE) && - ((cptr->u.board.type == APORT2_920P) || (cptr->u.board.type == APORT4_920P) || - (cptr->u.board.type == APORT8_920P) || (cptr->u.board.type == PAPORT4) || - (cptr->u.board.type == PAPORT8))) { - - found = TRUE; - } - - if (cptr->type == TNODE && found == TRUE) { - char *ptr1; - if (strstr(cptr->u.ttyname, "tty")) { - ptr1 = cptr->u.ttyname; - ptr1 += 3; - } - else { - ptr1 = cptr->u.ttyname; - } - if (ptr1) { - len = snprintf(ptr, left, "%s", ptr1); - left -= len; - ptr += len; - if (left <= 0) - break; - } - } - - if (cptr->type == CNODE) { - if (cptr->u.conc.id) { - len = snprintf(ptr, left, "%s", cptr->u.conc.id); - left -= len; - ptr += len; - if (left <= 0) - break; - } - } - - if (cptr->type == MNODE) { - if (cptr->u.module.id) { - len = snprintf(ptr, left, "%s", cptr->u.module.id); - left -= len; - ptr += len; - if (left <= 0) - break; - } - } - } - - return string; -} diff --git a/drivers/staging/dgap/dgap_parse.h b/drivers/staging/dgap/dgap_parse.h deleted file mode 100644 index 8128c47343cb..000000000000 --- a/drivers/staging/dgap/dgap_parse.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - */ - -#ifndef _DGAP_PARSE_H -#define _DGAP_PARSE_H - -#include "dgap_driver.h" - -extern int dgap_parsefile(char **in, int Remove); -extern struct cnode *dgap_find_config(int type, int bus, int slot); -extern uint dgap_config_get_number_of_ports(struct board_t *bd); -extern char *dgap_create_config_string(struct board_t *bd, char *string); -extern char *dgap_get_config_letters(struct board_t *bd, char *string); -extern uint dgap_config_get_useintr(struct board_t *bd); -extern uint dgap_config_get_altpin(struct board_t *bd); - -#endif diff --git a/drivers/staging/dgap/dgap_pci.h b/drivers/staging/dgap/dgap_pci.h deleted file mode 100644 index 05ed374f08e1..000000000000 --- a/drivers/staging/dgap/dgap_pci.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - */ - -/* $Id: dgap_pci.h,v 1.1 2009/10/23 14:01:57 markh Exp $ */ - -#ifndef __DGAP_PCI_H -#define __DGAP_PCI_H - -#define PCIMAX 32 /* maximum number of PCI boards */ - -#define DIGI_VID 0x114F - -#define PCI_DEVICE_EPC_DID 0x0002 -#define PCI_DEVICE_XEM_DID 0x0004 -#define PCI_DEVICE_XR_DID 0x0005 -#define PCI_DEVICE_CX_DID 0x0006 -#define PCI_DEVICE_XRJ_DID 0x0009 /* PLX-based Xr adapter */ -#define PCI_DEVICE_XR_IBM_DID 0x0011 /* IBM 8-port Async Adapter */ -#define PCI_DEVICE_XR_BULL_DID 0x0013 /* BULL 8-port Async Adapter */ -#define PCI_DEVICE_XR_SAIP_DID 0x001c /* SAIP card - Xr adapter */ -#define PCI_DEVICE_XR_422_DID 0x0012 /* Xr-422 */ -#define PCI_DEVICE_920_2_DID 0x0034 /* XR-Plus 920 K, 2 port */ -#define PCI_DEVICE_920_4_DID 0x0026 /* XR-Plus 920 K, 4 port */ -#define PCI_DEVICE_920_8_DID 0x0027 /* XR-Plus 920 K, 8 port */ -#define PCI_DEVICE_EPCJ_DID 0x000a /* PLX 9060 chip for PCI */ -#define PCI_DEVICE_CX_IBM_DID 0x001b /* IBM 128-port Async Adapter */ -#define PCI_DEVICE_920_8_HP_DID 0x0058 /* HP XR-Plus 920 K, 8 port */ -#define PCI_DEVICE_XEM_HP_DID 0x0059 /* HP Xem PCI */ - -#define PCI_DEVICE_XEM_NAME "AccelePort XEM" -#define PCI_DEVICE_CX_NAME "AccelePort CX" -#define PCI_DEVICE_XR_NAME "AccelePort Xr" -#define PCI_DEVICE_XRJ_NAME "AccelePort Xr (PLX)" -#define PCI_DEVICE_XR_SAIP_NAME "AccelePort Xr (SAIP)" -#define PCI_DEVICE_920_2_NAME "AccelePort Xr920 2 port" -#define PCI_DEVICE_920_4_NAME "AccelePort Xr920 4 port" -#define PCI_DEVICE_920_8_NAME "AccelePort Xr920 8 port" -#define PCI_DEVICE_XR_422_NAME "AccelePort Xr 422" -#define PCI_DEVICE_EPCJ_NAME "AccelePort EPC (PLX)" -#define PCI_DEVICE_XR_BULL_NAME "AccelePort Xr (BULL)" -#define PCI_DEVICE_XR_IBM_NAME "AccelePort Xr (IBM)" -#define PCI_DEVICE_CX_IBM_NAME "AccelePort CX (IBM)" -#define PCI_DEVICE_920_8_HP_NAME "AccelePort Xr920 8 port (HP)" -#define PCI_DEVICE_XEM_HP_NAME "AccelePort XEM (HP)" - - -/* - * On the PCI boards, there is no IO space allocated - * The I/O registers will be in the first 3 bytes of the - * upper 2MB of the 4MB memory space. The board memory - * will be mapped into the low 2MB of the 4MB memory space - */ - -/* Potential location of PCI Bios from E0000 to FFFFF*/ -#define PCI_BIOS_SIZE 0x00020000 - -/* Size of Memory and I/O for PCI (4MB) */ -#define PCI_RAM_SIZE 0x00400000 - -/* Size of Memory (2MB) */ -#define PCI_MEM_SIZE 0x00200000 - -/* Max PCI Window Size (2MB) */ -#define PCI_WIN_SIZE 0x00200000 - -#define PCI_WIN_SHIFT 21 /* 21 bits max */ - -/* Offset of I/0 in Memory (2MB) */ -#define PCI_IO_OFFSET 0x00200000 - -/* Size of IO (2MB) */ -#define PCI_IO_SIZE 0x00200000 - -#endif diff --git a/drivers/staging/dgap/dgap_sysfs.c b/drivers/staging/dgap/dgap_sysfs.c deleted file mode 100644 index 7f4ec9a18293..000000000000 --- a/drivers/staging/dgap/dgap_sysfs.c +++ /dev/null @@ -1,793 +0,0 @@ -/* - * Copyright 2004 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! - * - * This is shared code between Digi's CVS archive and the - * Linux Kernel sources. - * Changing the source just for reformatting needlessly breaks - * our CVS diff history. - * - * Send any bug fixes/changes to: Eng.Linux at digi dot com. - * Thank you. - * - * - * - * $Id: dgap_sysfs.c,v 1.1 2009/10/23 14:01:57 markh Exp $ - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dgap_driver.h" -#include "dgap_conf.h" -#include "dgap_parse.h" - - -static ssize_t dgap_driver_version_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", DG_PART); -} -static DRIVER_ATTR(version, S_IRUSR, dgap_driver_version_show, NULL); - - -static ssize_t dgap_driver_boards_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", dgap_NumBoards); -} -static DRIVER_ATTR(boards, S_IRUSR, dgap_driver_boards_show, NULL); - - -static ssize_t dgap_driver_maxboards_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", MAXBOARDS); -} -static DRIVER_ATTR(maxboards, S_IRUSR, dgap_driver_maxboards_show, NULL); - - -static ssize_t dgap_driver_pollcounter_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%ld\n", dgap_poll_counter); -} -static DRIVER_ATTR(pollcounter, S_IRUSR, dgap_driver_pollcounter_show, NULL); - - -static ssize_t dgap_driver_state_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", dgap_driver_state_text[dgap_driver_state]); -} -static DRIVER_ATTR(state, S_IRUSR, dgap_driver_state_show, NULL); - - -static ssize_t dgap_driver_debug_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "0x%x\n", dgap_debug); -} - -static ssize_t dgap_driver_debug_store(struct device_driver *ddp, const char *buf, size_t count) -{ - sscanf(buf, "0x%x\n", &dgap_debug); - return count; -} -static DRIVER_ATTR(debug, (S_IRUSR | S_IWUSR), dgap_driver_debug_show, dgap_driver_debug_store); - - -static ssize_t dgap_driver_rawreadok_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "0x%x\n", dgap_rawreadok); -} - -static ssize_t dgap_driver_rawreadok_store(struct device_driver *ddp, const char *buf, size_t count) -{ - sscanf(buf, "0x%x\n", &dgap_rawreadok); - return count; -} -static DRIVER_ATTR(rawreadok, (S_IRUSR | S_IWUSR), dgap_driver_rawreadok_show, dgap_driver_rawreadok_store); - - -static ssize_t dgap_driver_pollrate_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%dms\n", dgap_poll_tick); -} - -static ssize_t dgap_driver_pollrate_store(struct device_driver *ddp, const char *buf, size_t count) -{ - sscanf(buf, "%d\n", &dgap_poll_tick); - return count; -} -static DRIVER_ATTR(pollrate, (S_IRUSR | S_IWUSR), dgap_driver_pollrate_show, dgap_driver_pollrate_store); - - -void dgap_create_driver_sysfiles(struct pci_driver *dgap_driver) -{ - int rc = 0; - struct device_driver *driverfs = &dgap_driver->driver; - - rc |= driver_create_file(driverfs, &driver_attr_version); - rc |= driver_create_file(driverfs, &driver_attr_boards); - rc |= driver_create_file(driverfs, &driver_attr_maxboards); - rc |= driver_create_file(driverfs, &driver_attr_debug); - rc |= driver_create_file(driverfs, &driver_attr_rawreadok); - rc |= driver_create_file(driverfs, &driver_attr_pollrate); - rc |= driver_create_file(driverfs, &driver_attr_pollcounter); - rc |= driver_create_file(driverfs, &driver_attr_state); - if (rc) { - printk(KERN_ERR "DGAP: sysfs driver_create_file failed!\n"); - } -} - - -void dgap_remove_driver_sysfiles(struct pci_driver *dgap_driver) -{ - struct device_driver *driverfs = &dgap_driver->driver; - driver_remove_file(driverfs, &driver_attr_version); - driver_remove_file(driverfs, &driver_attr_boards); - driver_remove_file(driverfs, &driver_attr_maxboards); - driver_remove_file(driverfs, &driver_attr_debug); - driver_remove_file(driverfs, &driver_attr_rawreadok); - driver_remove_file(driverfs, &driver_attr_pollrate); - driver_remove_file(driverfs, &driver_attr_pollcounter); - driver_remove_file(driverfs, &driver_attr_state); -} - - -#define DGAP_VERIFY_BOARD(p, bd) \ - if (!p) \ - return (0); \ - \ - bd = dev_get_drvdata(p); \ - if (!bd || bd->magic != DGAP_BOARD_MAGIC) \ - return (0); \ - if (bd->state != BOARD_READY) \ - return (0); \ - - -static ssize_t dgap_ports_state_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, - "%d %s\n", bd->channels[i]->ch_portnum, - bd->channels[i]->ch_open_count ? "Open" : "Closed"); - } - return count; -} -static DEVICE_ATTR(ports_state, S_IRUSR, dgap_ports_state_show, NULL); - - -static ssize_t dgap_ports_baud_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, - "%d %d\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_baud_info); - } - return count; -} -static DEVICE_ATTR(ports_baud, S_IRUSR, dgap_ports_baud_show, NULL); - - -static ssize_t dgap_ports_msignals_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - if (bd->channels[i]->ch_open_count) { - count += snprintf(buf + count, PAGE_SIZE - count, - "%d %s %s %s %s %s %s\n", bd->channels[i]->ch_portnum, - (bd->channels[i]->ch_mostat & UART_MCR_RTS) ? "RTS" : "", - (bd->channels[i]->ch_mistat & UART_MSR_CTS) ? "CTS" : "", - (bd->channels[i]->ch_mostat & UART_MCR_DTR) ? "DTR" : "", - (bd->channels[i]->ch_mistat & UART_MSR_DSR) ? "DSR" : "", - (bd->channels[i]->ch_mistat & UART_MSR_DCD) ? "DCD" : "", - (bd->channels[i]->ch_mistat & UART_MSR_RI) ? "RI" : ""); - } else { - count += snprintf(buf + count, PAGE_SIZE - count, - "%d\n", bd->channels[i]->ch_portnum); - } - } - return count; -} -static DEVICE_ATTR(ports_msignals, S_IRUSR, dgap_ports_msignals_show, NULL); - - -static ssize_t dgap_ports_iflag_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", - bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_iflag); - } - return count; -} -static DEVICE_ATTR(ports_iflag, S_IRUSR, dgap_ports_iflag_show, NULL); - - -static ssize_t dgap_ports_cflag_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", - bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_cflag); - } - return count; -} -static DEVICE_ATTR(ports_cflag, S_IRUSR, dgap_ports_cflag_show, NULL); - - -static ssize_t dgap_ports_oflag_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", - bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_oflag); - } - return count; -} -static DEVICE_ATTR(ports_oflag, S_IRUSR, dgap_ports_oflag_show, NULL); - - -static ssize_t dgap_ports_lflag_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", - bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_lflag); - } - return count; -} -static DEVICE_ATTR(ports_lflag, S_IRUSR, dgap_ports_lflag_show, NULL); - - -static ssize_t dgap_ports_digi_flag_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", - bd->channels[i]->ch_portnum, bd->channels[i]->ch_digi.digi_flags); - } - return count; -} -static DEVICE_ATTR(ports_digi_flag, S_IRUSR, dgap_ports_digi_flag_show, NULL); - - -static ssize_t dgap_ports_rxcount_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n", - bd->channels[i]->ch_portnum, bd->channels[i]->ch_rxcount); - } - return count; -} -static DEVICE_ATTR(ports_rxcount, S_IRUSR, dgap_ports_rxcount_show, NULL); - - -static ssize_t dgap_ports_txcount_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n", - bd->channels[i]->ch_portnum, bd->channels[i]->ch_txcount); - } - return count; -} -static DEVICE_ATTR(ports_txcount, S_IRUSR, dgap_ports_txcount_show, NULL); - - -/* this function creates the sys files that will export each signal status - * to sysfs each value will be put in a separate filename - */ -void dgap_create_ports_sysfiles(struct board_t *bd) -{ - int rc = 0; - - dev_set_drvdata(&bd->pdev->dev, bd); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_state); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_baud); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_msignals); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_iflag); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_cflag); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_oflag); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_lflag); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_rxcount); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_txcount); - if (rc) { - printk(KERN_ERR "DGAP: sysfs device_create_file failed!\n"); - } -} - - -/* removes all the sys files created for that port */ -void dgap_remove_ports_sysfiles(struct board_t *bd) -{ - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_state); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_baud); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_msignals); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_iflag); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_cflag); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_oflag); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_lflag); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_rxcount); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_txcount); -} - - -static ssize_t dgap_tty_state_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%s", un->un_open_count ? "Open" : "Closed"); -} -static DEVICE_ATTR(state, S_IRUSR, dgap_tty_state_show, NULL); - - -static ssize_t dgap_tty_baud_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_baud_info); -} -static DEVICE_ATTR(baud, S_IRUSR, dgap_tty_baud_show, NULL); - - -static ssize_t dgap_tty_msignals_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - if (ch->ch_open_count) { - return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n", - (ch->ch_mostat & UART_MCR_RTS) ? "RTS" : "", - (ch->ch_mistat & UART_MSR_CTS) ? "CTS" : "", - (ch->ch_mostat & UART_MCR_DTR) ? "DTR" : "", - (ch->ch_mistat & UART_MSR_DSR) ? "DSR" : "", - (ch->ch_mistat & UART_MSR_DCD) ? "DCD" : "", - (ch->ch_mistat & UART_MSR_RI) ? "RI" : ""); - } - return 0; -} -static DEVICE_ATTR(msignals, S_IRUSR, dgap_tty_msignals_show, NULL); - - -static ssize_t dgap_tty_iflag_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_iflag); -} -static DEVICE_ATTR(iflag, S_IRUSR, dgap_tty_iflag_show, NULL); - - -static ssize_t dgap_tty_cflag_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_cflag); -} -static DEVICE_ATTR(cflag, S_IRUSR, dgap_tty_cflag_show, NULL); - - -static ssize_t dgap_tty_oflag_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_oflag); -} -static DEVICE_ATTR(oflag, S_IRUSR, dgap_tty_oflag_show, NULL); - - -static ssize_t dgap_tty_lflag_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_lflag); -} -static DEVICE_ATTR(lflag, S_IRUSR, dgap_tty_lflag_show, NULL); - - -static ssize_t dgap_tty_digi_flag_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags); -} -static DEVICE_ATTR(digi_flag, S_IRUSR, dgap_tty_digi_flag_show, NULL); - - -static ssize_t dgap_tty_rxcount_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_rxcount); -} -static DEVICE_ATTR(rxcount, S_IRUSR, dgap_tty_rxcount_show, NULL); - - -static ssize_t dgap_tty_txcount_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_txcount); -} -static DEVICE_ATTR(txcount, S_IRUSR, dgap_tty_txcount_show, NULL); - - -static ssize_t dgap_tty_name_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - int cn; - int bn; - struct cnode *cptr = NULL; - int found = FALSE; - int ncount = 0; - int starto = 0; - int i = 0; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - bn = bd->boardnum; - cn = ch->ch_portnum; - - for (cptr = bd->bd_config; cptr; cptr = cptr->next) { - - if ((cptr->type == BNODE) && - ((cptr->u.board.type == APORT2_920P) || (cptr->u.board.type == APORT4_920P) || - (cptr->u.board.type == APORT8_920P) || (cptr->u.board.type == PAPORT4) || - (cptr->u.board.type == PAPORT8))) { - - found = TRUE; - if (cptr->u.board.v_start) - starto = cptr->u.board.start; - else - starto = 1; - } - - if (cptr->type == TNODE && found == TRUE) { - char *ptr1; - if (strstr(cptr->u.ttyname, "tty")) { - ptr1 = cptr->u.ttyname; - ptr1 += 3; - } - else { - ptr1 = cptr->u.ttyname; - } - - for (i = 0; i < dgap_config_get_number_of_ports(bd); i++) { - if (cn == i) { - return snprintf(buf, PAGE_SIZE, "%s%s%02d\n", - (un->un_type == DGAP_PRINT) ? "pr" : "tty", - ptr1, i + starto); - } - } - } - - if (cptr->type == CNODE) { - - for (i = 0; i < cptr->u.conc.nport; i++) { - if (cn == (i + ncount)) { - - return snprintf(buf, PAGE_SIZE, "%s%s%02d\n", - (un->un_type == DGAP_PRINT) ? "pr" : "tty", - cptr->u.conc.id, - i + (cptr->u.conc.v_start ? cptr->u.conc.start : 1)); - } - } - - ncount += cptr->u.conc.nport; - } - - if (cptr->type == MNODE) { - - for (i = 0; i < cptr->u.module.nport; i++) { - if (cn == (i + ncount)) { - return snprintf(buf, PAGE_SIZE, "%s%s%02d\n", - (un->un_type == DGAP_PRINT) ? "pr" : "tty", - cptr->u.module.id, - i + (cptr->u.module.v_start ? cptr->u.module.start : 1)); - } - } - - ncount += cptr->u.module.nport; - - } - } - - return snprintf(buf, PAGE_SIZE, "%s_dgap_%d_%d\n", - (un->un_type == DGAP_PRINT) ? "pr" : "tty", bn, cn); - -} -static DEVICE_ATTR(custom_name, S_IRUSR, dgap_tty_name_show, NULL); - - -static struct attribute *dgap_sysfs_tty_entries[] = { - &dev_attr_state.attr, - &dev_attr_baud.attr, - &dev_attr_msignals.attr, - &dev_attr_iflag.attr, - &dev_attr_cflag.attr, - &dev_attr_oflag.attr, - &dev_attr_lflag.attr, - &dev_attr_digi_flag.attr, - &dev_attr_rxcount.attr, - &dev_attr_txcount.attr, - &dev_attr_custom_name.attr, - NULL -}; - - -static struct attribute_group dgap_tty_attribute_group = { - .name = NULL, - .attrs = dgap_sysfs_tty_entries, -}; - - - - -void dgap_create_tty_sysfs(struct un_t *un, struct device *c) -{ - int ret; - - ret = sysfs_create_group(&c->kobj, &dgap_tty_attribute_group); - if (ret) { - printk(KERN_ERR "dgap: failed to create sysfs tty device attributes.\n"); - sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group); - return; - } - - dev_set_drvdata(c, un); - -} - - -void dgap_remove_tty_sysfs(struct device *c) -{ - sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group); -} diff --git a/drivers/staging/dgap/dgap_sysfs.h b/drivers/staging/dgap/dgap_sysfs.h deleted file mode 100644 index dde690eec5cf..000000000000 --- a/drivers/staging/dgap/dgap_sysfs.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - */ - -#ifndef __DGAP_SYSFS_H -#define __DGAP_SYSFS_H - -#include "dgap_driver.h" - -#include - -struct board_t; -struct channel_t; -struct un_t; -struct pci_driver; -struct class_device; - -extern void dgap_create_ports_sysfiles(struct board_t *bd); -extern void dgap_remove_ports_sysfiles(struct board_t *bd); - -extern void dgap_create_driver_sysfiles(struct pci_driver *); -extern void dgap_remove_driver_sysfiles(struct pci_driver *); - -extern int dgap_tty_class_init(void); -extern int dgap_tty_class_destroy(void); - -extern void dgap_create_tty_sysfs(struct un_t *un, struct device *c); -extern void dgap_remove_tty_sysfs(struct device *c); - - -#endif diff --git a/drivers/staging/dgap/dgap_trace.c b/drivers/staging/dgap/dgap_trace.c deleted file mode 100644 index a53db9e0a577..000000000000 --- a/drivers/staging/dgap/dgap_trace.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! - * - * This is shared code between Digi's CVS archive and the - * Linux Kernel sources. - * Changing the source just for reformatting needlessly breaks - * our CVS diff history. - * - * Send any bug fixes/changes to: Eng.Linux at digi dot com. - * Thank you. - * - */ - -/* $Id: dgap_trace.c,v 1.1 2009/10/23 14:01:57 markh Exp $ */ - -#include -#include /* For jiffies, task states */ -#include /* For tasklet and interrupt structs/defines */ -#include - -#include "dgap_driver.h" -#include "dgap_trace.h" - -#define TRC_TO_CONSOLE 1 - -/* file level globals */ -static char *dgap_trcbuf; /* the ringbuffer */ - -#if defined(TRC_TO_KMEM) -static int dgap_trcbufi = 0; /* index of the tilde at the end of */ -#endif - -extern int dgap_trcbuf_size; /* size of the ringbuffer */ - -#if defined(TRC_TO_KMEM) -static DEFINE_SPINLOCK(dgap_tracef_lock); -#endif - -#if 0 - -#if !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) -void dgap_tracef(const char *fmt, ...) -{ - return; -} - -#else /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */ - -void dgap_tracef(const char *fmt, ...) -{ - va_list ap; - char buf[TRC_MAXMSG+1]; - size_t lenbuf; - int i; - static int failed = FALSE; -# if defined(TRC_TO_KMEM) - unsigned long flags; -#endif - - if(failed) - return; -# if defined(TRC_TO_KMEM) - DGAP_LOCK(dgap_tracef_lock, flags); -#endif - - /* Format buf using fmt and arguments contained in ap. */ - va_start(ap, fmt); - i = vsprintf(buf, fmt, ap); - va_end(ap); - lenbuf = strlen(buf); - -# if defined(TRC_TO_KMEM) - { - static int initd=0; - - /* - * Now, in addition to (or instead of) printing this stuff out - * (which is a buffered operation), also tuck it away into a - * corner of memory which can be examined post-crash in kdb. - */ - if (!initd) { - dgap_trcbuf = (char *) vmalloc(dgap_trcbuf_size); - if(!dgap_trcbuf) { - failed = TRUE; - printk("dgap: tracing init failed!\n"); - return; - } - - memset(dgap_trcbuf, '\0', dgap_trcbuf_size); - dgap_trcbufi = 0; - initd++; - - printk("dgap: tracing enabled - " TRC_DTRC - " 0x%lx 0x%x\n", - (unsigned long)dgap_trcbuf, - dgap_trcbuf_size); - } - -# if defined(TRC_ON_OVERFLOW_WRAP_AROUND) - /* - * This is the less CPU-intensive way to do things. We simply - * wrap around before we fall off the end of the buffer. A - * tilde (~) demarcates the current end of the trace. - * - * This method should be used if you are concerned about race - * conditions as it is less likely to affect the timing of - * things. - */ - - if (dgap_trcbufi + lenbuf >= dgap_trcbuf_size) { - /* We are wrapping, so wipe out the last tilde. */ - dgap_trcbuf[dgap_trcbufi] = '\0'; - /* put the new string at the beginning of the buffer */ - dgap_trcbufi = 0; - } - - strcpy(&dgap_trcbuf[dgap_trcbufi], buf); - dgap_trcbufi += lenbuf; - dgap_trcbuf[dgap_trcbufi] = '~'; - -# elif defined(TRC_ON_OVERFLOW_SHIFT_BUFFER) - /* - * This is the more CPU-intensive way to do things. If we - * venture into the last 1/8 of the buffer, we shift the - * last 7/8 of the buffer forward, wiping out the first 1/8. - * Advantage: No wrap-around, only truncation from the - * beginning. - * - * This method should not be used if you are concerned about - * timing changes affecting the behaviour of the driver (ie, - * race conditions). - */ - strcpy(&dgap_trcbuf[dgap_trcbufi], buf); - dgap_trcbufi += lenbuf; - dgap_trcbuf[dgap_trcbufi] = '~'; - dgap_trcbuf[dgap_trcbufi+1] = '\0'; - - /* If we're near the end of the trace buffer... */ - if (dgap_trcbufi > (dgap_trcbuf_size/8)*7) { - /* Wipe out the first eighth to make some more room. */ - strcpy(dgap_trcbuf, &dgap_trcbuf[dgap_trcbuf_size/8]); - dgap_trcbufi = strlen(dgap_trcbuf)-1; - /* Plop overflow message at the top of the buffer. */ - bcopy(TRC_OVERFLOW, dgap_trcbuf, strlen(TRC_OVERFLOW)); - } -# else -# error "TRC_ON_OVERFLOW_WRAP_AROUND or TRC_ON_OVERFLOW_SHIFT_BUFFER?" -# endif - } - DGAP_UNLOCK(dgap_tracef_lock, flags); - -# endif /* defined(TRC_TO_KMEM) */ -} - -#endif /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */ - -#endif - -/* - * dgap_tracer_free() - * - * - */ -void dgap_tracer_free(void) -{ - if(dgap_trcbuf) - vfree(dgap_trcbuf); -} diff --git a/drivers/staging/dgap/dgap_trace.h b/drivers/staging/dgap/dgap_trace.h deleted file mode 100644 index b21f46198e71..000000000000 --- a/drivers/staging/dgap/dgap_trace.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - * - ***************************************************************************** - * Header file for dgap_trace.c - * - * $Id: dgap_trace.h,v 1.1 2009/10/23 14:01:57 markh Exp $ - */ - -#ifndef __DGAP_TRACE_H -#define __DGAP_TRACE_H - -#include "dgap_driver.h" - -void dgap_tracef(const char *fmt, ...); -void dgap_tracer_free(void); - -#endif - diff --git a/drivers/staging/dgap/dgap_tty.c b/drivers/staging/dgap/dgap_tty.c deleted file mode 100644 index 39fb4dfb8b7e..000000000000 --- a/drivers/staging/dgap/dgap_tty.c +++ /dev/null @@ -1,3580 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! - * - * This is shared code between Digi's CVS archive and the - * Linux Kernel sources. - * Changing the source just for reformatting needlessly breaks - * our CVS diff history. - * - * Send any bug fixes/changes to: Eng.Linux at digi dot com. - * Thank you. - */ - -/************************************************************************ - * - * This file implements the tty driver functionality for the - * FEP5 based product lines. - * - ************************************************************************ - * - * $Id: dgap_tty.c,v 1.3 2011/06/23 12:11:31 markh Exp $ - */ - -#include -#include -#include /* For jiffies, task states */ -#include /* For tasklet and interrupt structs/defines */ -#include -#include -#include -#include -#include -#include -#include /* For udelay */ -#include /* For copy_from_user/copy_to_user */ -#include /* For read[bwl]/write[bwl] */ -#include - -#include "dgap_driver.h" -#include "dgap_tty.h" -#include "dgap_types.h" -#include "dgap_fep5.h" -#include "dgap_parse.h" -#include "dgap_conf.h" -#include "dgap_sysfs.h" - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) -#define init_MUTEX(sem) sema_init(sem, 1) -#define DECLARE_MUTEX(name) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1) -#endif - -/* - * internal variables - */ -static struct board_t *dgap_BoardsByMajor[256]; -static uchar *dgap_TmpWriteBuf = NULL; -static DECLARE_MUTEX(dgap_TmpWriteSem); - -/* - * Default transparent print information. - */ -static struct digi_t dgap_digi_init = { - .digi_flags = DIGI_COOK, /* Flags */ - .digi_maxcps = 100, /* Max CPS */ - .digi_maxchar = 50, /* Max chars in print queue */ - .digi_bufsize = 100, /* Printer buffer size */ - .digi_onlen = 4, /* size of printer on string */ - .digi_offlen = 4, /* size of printer off string */ - .digi_onstr = "\033[5i", /* ANSI printer on string ] */ - .digi_offstr = "\033[4i", /* ANSI printer off string ] */ - .digi_term = "ansi" /* default terminal type */ -}; - - -/* - * Define a local default termios struct. All ports will be created - * with this termios initially. - * - * This defines a raw port at 9600 baud, 8 data bits, no parity, - * 1 stop bit. - */ - -static struct ktermios DgapDefaultTermios = -{ - .c_iflag = (DEFAULT_IFLAGS), /* iflags */ - .c_oflag = (DEFAULT_OFLAGS), /* oflags */ - .c_cflag = (DEFAULT_CFLAGS), /* cflags */ - .c_lflag = (DEFAULT_LFLAGS), /* lflags */ - .c_cc = INIT_C_CC, - .c_line = 0, -}; - -/* Our function prototypes */ -static int dgap_tty_open(struct tty_struct *tty, struct file *file); -static void dgap_tty_close(struct tty_struct *tty, struct file *file); -static int dgap_block_til_ready(struct tty_struct *tty, struct file *file, struct channel_t *ch); -static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); -static int dgap_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo); -static int dgap_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info); -static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo); -static int dgap_tty_digisetedelay(struct tty_struct *tty, int __user *new_info); -static int dgap_tty_write_room(struct tty_struct* tty); -static int dgap_tty_chars_in_buffer(struct tty_struct* tty); -static void dgap_tty_start(struct tty_struct *tty); -static void dgap_tty_stop(struct tty_struct *tty); -static void dgap_tty_throttle(struct tty_struct *tty); -static void dgap_tty_unthrottle(struct tty_struct *tty); -static void dgap_tty_flush_chars(struct tty_struct *tty); -static void dgap_tty_flush_buffer(struct tty_struct *tty); -static void dgap_tty_hangup(struct tty_struct *tty); -static int dgap_wait_for_drain(struct tty_struct *tty); -static int dgap_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value); -static int dgap_get_modem_info(struct channel_t *ch, unsigned int __user *value); -static int dgap_tty_digisetcustombaud(struct tty_struct *tty, int __user *new_info); -static int dgap_tty_digigetcustombaud(struct tty_struct *tty, int __user *retinfo); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) -static int dgap_tty_tiocmget(struct tty_struct *tty); -static int dgap_tty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -#else -static int dgap_tty_tiocmget(struct tty_struct *tty, struct file *file); -static int dgap_tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); -#endif -static int dgap_tty_send_break(struct tty_struct *tty, int msec); -static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout); -static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf, int count); -static void dgap_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios); -static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c); -static void dgap_tty_send_xchar(struct tty_struct *tty, char ch); - -static const struct tty_operations dgap_tty_ops = { - .open = dgap_tty_open, - .close = dgap_tty_close, - .write = dgap_tty_write, - .write_room = dgap_tty_write_room, - .flush_buffer = dgap_tty_flush_buffer, - .chars_in_buffer = dgap_tty_chars_in_buffer, - .flush_chars = dgap_tty_flush_chars, - .ioctl = dgap_tty_ioctl, - .set_termios = dgap_tty_set_termios, - .stop = dgap_tty_stop, - .start = dgap_tty_start, - .throttle = dgap_tty_throttle, - .unthrottle = dgap_tty_unthrottle, - .hangup = dgap_tty_hangup, - .put_char = dgap_tty_put_char, - .tiocmget = dgap_tty_tiocmget, - .tiocmset = dgap_tty_tiocmset, - .break_ctl = dgap_tty_send_break, - .wait_until_sent = dgap_tty_wait_until_sent, - .send_xchar = dgap_tty_send_xchar -}; - - - - - -/************************************************************************ - * - * TTY Initialization/Cleanup Functions - * - ************************************************************************/ - -/* - * dgap_tty_preinit() - * - * Initialize any global tty related data before we download any boards. - */ -int dgap_tty_preinit(void) -{ - unsigned long flags; - - DGAP_LOCK(dgap_global_lock, flags); - - /* - * Allocate a buffer for doing the copy from user space to - * kernel space in dgap_input(). We only use one buffer and - * control access to it with a semaphore. If we are paging, we - * are already in trouble so one buffer won't hurt much anyway. - */ - dgap_TmpWriteBuf = kmalloc(WRITEBUFLEN, GFP_ATOMIC); - - if (!dgap_TmpWriteBuf) { - DGAP_UNLOCK(dgap_global_lock, flags); - DPR_INIT(("unable to allocate tmp write buf")); - return (-ENOMEM); - } - - DGAP_UNLOCK(dgap_global_lock, flags); - return(0); -} - - -/* - * dgap_tty_register() - * - * Init the tty subsystem for this board. - */ -int dgap_tty_register(struct board_t *brd) -{ - int rc = 0; - - DPR_INIT(("tty_register start")); - - brd->SerialDriver = alloc_tty_driver(MAXPORTS); - - snprintf(brd->SerialName, MAXTTYNAMELEN, "tty_dgap_%d_", brd->boardnum); - brd->SerialDriver->name = brd->SerialName; - brd->SerialDriver->name_base = 0; - brd->SerialDriver->major = 0; - brd->SerialDriver->minor_start = 0; - brd->SerialDriver->type = TTY_DRIVER_TYPE_SERIAL; - brd->SerialDriver->subtype = SERIAL_TYPE_NORMAL; - brd->SerialDriver->init_termios = DgapDefaultTermios; - brd->SerialDriver->driver_name = DRVSTR; - brd->SerialDriver->flags = (TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK); - - /* The kernel wants space to store pointers to tty_structs */ - brd->SerialDriver->ttys = kzalloc(MAXPORTS * sizeof(struct tty_struct *), GFP_KERNEL); - if (!brd->SerialDriver->ttys) - return(-ENOMEM); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) - brd->SerialDriver->refcount = brd->TtyRefCnt; -#endif - - /* - * Entry points for driver. Called by the kernel from - * tty_io.c and n_tty.c. - */ - tty_set_operations(brd->SerialDriver, &dgap_tty_ops); - - /* - * If we're doing transparent print, we have to do all of the above - * again, separately so we don't get the LD confused about what major - * we are when we get into the dgap_tty_open() routine. - */ - brd->PrintDriver = alloc_tty_driver(MAXPORTS); - - snprintf(brd->PrintName, MAXTTYNAMELEN, "pr_dgap_%d_", brd->boardnum); - brd->PrintDriver->name = brd->PrintName; - brd->PrintDriver->name_base = 0; - brd->PrintDriver->major = 0; - brd->PrintDriver->minor_start = 0; - brd->PrintDriver->type = TTY_DRIVER_TYPE_SERIAL; - brd->PrintDriver->subtype = SERIAL_TYPE_NORMAL; - brd->PrintDriver->init_termios = DgapDefaultTermios; - brd->PrintDriver->driver_name = DRVSTR; - brd->PrintDriver->flags = (TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK); - - /* The kernel wants space to store pointers to tty_structs */ - brd->PrintDriver->ttys = kzalloc(MAXPORTS * sizeof(struct tty_struct *), GFP_KERNEL); - if (!brd->PrintDriver->ttys) - return(-ENOMEM); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) - brd->PrintDriver->refcount = brd->TtyRefCnt; -#endif - - /* - * Entry points for driver. Called by the kernel from - * tty_io.c and n_tty.c. - */ - tty_set_operations(brd->PrintDriver, &dgap_tty_ops); - - if (!brd->dgap_Major_Serial_Registered) { - /* Register tty devices */ - rc = tty_register_driver(brd->SerialDriver); - if (rc < 0) { - APR(("Can't register tty device (%d)\n", rc)); - return(rc); - } - brd->dgap_Major_Serial_Registered = TRUE; - dgap_BoardsByMajor[brd->SerialDriver->major] = brd; - brd->dgap_Serial_Major = brd->SerialDriver->major; - } - - if (!brd->dgap_Major_TransparentPrint_Registered) { - /* Register Transparent Print devices */ - rc = tty_register_driver(brd->PrintDriver); - if (rc < 0) { - APR(("Can't register Transparent Print device (%d)\n", rc)); - return(rc); - } - brd->dgap_Major_TransparentPrint_Registered = TRUE; - dgap_BoardsByMajor[brd->PrintDriver->major] = brd; - brd->dgap_TransparentPrint_Major = brd->PrintDriver->major; - } - - DPR_INIT(("DGAP REGISTER TTY: MAJORS: %d %d\n", brd->SerialDriver->major, - brd->PrintDriver->major)); - - return (rc); -} - - -/* - * dgap_tty_init() - * - * Init the tty subsystem. Called once per board after board has been - * downloaded and init'ed. - */ -int dgap_tty_init(struct board_t *brd) -{ - int i; - int tlw; - uint true_count = 0; - uchar *vaddr; - uchar modem = 0; - struct channel_t *ch; - struct bs_t *bs; - struct cm_t *cm; - - if (!brd) - return (-ENXIO); - - DPR_INIT(("dgap_tty_init start\n")); - - /* - * Initialize board structure elements. - */ - - vaddr = brd->re_map_membase; - true_count = readw((vaddr + NCHAN)); - - brd->nasync = dgap_config_get_number_of_ports(brd); - - if (!brd->nasync) { - brd->nasync = brd->maxports; - } - - if (brd->nasync > brd->maxports) { - brd->nasync = brd->maxports; - } - - if (true_count != brd->nasync) { - if ((brd->type == PPCM) && (true_count == 64)) { - APR(("***WARNING**** %s configured for %d ports, has %d ports.\nPlease make SURE the EBI cable running from the card\nto each EM module is plugged into EBI IN!\n", - brd->name, brd->nasync, true_count)); - } - else if ((brd->type == PPCM) && (true_count == 0)) { - APR(("***WARNING**** %s configured for %d ports, has %d ports.\nPlease make SURE the EBI cable running from the card\nto each EM module is plugged into EBI IN!\n", - brd->name, brd->nasync, true_count)); - } - else { - APR(("***WARNING**** %s configured for %d ports, has %d ports.\n", - brd->name, brd->nasync, true_count)); - } - - brd->nasync = true_count; - - /* If no ports, don't bother going any further */ - if (!brd->nasync) { - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - return(-ENXIO); - } - } - - /* - * Allocate channel memory that might not have been allocated - * when the driver was first loaded. - */ - for (i = 0; i < brd->nasync; i++) { - if (!brd->channels[i]) { - brd->channels[i] = kzalloc(sizeof(struct channel_t), GFP_ATOMIC); - if (!brd->channels[i]) { - DPR_CORE(("%s:%d Unable to allocate memory for channel struct\n", - __FILE__, __LINE__)); - } - } - } - - ch = brd->channels[0]; - vaddr = brd->re_map_membase; - - bs = (struct bs_t *) ((ulong) vaddr + CHANBUF); - cm = (struct cm_t *) ((ulong) vaddr + CMDBUF); - - brd->bd_bs = bs; - - /* Set up channel variables */ - for (i = 0; i < brd->nasync; i++, ch = brd->channels[i], bs++) { - - if (!brd->channels[i]) - continue; - - DGAP_SPINLOCK_INIT(ch->ch_lock); - - /* Store all our magic numbers */ - ch->magic = DGAP_CHANNEL_MAGIC; - ch->ch_tun.magic = DGAP_UNIT_MAGIC; - ch->ch_tun.un_type = DGAP_SERIAL; - ch->ch_tun.un_ch = ch; - ch->ch_tun.un_dev = i; - - ch->ch_pun.magic = DGAP_UNIT_MAGIC; - ch->ch_pun.un_type = DGAP_PRINT; - ch->ch_pun.un_ch = ch; - ch->ch_pun.un_dev = i; - - ch->ch_vaddr = vaddr; - ch->ch_bs = bs; - ch->ch_cm = cm; - ch->ch_bd = brd; - ch->ch_portnum = i; - ch->ch_digi = dgap_digi_init; - - /* - * Set up digi dsr and dcd bits based on altpin flag. - */ - if (dgap_config_get_altpin(brd)) { - ch->ch_dsr = DM_CD; - ch->ch_cd = DM_DSR; - ch->ch_digi.digi_flags |= DIGI_ALTPIN; - } - else { - ch->ch_cd = DM_CD; - ch->ch_dsr = DM_DSR; - } - - ch->ch_taddr = vaddr + ((ch->ch_bs->tx_seg) << 4); - ch->ch_raddr = vaddr + ((ch->ch_bs->rx_seg) << 4); - ch->ch_tx_win = 0; - ch->ch_rx_win = 0; - ch->ch_tsize = readw(&(ch->ch_bs->tx_max)) + 1; - ch->ch_rsize = readw(&(ch->ch_bs->rx_max)) + 1; - ch->ch_tstart = 0; - ch->ch_rstart = 0; - - /* .25 second delay */ - ch->ch_close_delay = 250; - - /* - * Set queue water marks, interrupt mask, - * and general tty parameters. - */ - ch->ch_tlw = tlw = ch->ch_tsize >= 2000 ? ((ch->ch_tsize * 5) / 8) : ch->ch_tsize / 2; - - dgap_cmdw(ch, STLOW, tlw, 0); - - dgap_cmdw(ch, SRLOW, ch->ch_rsize / 2, 0); - - dgap_cmdw(ch, SRHIGH, 7 * ch->ch_rsize / 8, 0); - - ch->ch_mistat = readb(&(ch->ch_bs->m_stat)); - - init_waitqueue_head(&ch->ch_flags_wait); - init_waitqueue_head(&ch->ch_tun.un_flags_wait); - init_waitqueue_head(&ch->ch_pun.un_flags_wait); - init_waitqueue_head(&ch->ch_sniff_wait); - - /* Turn on all modem interrupts for now */ - modem = (DM_CD | DM_DSR | DM_CTS | DM_RI); - writeb(modem, &(ch->ch_bs->m_int)); - - /* - * Set edelay to 0 if interrupts are turned on, - * otherwise set edelay to the usual 100. - */ - if (brd->intr_used) - writew(0, &(ch->ch_bs->edelay)); - else - writew(100, &(ch->ch_bs->edelay)); - - writeb(1, &(ch->ch_bs->idata)); - } - - - DPR_INIT(("dgap_tty_init finish\n")); - - return (0); -} - - -/* - * dgap_tty_post_uninit() - * - * UnInitialize any global tty related data. - */ -void dgap_tty_post_uninit(void) -{ - kfree(dgap_TmpWriteBuf); - dgap_TmpWriteBuf = NULL; -} - - -/* - * dgap_tty_uninit() - * - * Uninitialize the TTY portion of this driver. Free all memory and - * resources. - */ -void dgap_tty_uninit(struct board_t *brd) -{ - int i = 0; - - if (brd->dgap_Major_Serial_Registered) { - dgap_BoardsByMajor[brd->SerialDriver->major] = NULL; - brd->dgap_Serial_Major = 0; - for (i = 0; i < brd->nasync; i++) { - dgap_remove_tty_sysfs(brd->channels[i]->ch_tun.un_sysfs); - tty_unregister_device(brd->SerialDriver, i); - } - tty_unregister_driver(brd->SerialDriver); - kfree(brd->SerialDriver->ttys); - brd->SerialDriver->ttys = NULL; - put_tty_driver(brd->SerialDriver); - brd->dgap_Major_Serial_Registered = FALSE; - } - - if (brd->dgap_Major_TransparentPrint_Registered) { - dgap_BoardsByMajor[brd->PrintDriver->major] = NULL; - brd->dgap_TransparentPrint_Major = 0; - for (i = 0; i < brd->nasync; i++) { - dgap_remove_tty_sysfs(brd->channels[i]->ch_pun.un_sysfs); - tty_unregister_device(brd->PrintDriver, i); - } - tty_unregister_driver(brd->PrintDriver); - kfree(brd->PrintDriver->ttys); - brd->PrintDriver->ttys = NULL; - put_tty_driver(brd->PrintDriver); - brd->dgap_Major_TransparentPrint_Registered = FALSE; - } -} - - -#define TMPBUFLEN (1024) - -/* - * dgap_sniff - Dump data out to the "sniff" buffer if the - * proc sniff file is opened... - */ -static void dgap_sniff_nowait_nolock(struct channel_t *ch, uchar *text, uchar *buf, int len) -{ - struct timeval tv; - int n; - int r; - int nbuf; - int i; - int tmpbuflen; - char tmpbuf[TMPBUFLEN]; - char *p = tmpbuf; - int too_much_data; - - /* Leave if sniff not open */ - if (!(ch->ch_sniff_flags & SNIFF_OPEN)) - return; - - do_gettimeofday(&tv); - - /* Create our header for data dump */ - p += sprintf(p, "<%ld %ld><%s><", tv.tv_sec, tv.tv_usec, text); - tmpbuflen = p - tmpbuf; - - do { - too_much_data = 0; - - for (i = 0; i < len && tmpbuflen < (TMPBUFLEN - 4); i++) { - p += sprintf(p, "%02x ", *buf); - buf++; - tmpbuflen = p - tmpbuf; - } - - if (tmpbuflen < (TMPBUFLEN - 4)) { - if (i > 0) - p += sprintf(p - 1, "%s\n", ">"); - else - p += sprintf(p, "%s\n", ">"); - } else { - too_much_data = 1; - len -= i; - } - - nbuf = strlen(tmpbuf); - p = tmpbuf; - - /* - * Loop while data remains. - */ - while (nbuf > 0 && ch->ch_sniff_buf) { - /* - * Determine the amount of available space left in the - * buffer. If there's none, wait until some appears. - */ - n = (ch->ch_sniff_out - ch->ch_sniff_in - 1) & SNIFF_MASK; - - /* - * If there is no space left to write to in our sniff buffer, - * we have no choice but to drop the data. - * We *cannot* sleep here waiting for space, because this - * function was probably called by the interrupt/timer routines! - */ - if (n == 0) { - return; - } - - /* - * Copy as much data as will fit. - */ - - if (n > nbuf) - n = nbuf; - - r = SNIFF_MAX - ch->ch_sniff_in; - - if (r <= n) { - memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, r); - - n -= r; - ch->ch_sniff_in = 0; - p += r; - nbuf -= r; - } - - memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, n); - - ch->ch_sniff_in += n; - p += n; - nbuf -= n; - - /* - * Wakeup any thread waiting for data - */ - if (ch->ch_sniff_flags & SNIFF_WAIT_DATA) { - ch->ch_sniff_flags &= ~SNIFF_WAIT_DATA; - wake_up_interruptible(&ch->ch_sniff_wait); - } - } - - /* - * If the user sent us too much data to push into our tmpbuf, - * we need to keep looping around on all the data. - */ - if (too_much_data) { - p = tmpbuf; - tmpbuflen = 0; - } - - } while (too_much_data); -} - - -/*======================================================================= - * - * dgap_input - Process received data. - * - * ch - Pointer to channel structure. - * - *=======================================================================*/ - -void dgap_input(struct channel_t *ch) -{ - struct board_t *bd; - struct bs_t *bs; - struct tty_struct *tp; - struct tty_ldisc *ld; - uint rmask; - uint head; - uint tail; - int data_len; - ulong lock_flags; - ulong lock_flags2; - int flip_len; - int len = 0; - int n = 0; - uchar *buf; - uchar tmpchar; - int s = 0; - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - tp = ch->ch_tun.un_tty; - - bs = ch->ch_bs; - if (!bs) { - return; - } - - bd = ch->ch_bd; - if(!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_READ(("dgap_input start\n")); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - /* - * Figure the number of characters in the buffer. - * Exit immediately if none. - */ - - rmask = ch->ch_rsize - 1; - - head = readw(&(bs->rx_head)); - head &= rmask; - tail = readw(&(bs->rx_tail)); - tail &= rmask; - - data_len = (head - tail) & rmask; - - if (data_len == 0) { - writeb(1, &(bs->idata)); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - DPR_READ(("No data on port %d\n", ch->ch_portnum)); - return; - } - - /* - * If the device is not open, or CREAD is off, flush - * input data and return immediately. - */ - if ((bd->state != BOARD_READY) || !tp || (tp->magic != TTY_MAGIC) || - !(ch->ch_tun.un_flags & UN_ISOPEN) || !(tp->termios.c_cflag & CREAD) || - (ch->ch_tun.un_flags & UN_CLOSING)) { - - DPR_READ(("input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum)); - DPR_READ(("input. tp: %p tp->magic: %x MAGIC:%x ch flags: %x\n", - tp, tp ? tp->magic : 0, TTY_MAGIC, ch->ch_tun.un_flags)); - writew(head, &(bs->rx_tail)); - writeb(1, &(bs->idata)); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return; - } - - /* - * If we are throttled, simply don't read any data. - */ - if (ch->ch_flags & CH_RXBLOCK) { - writeb(1, &(bs->idata)); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - DPR_READ(("Port %d throttled, not reading any data. head: %x tail: %x\n", - ch->ch_portnum, head, tail)); - return; - } - - /* - * Ignore oruns. - */ - tmpchar = readb(&(bs->orun)); - if (tmpchar) { - ch->ch_err_overrun++; - writeb(0, &(bs->orun)); - } - - DPR_READ(("dgap_input start 2\n")); - - /* Decide how much data we can send into the tty layer */ - flip_len = TTY_FLIPBUF_SIZE; - - /* Chop down the length, if needed */ - len = min(data_len, flip_len); - len = min(len, (N_TTY_BUF_SIZE - 1)); - - ld = tty_ldisc_ref(tp); - -#ifdef TTY_DONT_FLIP - /* - * If the DONT_FLIP flag is on, don't flush our buffer, and act - * like the ld doesn't have any space to put the data right now. - */ - if (test_bit(TTY_DONT_FLIP, &tp->flags)) - len = 0; -#endif - - /* - * If we were unable to get a reference to the ld, - * don't flush our buffer, and act like the ld doesn't - * have any space to put the data right now. - */ - if (!ld) { - len = 0; - } else { - /* - * If ld doesn't have a pointer to a receive_buf function, - * flush the data, then act like the ld doesn't have any - * space to put the data right now. - */ - if (!ld->ops->receive_buf) { - writew(head, &(bs->rx_tail)); - len = 0; - } - } - - if (len <= 0) { - writeb(1, &(bs->idata)); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - DPR_READ(("dgap_input 1 - finish\n")); - if (ld) - tty_ldisc_deref(ld); - return; - } - - buf = ch->ch_bd->flipbuf; - n = len; - - /* - * n now contains the most amount of data we can copy, - * bounded either by our buffer size or the amount - * of data the card actually has pending... - */ - while (n) { - - s = ((head >= tail) ? head : ch->ch_rsize) - tail; - s = min(s, n); - - if (s <= 0) - break; - - memcpy_fromio(buf, (char *) ch->ch_raddr + tail, s); - dgap_sniff_nowait_nolock(ch, "USER READ", buf, s); - - tail += s; - buf += s; - - n -= s; - /* Flip queue if needed */ - tail &= rmask; - } - - writew(tail, &(bs->rx_tail)); - writeb(1, &(bs->idata)); - ch->ch_rxcount += len; - - /* - * If we are completely raw, we don't need to go through a lot - * of the tty layers that exist. - * In this case, we take the shortest and fastest route we - * can to relay the data to the user. - * - * On the other hand, if we are not raw, we need to go through - * the tty layer, which has its API more well defined. - */ - if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { - dgap_parity_scan(ch, ch->ch_bd->flipbuf, ch->ch_bd->flipflagbuf, &len); - - len = tty_buffer_request_room(tp->port, len); - tty_insert_flip_string_flags(tp->port, ch->ch_bd->flipbuf, - ch->ch_bd->flipflagbuf, len); - } - else { - len = tty_buffer_request_room(tp->port, len); - tty_insert_flip_string(tp->port, ch->ch_bd->flipbuf, len); - } - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - /* Tell the tty layer its okay to "eat" the data now */ - tty_flip_buffer_push(tp->port); - - if (ld) - tty_ldisc_deref(ld); - - DPR_READ(("dgap_input - finish\n")); -} - - -/************************************************************************ - * Determines when CARRIER changes state and takes appropriate - * action. - ************************************************************************/ -void dgap_carrier(struct channel_t *ch) -{ - struct board_t *bd; - - int virt_carrier = 0; - int phys_carrier = 0; - - DPR_CARR(("dgap_carrier called...\n")); - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - /* Make sure altpin is always set correctly */ - if (ch->ch_digi.digi_flags & DIGI_ALTPIN) { - ch->ch_dsr = DM_CD; - ch->ch_cd = DM_DSR; - } - else { - ch->ch_dsr = DM_DSR; - ch->ch_cd = DM_CD; - } - - if (ch->ch_mistat & D_CD(ch)) { - DPR_CARR(("mistat: %x D_CD: %x\n", ch->ch_mistat, D_CD(ch))); - phys_carrier = 1; - } - - if (ch->ch_digi.digi_flags & DIGI_FORCEDCD) { - virt_carrier = 1; - } - - if (ch->ch_c_cflag & CLOCAL) { - virt_carrier = 1; - } - - - DPR_CARR(("DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier)); - - /* - * Test for a VIRTUAL carrier transition to HIGH. - */ - if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) { - - /* - * When carrier rises, wake any threads waiting - * for carrier in the open routine. - */ - - DPR_CARR(("carrier: virt DCD rose\n")); - - if (waitqueue_active(&(ch->ch_flags_wait))) - wake_up_interruptible(&ch->ch_flags_wait); - } - - /* - * Test for a PHYSICAL carrier transition to HIGH. - */ - if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) { - - /* - * When carrier rises, wake any threads waiting - * for carrier in the open routine. - */ - - DPR_CARR(("carrier: physical DCD rose\n")); - - if (waitqueue_active(&(ch->ch_flags_wait))) - wake_up_interruptible(&ch->ch_flags_wait); - } - - /* - * Test for a PHYSICAL transition to low, so long as we aren't - * currently ignoring physical transitions (which is what "virtual - * carrier" indicates). - * - * The transition of the virtual carrier to low really doesn't - * matter... it really only means "ignore carrier state", not - * "make pretend that carrier is there". - */ - if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0) && - (phys_carrier == 0)) - { - - /* - * When carrier drops: - * - * Drop carrier on all open units. - * - * Flush queues, waking up any task waiting in the - * line discipline. - * - * Send a hangup to the control terminal. - * - * Enable all select calls. - */ - if (waitqueue_active(&(ch->ch_flags_wait))) - wake_up_interruptible(&ch->ch_flags_wait); - - if (ch->ch_tun.un_open_count > 0) { - DPR_CARR(("Sending tty hangup\n")); - tty_hangup(ch->ch_tun.un_tty); - } - - if (ch->ch_pun.un_open_count > 0) { - DPR_CARR(("Sending pr hangup\n")); - tty_hangup(ch->ch_pun.un_tty); - } - } - - /* - * Make sure that our cached values reflect the current reality. - */ - if (virt_carrier == 1) - ch->ch_flags |= CH_FCAR; - else - ch->ch_flags &= ~CH_FCAR; - - if (phys_carrier == 1) - ch->ch_flags |= CH_CD; - else - ch->ch_flags &= ~CH_CD; -} - - -/************************************************************************ - * - * TTY Entry points and helper functions - * - ************************************************************************/ - -/* - * dgap_tty_open() - * - */ -static int dgap_tty_open(struct tty_struct *tty, struct file *file) -{ - struct board_t *brd; - struct channel_t *ch; - struct un_t *un; - struct bs_t *bs; - uint major = 0; - uint minor = 0; - int rc = 0; - ulong lock_flags; - ulong lock_flags2; - u16 head; - - rc = 0; - - major = MAJOR(tty_devnum(tty)); - minor = MINOR(tty_devnum(tty)); - - if (major > 255) { - return -ENXIO; - } - - /* Get board pointer from our array of majors we have allocated */ - brd = dgap_BoardsByMajor[major]; - if (!brd) { - return -ENXIO; - } - - /* - * If board is not yet up to a state of READY, go to - * sleep waiting for it to happen or they cancel the open. - */ - rc = wait_event_interruptible(brd->state_wait, - (brd->state & BOARD_READY)); - - if (rc) { - return rc; - } - - DGAP_LOCK(brd->bd_lock, lock_flags); - - /* The wait above should guarantee this cannot happen */ - if (brd->state != BOARD_READY) { - DGAP_UNLOCK(brd->bd_lock, lock_flags); - return -ENXIO; - } - - /* If opened device is greater than our number of ports, bail. */ - if (MINOR(tty_devnum(tty)) > brd->nasync) { - DGAP_UNLOCK(brd->bd_lock, lock_flags); - return -ENXIO; - } - - ch = brd->channels[minor]; - if (!ch) { - DGAP_UNLOCK(brd->bd_lock, lock_flags); - return -ENXIO; - } - - /* Grab channel lock */ - DGAP_LOCK(ch->ch_lock, lock_flags2); - - /* Figure out our type */ - if (major == brd->dgap_Serial_Major) { - un = &brd->channels[minor]->ch_tun; - un->un_type = DGAP_SERIAL; - } - else if (major == brd->dgap_TransparentPrint_Major) { - un = &brd->channels[minor]->ch_pun; - un->un_type = DGAP_PRINT; - } - else { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(brd->bd_lock, lock_flags); - DPR_OPEN(("%d Unknown TYPE!\n", __LINE__)); - return -ENXIO; - } - - /* Store our unit into driver_data, so we always have it available. */ - tty->driver_data = un; - - DPR_OPEN(("Open called. MAJOR: %d MINOR:%d unit: %p NAME: %s\n", - MAJOR(tty_devnum(tty)), MINOR(tty_devnum(tty)), un, brd->name)); - - /* - * Error if channel info pointer is NULL. - */ - bs = ch->ch_bs; - if (!bs) { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(brd->bd_lock, lock_flags); - DPR_OPEN(("%d BS is 0!\n", __LINE__)); - return -ENXIO; - } - - DPR_OPEN(("%d: tflag=%x pflag=%x\n", __LINE__, ch->ch_tun.un_flags, ch->ch_pun.un_flags)); - - /* - * Initialize tty's - */ - if (!(un->un_flags & UN_ISOPEN)) { - /* Store important variables. */ - un->un_tty = tty; - - /* Maybe do something here to the TTY struct as well? */ - } - - /* - * Initialize if neither terminal or printer is open. - */ - if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_ISOPEN)) { - - DPR_OPEN(("dgap_open: initializing channel in open...\n")); - - ch->ch_mforce = 0; - ch->ch_mval = 0; - - /* - * Flush input queue. - */ - head = readw(&(bs->rx_head)); - writew(head, &(bs->rx_tail)); - - ch->ch_flags = 0; - ch->pscan_state = 0; - ch->pscan_savechar = 0; - - ch->ch_c_cflag = tty->termios.c_cflag; - ch->ch_c_iflag = tty->termios.c_iflag; - ch->ch_c_oflag = tty->termios.c_oflag; - ch->ch_c_lflag = tty->termios.c_lflag; - ch->ch_startc = tty->termios.c_cc[VSTART]; - ch->ch_stopc = tty->termios.c_cc[VSTOP]; - - /* TODO: flush our TTY struct here? */ - } - - dgap_carrier(ch); - /* - * Run param in case we changed anything - */ - dgap_param(tty); - - /* - * follow protocol for opening port - */ - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(brd->bd_lock, lock_flags); - - rc = dgap_block_til_ready(tty, file, ch); - - if (!un->un_tty) { - return -ENODEV; - } - - if (rc) { - DPR_OPEN(("dgap_tty_open returning after dgap_block_til_ready " - "with %d\n", rc)); - } - - /* No going back now, increment our unit and channel counters */ - DGAP_LOCK(ch->ch_lock, lock_flags); - ch->ch_open_count++; - un->un_open_count++; - un->un_flags |= (UN_ISOPEN); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - DPR_OPEN(("dgap_tty_open finished\n")); - return (rc); -} - - -/* - * dgap_block_til_ready() - * - * Wait for DCD, if needed. - */ -static int dgap_block_til_ready(struct tty_struct *tty, struct file *file, struct channel_t *ch) -{ - int retval = 0; - struct un_t *un = NULL; - ulong lock_flags; - uint old_flags = 0; - int sleep_on_un_flags = 0; - - if (!tty || tty->magic != TTY_MAGIC || !file || !ch || ch->magic != DGAP_CHANNEL_MAGIC) { - return (-ENXIO); - } - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) { - return (-ENXIO); - } - - DPR_OPEN(("dgap_block_til_ready - before block.\n")); - - DGAP_LOCK(ch->ch_lock, lock_flags); - - ch->ch_wopen++; - - /* Loop forever */ - while (1) { - - sleep_on_un_flags = 0; - - /* - * If board has failed somehow during our sleep, bail with error. - */ - if (ch->ch_bd->state == BOARD_FAILED) { - retval = -ENXIO; - break; - } - - /* If tty was hung up, break out of loop and set error. */ - if (tty_hung_up_p(file)) { - retval = -EAGAIN; - break; - } - - /* - * If either unit is in the middle of the fragile part of close, - * we just cannot touch the channel safely. - * Go back to sleep, knowing that when the channel can be - * touched safely, the close routine will signal the - * ch_wait_flags to wake us back up. - */ - if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_CLOSING)) { - - /* - * Our conditions to leave cleanly and happily: - * 1) NONBLOCKING on the tty is set. - * 2) CLOCAL is set. - * 3) DCD (fake or real) is active. - */ - - if (file->f_flags & O_NONBLOCK) { - break; - } - - if (tty->flags & (1 << TTY_IO_ERROR)) { - break; - } - - if (ch->ch_flags & CH_CD) { - DPR_OPEN(("%d: ch_flags: %x\n", __LINE__, ch->ch_flags)); - break; - } - - if (ch->ch_flags & CH_FCAR) { - DPR_OPEN(("%d: ch_flags: %x\n", __LINE__, ch->ch_flags)); - break; - } - } - else { - sleep_on_un_flags = 1; - } - - /* - * If there is a signal pending, the user probably - * interrupted (ctrl-c) us. - * Leave loop with error set. - */ - if (signal_pending(current)) { - DPR_OPEN(("%d: signal pending...\n", __LINE__)); - retval = -ERESTARTSYS; - break; - } - - DPR_OPEN(("dgap_block_til_ready - blocking.\n")); - - /* - * Store the flags before we let go of channel lock - */ - if (sleep_on_un_flags) - old_flags = ch->ch_tun.un_flags | ch->ch_pun.un_flags; - else - old_flags = ch->ch_flags; - - /* - * Let go of channel lock before calling schedule. - * Our poller will get any FEP events and wake us up when DCD - * eventually goes active. - */ - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - DPR_OPEN(("Going to sleep on %s flags...\n", - (sleep_on_un_flags ? "un" : "ch"))); - - /* - * Wait for something in the flags to change from the current value. - */ - if (sleep_on_un_flags) { - retval = wait_event_interruptible(un->un_flags_wait, - (old_flags != (ch->ch_tun.un_flags | ch->ch_pun.un_flags))); - } - else { - retval = wait_event_interruptible(ch->ch_flags_wait, - (old_flags != ch->ch_flags)); - } - - DPR_OPEN(("After sleep... retval: %x\n", retval)); - - /* - * We got woken up for some reason. - * Before looping around, grab our channel lock. - */ - DGAP_LOCK(ch->ch_lock, lock_flags); - } - - ch->ch_wopen--; - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - DPR_OPEN(("dgap_block_til_ready - after blocking.\n")); - - if (retval) { - DPR_OPEN(("dgap_block_til_ready - done. error. retval: %x\n", retval)); - return(retval); - } - - DPR_OPEN(("dgap_block_til_ready - done no error. jiffies: %lu\n", jiffies)); - - return(0); -} - - -/* - * dgap_tty_hangup() - * - * Hangup the port. Like a close, but don't wait for output to drain. - */ -static void dgap_tty_hangup(struct tty_struct *tty) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_CLOSE(("dgap_hangup called. ch->ch_open_count: %d un->un_open_count: %d\n", - ch->ch_open_count, un->un_open_count)); - - /* flush the transmit queues */ - dgap_tty_flush_buffer(tty); - - DPR_CLOSE(("dgap_hangup finished. ch->ch_open_count: %d un->un_open_count: %d\n", - ch->ch_open_count, un->un_open_count)); -} - - - -/* - * dgap_tty_close() - * - */ -static void dgap_tty_close(struct tty_struct *tty, struct file *file) -{ - struct ktermios *ts; - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - ulong lock_flags; - int rc = 0; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - ts = &tty->termios; - - DPR_CLOSE(("Close called\n")); - - DGAP_LOCK(ch->ch_lock, lock_flags); - - /* - * Determine if this is the last close or not - and if we agree about - * which type of close it is with the Line Discipline - */ - if ((tty->count == 1) && (un->un_open_count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. un_open_count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - APR(("tty->count is 1, un open count is %d\n", un->un_open_count)); - un->un_open_count = 1; - } - - if (--un->un_open_count < 0) { - APR(("bad serial port open count of %d\n", un->un_open_count)); - un->un_open_count = 0; - } - - ch->ch_open_count--; - - if (ch->ch_open_count && un->un_open_count) { - DPR_CLOSE(("dgap_tty_close: not last close ch: %d un:%d\n", - ch->ch_open_count, un->un_open_count)); - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - return; - } - - /* OK, its the last close on the unit */ - DPR_CLOSE(("dgap_tty_close - last close on unit procedures\n")); - - un->un_flags |= UN_CLOSING; - - tty->closing = 1; - - /* - * Only officially close channel if count is 0 and - * DIGI_PRINTER bit is not set. - */ - if ((ch->ch_open_count == 0) && !(ch->ch_digi.digi_flags & DIGI_PRINTER)) { - - ch->ch_flags &= ~(CH_RXBLOCK); - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - /* wait for output to drain */ - /* This will also return if we take an interrupt */ - - DPR_CLOSE(("Calling wait_for_drain\n")); - rc = dgap_wait_for_drain(tty); - DPR_CLOSE(("After calling wait_for_drain\n")); - - if (rc) { - DPR_BASIC(("dgap_tty_close - bad return: %d ", rc)); - } - - dgap_tty_flush_buffer(tty); - tty_ldisc_flush(tty); - - DGAP_LOCK(ch->ch_lock, lock_flags); - - tty->closing = 0; - - /* - * If we have HUPCL set, lower DTR and RTS - */ - if (ch->ch_c_cflag & HUPCL ) { - DPR_CLOSE(("Close. HUPCL set, dropping DTR/RTS\n")); - ch->ch_mostat &= ~(D_RTS(ch)|D_DTR(ch)); - dgap_cmdb( ch, SMODEM, 0, D_DTR(ch)|D_RTS(ch), 0 ); - - /* - * Go to sleep to ensure RTS/DTR - * have been dropped for modems to see it. - */ - if (ch->ch_close_delay) { - DPR_CLOSE(("Close. Sleeping for RTS/DTR drop\n")); - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - dgap_ms_sleep(ch->ch_close_delay); - DGAP_LOCK(ch->ch_lock, lock_flags); - - DPR_CLOSE(("Close. After sleeping for RTS/DTR drop\n")); - } - } - - ch->pscan_state = 0; - ch->pscan_savechar = 0; - ch->ch_baud_info = 0; - - } - - /* - * turn off print device when closing print device. - */ - if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON) ) { - dgap_wmove(ch, ch->ch_digi.digi_offstr, - (int) ch->ch_digi.digi_offlen); - ch->ch_flags &= ~CH_PRON; - } - - un->un_tty = NULL; - un->un_flags &= ~(UN_ISOPEN | UN_CLOSING); - tty->driver_data = NULL; - - DPR_CLOSE(("Close. Doing wakeups\n")); - wake_up_interruptible(&ch->ch_flags_wait); - wake_up_interruptible(&un->un_flags_wait); - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - DPR_BASIC(("dgap_tty_close - complete\n")); -} - - -/* - * dgap_tty_chars_in_buffer() - * - * Return number of characters that have not been transmitted yet. - * - * This routine is used by the line discipline to determine if there - * is data waiting to be transmitted/drained/flushed or not. - */ -static int dgap_tty_chars_in_buffer(struct tty_struct *tty) -{ - struct board_t *bd = NULL; - struct channel_t *ch = NULL; - struct un_t *un = NULL; - struct bs_t *bs = NULL; - uchar tbusy; - uint chars = 0; - u16 thead, ttail, tmask, chead, ctail; - ulong lock_flags = 0; - ulong lock_flags2 = 0; - - if (tty == NULL) - return(0); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - - bs = ch->ch_bs; - if (!bs) - return (0); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - tmask = (ch->ch_tsize - 1); - - /* Get Transmit queue pointers */ - thead = readw(&(bs->tx_head)) & tmask; - ttail = readw(&(bs->tx_tail)) & tmask; - - /* Get tbusy flag */ - tbusy = readb(&(bs->tbusy)); - - /* Get Command queue pointers */ - chead = readw(&(ch->ch_cm->cm_head)); - ctail = readw(&(ch->ch_cm->cm_tail)); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - /* - * The only way we know for sure if there is no pending - * data left to be transferred, is if: - * 1) Transmit head and tail are equal (empty). - * 2) Command queue head and tail are equal (empty). - * 3) The "TBUSY" flag is 0. (Transmitter not busy). - */ - - if ((ttail == thead) && (tbusy == 0) && (chead == ctail)) { - chars = 0; - } - else { - if (thead >= ttail) - chars = thead - ttail; - else - chars = thead - ttail + ch->ch_tsize; - /* - * Fudge factor here. - * If chars is zero, we know that the command queue had - * something in it or tbusy was set. Because we cannot - * be sure if there is still some data to be transmitted, - * lets lie, and tell ld we have 1 byte left. - */ - if (chars == 0) { - /* - * If TBUSY is still set, and our tx buffers are empty, - * force the firmware to send me another wakeup after - * TBUSY has been cleared. - */ - if (tbusy != 0) { - DGAP_LOCK(ch->ch_lock, lock_flags); - un->un_flags |= UN_EMPTY; - writeb(1, &(bs->iempty)); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - } - chars = 1; - } - } - - DPR_WRITE(("dgap_tty_chars_in_buffer. Port: %x - %d (head: %d tail: %d tsize: %d)\n", - ch->ch_portnum, chars, thead, ttail, ch->ch_tsize)); - return(chars); -} - - -static int dgap_wait_for_drain(struct tty_struct *tty) -{ - struct channel_t *ch; - struct un_t *un; - struct bs_t *bs; - int ret = -EIO; - uint count = 1; - ulong lock_flags = 0; - - if (!tty || tty->magic != TTY_MAGIC) - return ret; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return ret; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return ret; - - bs = ch->ch_bs; - if (!bs) - return ret; - - ret = 0; - - DPR_DRAIN(("dgap_wait_for_drain start\n")); - - /* Loop until data is drained */ - while (count != 0) { - - count = dgap_tty_chars_in_buffer(tty); - - if (count == 0) - break; - - /* Set flag waiting for drain */ - DGAP_LOCK(ch->ch_lock, lock_flags); - un->un_flags |= UN_EMPTY; - writeb(1, &(bs->iempty)); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - /* Go to sleep till we get woken up */ - ret = wait_event_interruptible(un->un_flags_wait, ((un->un_flags & UN_EMPTY) == 0)); - /* If ret is non-zero, user ctrl-c'ed us */ - if (ret) { - break; - } - } - - DGAP_LOCK(ch->ch_lock, lock_flags); - un->un_flags &= ~(UN_EMPTY); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - DPR_DRAIN(("dgap_wait_for_drain finish\n")); - return (ret); -} - - -/* - * dgap_maxcps_room - * - * Reduces bytes_available to the max number of characters - * that can be sent currently given the maxcps value, and - * returns the new bytes_available. This only affects printer - * output. - */ -static int dgap_maxcps_room(struct tty_struct *tty, int bytes_available) -{ - struct channel_t *ch = NULL; - struct un_t *un = NULL; - - if (tty == NULL) - return (bytes_available); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (bytes_available); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (bytes_available); - - /* - * If its not the Transparent print device, return - * the full data amount. - */ - if (un->un_type != DGAP_PRINT) - return (bytes_available); - - if (ch->ch_digi.digi_maxcps > 0 && ch->ch_digi.digi_bufsize > 0 ) { - int cps_limit = 0; - unsigned long current_time = jiffies; - unsigned long buffer_time = current_time + - (HZ * ch->ch_digi.digi_bufsize) / ch->ch_digi.digi_maxcps; - - if (ch->ch_cpstime < current_time) { - /* buffer is empty */ - ch->ch_cpstime = current_time; /* reset ch_cpstime */ - cps_limit = ch->ch_digi.digi_bufsize; - } - else if (ch->ch_cpstime < buffer_time) { - /* still room in the buffer */ - cps_limit = ((buffer_time - ch->ch_cpstime) * ch->ch_digi.digi_maxcps) / HZ; - } - else { - /* no room in the buffer */ - cps_limit = 0; - } - - bytes_available = min(cps_limit, bytes_available); - } - - return (bytes_available); -} - - -static inline void dgap_set_firmware_event(struct un_t *un, unsigned int event) -{ - struct channel_t *ch = NULL; - struct bs_t *bs = NULL; - - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - bs = ch->ch_bs; - if (!bs) - return; - - if ((event & UN_LOW) != 0) { - if ((un->un_flags & UN_LOW) == 0) { - un->un_flags |= UN_LOW; - writeb(1, &(bs->ilow)); - } - } - if ((event & UN_LOW) != 0) { - if ((un->un_flags & UN_EMPTY) == 0) { - un->un_flags |= UN_EMPTY; - writeb(1, &(bs->iempty)); - } - } -} - - -/* - * dgap_tty_write_room() - * - * Return space available in Tx buffer - */ -static int dgap_tty_write_room(struct tty_struct *tty) -{ - struct channel_t *ch = NULL; - struct un_t *un = NULL; - struct bs_t *bs = NULL; - u16 head, tail, tmask; - int ret = 0; - ulong lock_flags = 0; - - if (tty == NULL || dgap_TmpWriteBuf == NULL) - return(0); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - - bs = ch->ch_bs; - if (!bs) - return (0); - - DGAP_LOCK(ch->ch_lock, lock_flags); - - tmask = ch->ch_tsize - 1; - head = readw(&(bs->tx_head)) & tmask; - tail = readw(&(bs->tx_tail)) & tmask; - - if ((ret = tail - head - 1) < 0) - ret += ch->ch_tsize; - - /* Limit printer to maxcps */ - ret = dgap_maxcps_room(tty, ret); - - /* - * If we are printer device, leave space for - * possibly both the on and off strings. - */ - if (un->un_type == DGAP_PRINT) { - if (!(ch->ch_flags & CH_PRON)) - ret -= ch->ch_digi.digi_onlen; - ret -= ch->ch_digi.digi_offlen; - } - else { - if (ch->ch_flags & CH_PRON) - ret -= ch->ch_digi.digi_offlen; - } - - if (ret < 0) - ret = 0; - - /* - * Schedule FEP to wake us up if needed. - * - * TODO: This might be overkill... - * Do we really need to schedule callbacks from the FEP - * in every case? Can we get smarter based on ret? - */ - dgap_set_firmware_event(un, UN_LOW | UN_EMPTY); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - DPR_WRITE(("dgap_tty_write_room - %d tail: %d head: %d\n", ret, tail, head)); - - return(ret); -} - - -/* - * dgap_tty_put_char() - * - * Put a character into ch->ch_buf - * - * - used by the line discipline for OPOST processing - */ -static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c) -{ - /* - * Simply call tty_write. - */ - DPR_WRITE(("dgap_tty_put_char called\n")); - dgap_tty_write(tty, &c, 1); - return 1; -} - - -/* - * dgap_tty_write() - * - * Take data from the user or kernel and send it out to the FEP. - * In here exists all the Transparent Print magic as well. - */ -static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) -{ - struct channel_t *ch = NULL; - struct un_t *un = NULL; - struct bs_t *bs = NULL; - char *vaddr = NULL; - u16 head, tail, tmask, remain; - int bufcount = 0, n = 0; - int orig_count = 0; - ulong lock_flags; - int from_user = 0; - - if (tty == NULL || dgap_TmpWriteBuf == NULL) - return(0); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return(0); - - bs = ch->ch_bs; - if (!bs) - return(0); - - if (!count) - return(0); - - DPR_WRITE(("dgap_tty_write: Port: %x tty=%p user=%d len=%d\n", - ch->ch_portnum, tty, from_user, count)); - - /* - * Store original amount of characters passed in. - * This helps to figure out if we should ask the FEP - * to send us an event when it has more space available. - */ - orig_count = count; - - DGAP_LOCK(ch->ch_lock, lock_flags); - - /* Get our space available for the channel from the board */ - tmask = ch->ch_tsize - 1; - head = readw(&(bs->tx_head)) & tmask; - tail = readw(&(bs->tx_tail)) & tmask; - - if ((bufcount = tail - head - 1) < 0) - bufcount += ch->ch_tsize; - - DPR_WRITE(("%d: bufcount: %x count: %x tail: %x head: %x tmask: %x\n", - __LINE__, bufcount, count, tail, head, tmask)); - - /* - * Limit printer output to maxcps overall, with bursts allowed - * up to bufsize characters. - */ - bufcount = dgap_maxcps_room(tty, bufcount); - - /* - * Take minimum of what the user wants to send, and the - * space available in the FEP buffer. - */ - count = min(count, bufcount); - - /* - * Bail if no space left. - */ - if (count <= 0) { - dgap_set_firmware_event(un, UN_LOW | UN_EMPTY); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - return(0); - } - - /* - * Output the printer ON string, if we are in terminal mode, but - * need to be in printer mode. - */ - if ((un->un_type == DGAP_PRINT) && !(ch->ch_flags & CH_PRON)) { - dgap_wmove(ch, ch->ch_digi.digi_onstr, - (int) ch->ch_digi.digi_onlen); - head = readw(&(bs->tx_head)) & tmask; - ch->ch_flags |= CH_PRON; - } - - /* - * On the other hand, output the printer OFF string, if we are - * currently in printer mode, but need to output to the terminal. - */ - if ((un->un_type != DGAP_PRINT) && (ch->ch_flags & CH_PRON)) { - dgap_wmove(ch, ch->ch_digi.digi_offstr, - (int) ch->ch_digi.digi_offlen); - head = readw(&(bs->tx_head)) & tmask; - ch->ch_flags &= ~CH_PRON; - } - - /* - * If there is nothing left to copy, or I can't handle any more data, leave. - */ - if (count <= 0) { - dgap_set_firmware_event(un, UN_LOW | UN_EMPTY); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - return(0); - } - - if (from_user) { - - count = min(count, WRITEBUFLEN); - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - /* - * If data is coming from user space, copy it into a temporary - * buffer so we don't get swapped out while doing the copy to - * the board. - */ - /* we're allowed to block if it's from_user */ - if (down_interruptible(&dgap_TmpWriteSem)) { - return (-EINTR); - } - - if (copy_from_user(dgap_TmpWriteBuf, (const uchar __user *) buf, count)) { - up(&dgap_TmpWriteSem); - printk("Write: Copy from user failed!\n"); - return -EFAULT; - } - - DGAP_LOCK(ch->ch_lock, lock_flags); - - buf = dgap_TmpWriteBuf; - } - - n = count; - - /* - * If the write wraps over the top of the circular buffer, - * move the portion up to the wrap point, and reset the - * pointers to the bottom. - */ - remain = ch->ch_tstart + ch->ch_tsize - head; - - if (n >= remain) { - n -= remain; - vaddr = ch->ch_taddr + head; - - memcpy_toio(vaddr, (uchar *) buf, remain); - dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *) buf, remain); - - head = ch->ch_tstart; - buf += remain; - } - - if (n > 0) { - - /* - * Move rest of data. - */ - vaddr = ch->ch_taddr + head; - remain = n; - - memcpy_toio(vaddr, (uchar *) buf, remain); - dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *) buf, remain); - - head += remain; - - } - - if (count) { - ch->ch_txcount += count; - head &= tmask; - writew(head, &(bs->tx_head)); - } - - - dgap_set_firmware_event(un, UN_LOW | UN_EMPTY); - - /* - * If this is the print device, and the - * printer is still on, we need to turn it - * off before going idle. If the buffer is - * non-empty, wait until it goes empty. - * Otherwise turn it off right now. - */ - if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON)) { - tail = readw(&(bs->tx_tail)) & tmask; - - if (tail != head) { - un->un_flags |= UN_EMPTY; - writeb(1, &(bs->iempty)); - } - else { - dgap_wmove(ch, ch->ch_digi.digi_offstr, - (int) ch->ch_digi.digi_offlen); - head = readw(&(bs->tx_head)) & tmask; - ch->ch_flags &= ~CH_PRON; - } - } - - /* Update printer buffer empty time. */ - if ((un->un_type == DGAP_PRINT) && (ch->ch_digi.digi_maxcps > 0) - && (ch->ch_digi.digi_bufsize > 0)) { - ch->ch_cpstime += (HZ * count) / ch->ch_digi.digi_maxcps; - } - - if (from_user) { - DGAP_UNLOCK(ch->ch_lock, lock_flags); - up(&dgap_TmpWriteSem); - } - else { - DGAP_UNLOCK(ch->ch_lock, lock_flags); - } - - DPR_WRITE(("Write finished - Write %d bytes of %d.\n", count, orig_count)); - - return (count); -} - - - -/* - * Return modem signals to ld. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) -static int dgap_tty_tiocmget(struct tty_struct *tty) -#else -static int dgap_tty_tiocmget(struct tty_struct *tty, struct file *file) -#endif -{ - struct channel_t *ch; - struct un_t *un; - int result = -EIO; - uchar mstat = 0; - ulong lock_flags; - - if (!tty || tty->magic != TTY_MAGIC) - return result; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return result; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return result; - - DPR_IOCTL(("dgap_tty_tiocmget start\n")); - - DGAP_LOCK(ch->ch_lock, lock_flags); - - mstat = readb(&(ch->ch_bs->m_stat)); - /* Append any outbound signals that might be pending... */ - mstat |= ch->ch_mostat; - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - result = 0; - - if (mstat & D_DTR(ch)) - result |= TIOCM_DTR; - if (mstat & D_RTS(ch)) - result |= TIOCM_RTS; - if (mstat & D_CTS(ch)) - result |= TIOCM_CTS; - if (mstat & D_DSR(ch)) - result |= TIOCM_DSR; - if (mstat & D_RI(ch)) - result |= TIOCM_RI; - if (mstat & D_CD(ch)) - result |= TIOCM_CD; - - DPR_IOCTL(("dgap_tty_tiocmget finish\n")); - - return result; -} - - -/* - * dgap_tty_tiocmset() - * - * Set modem signals, called by ld. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) -static int dgap_tty_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -#else -static int dgap_tty_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) -#endif -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - int ret = -EIO; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return ret; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return ret; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return ret; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return ret; - - DPR_IOCTL(("dgap_tty_tiocmset start\n")); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - if (set & TIOCM_RTS) { - ch->ch_mforce |= D_RTS(ch); - ch->ch_mval |= D_RTS(ch); - } - - if (set & TIOCM_DTR) { - ch->ch_mforce |= D_DTR(ch); - ch->ch_mval |= D_DTR(ch); - } - - if (clear & TIOCM_RTS) { - ch->ch_mforce |= D_RTS(ch); - ch->ch_mval &= ~(D_RTS(ch)); - } - - if (clear & TIOCM_DTR) { - ch->ch_mforce |= D_DTR(ch); - ch->ch_mval &= ~(D_DTR(ch)); - } - - dgap_param(tty); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_tiocmset finish\n")); - - return (0); -} - - - -/* - * dgap_tty_send_break() - * - * Send a Break, called by ld. - */ -static int dgap_tty_send_break(struct tty_struct *tty, int msec) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - int ret = -EIO; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return ret; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return ret; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return ret; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return ret; - - switch (msec) { - case -1: - msec = 0xFFFF; - break; - case 0: - msec = 1; - break; - default: - msec /= 10; - break; - } - - DPR_IOCTL(("dgap_tty_send_break start 1. %lx\n", jiffies)); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); -#if 0 - dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0); -#endif - dgap_cmdw(ch, SBREAK, (u16) msec, 0); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_send_break finish\n")); - - return (0); -} - - - - -/* - * dgap_tty_wait_until_sent() - * - * wait until data has been transmitted, called by ld. - */ -static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout) -{ - int rc; - rc = dgap_wait_for_drain(tty); - if (rc) { - DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc)); - return; - } - return; -} - - - -/* - * dgap_send_xchar() - * - * send a high priority character, called by ld. - */ -static void dgap_tty_send_xchar(struct tty_struct *tty, char c) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_IOCTL(("dgap_tty_send_xchar start 1. %lx\n", jiffies)); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - /* - * This is technically what we should do. - * However, the NIST tests specifically want - * to see each XON or XOFF character that it - * sends, so lets just send each character - * by hand... - */ -#if 0 - if (c == STOP_CHAR(tty)) { - dgap_cmdw(ch, RPAUSE, 0, 0); - } - else if (c == START_CHAR(tty)) { - dgap_cmdw(ch, RRESUME, 0, 0); - } - else { - dgap_wmove(ch, &c, 1); - } -#else - dgap_wmove(ch, &c, 1); -#endif - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_send_xchar finish\n")); - - return; -} - - - - -/* - * Return modem signals to ld. - */ -static int dgap_get_modem_info(struct channel_t *ch, unsigned int __user *value) -{ - int result = 0; - uchar mstat = 0; - ulong lock_flags; - int rc = 0; - - DPR_IOCTL(("dgap_get_modem_info start\n")); - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return(-ENXIO); - - DGAP_LOCK(ch->ch_lock, lock_flags); - - mstat = readb(&(ch->ch_bs->m_stat)); - /* Append any outbound signals that might be pending... */ - mstat |= ch->ch_mostat; - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - result = 0; - - if (mstat & D_DTR(ch)) - result |= TIOCM_DTR; - if (mstat & D_RTS(ch)) - result |= TIOCM_RTS; - if (mstat & D_CTS(ch)) - result |= TIOCM_CTS; - if (mstat & D_DSR(ch)) - result |= TIOCM_DSR; - if (mstat & D_RI(ch)) - result |= TIOCM_RI; - if (mstat & D_CD(ch)) - result |= TIOCM_CD; - - rc = put_user(result, value); - - DPR_IOCTL(("dgap_get_modem_info finish\n")); - return(rc); -} - - -/* - * dgap_set_modem_info() - * - * Set modem signals, called by ld. - */ -static int dgap_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - int ret = -ENXIO; - unsigned int arg = 0; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return ret; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return ret; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return ret; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return ret; - - DPR_IOCTL(("dgap_set_modem_info() start\n")); - - ret = get_user(arg, value); - if (ret) { - DPR_IOCTL(("dgap_set_modem_info %d ret: %x. finished.\n", __LINE__, ret)); - return(ret); - } - - DPR_IOCTL(("dgap_set_modem_info: command: %x arg: %x\n", command, arg)); - - switch (command) { - case TIOCMBIS: - if (arg & TIOCM_RTS) { - ch->ch_mforce |= D_RTS(ch); - ch->ch_mval |= D_RTS(ch); - } - - if (arg & TIOCM_DTR) { - ch->ch_mforce |= D_DTR(ch); - ch->ch_mval |= D_DTR(ch); - } - - break; - - case TIOCMBIC: - if (arg & TIOCM_RTS) { - ch->ch_mforce |= D_RTS(ch); - ch->ch_mval &= ~(D_RTS(ch)); - } - - if (arg & TIOCM_DTR) { - ch->ch_mforce |= D_DTR(ch); - ch->ch_mval &= ~(D_DTR(ch)); - } - - break; - - case TIOCMSET: - ch->ch_mforce = D_DTR(ch)|D_RTS(ch); - - if (arg & TIOCM_RTS) { - ch->ch_mval |= D_RTS(ch); - } - else { - ch->ch_mval &= ~(D_RTS(ch)); - } - - if (arg & TIOCM_DTR) { - ch->ch_mval |= (D_DTR(ch)); - } - else { - ch->ch_mval &= ~(D_DTR(ch)); - } - - break; - - default: - return(-EINVAL); - } - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - dgap_param(tty); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_set_modem_info finish\n")); - - return (0); -} - - -/* - * dgap_tty_digigeta() - * - * Ioctl to get the information for ditty. - * - * - * - */ -static int dgap_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo) -{ - struct channel_t *ch; - struct un_t *un; - struct digi_t tmp; - ulong lock_flags; - - if (!retinfo) - return (-EFAULT); - - if (!tty || tty->magic != TTY_MAGIC) - return (-EFAULT); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (-EFAULT); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (-EFAULT); - - memset(&tmp, 0, sizeof(tmp)); - - DGAP_LOCK(ch->ch_lock, lock_flags); - memcpy(&tmp, &ch->ch_digi, sizeof(tmp)); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return (-EFAULT); - - return (0); -} - - -/* - * dgap_tty_digiseta() - * - * Ioctl to set the information for ditty. - * - * - * - */ -static int dgap_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - struct digi_t new_digi; - ulong lock_flags = 0; - unsigned long lock_flags2; - - DPR_IOCTL(("DIGI_SETA start\n")); - - if (!tty || tty->magic != TTY_MAGIC) - return (-EFAULT); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (-EFAULT); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (-EFAULT); - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (-EFAULT); - - if (copy_from_user(&new_digi, new_info, sizeof(struct digi_t))) { - DPR_IOCTL(("DIGI_SETA failed copy_from_user\n")); - return(-EFAULT); - } - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - memcpy(&ch->ch_digi, &new_digi, sizeof(struct digi_t)); - - if (ch->ch_digi.digi_maxcps < 1) - ch->ch_digi.digi_maxcps = 1; - - if (ch->ch_digi.digi_maxcps > 10000) - ch->ch_digi.digi_maxcps = 10000; - - if (ch->ch_digi.digi_bufsize < 10) - ch->ch_digi.digi_bufsize = 10; - - if (ch->ch_digi.digi_maxchar < 1) - ch->ch_digi.digi_maxchar = 1; - - if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize) - ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize; - - if (ch->ch_digi.digi_onlen > DIGI_PLEN) - ch->ch_digi.digi_onlen = DIGI_PLEN; - - if (ch->ch_digi.digi_offlen > DIGI_PLEN) - ch->ch_digi.digi_offlen = DIGI_PLEN; - - dgap_param(tty); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("DIGI_SETA finish\n")); - - return(0); -} - - -/* - * dgap_tty_digigetedelay() - * - * Ioctl to get the current edelay setting. - * - * - * - */ -static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo) -{ - struct channel_t *ch; - struct un_t *un; - int tmp; - ulong lock_flags; - - if (!retinfo) - return (-EFAULT); - - if (!tty || tty->magic != TTY_MAGIC) - return (-EFAULT); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (-EFAULT); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (-EFAULT); - - memset(&tmp, 0, sizeof(tmp)); - - DGAP_LOCK(ch->ch_lock, lock_flags); - tmp = readw(&(ch->ch_bs->edelay)); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return (-EFAULT); - - return (0); -} - - -/* - * dgap_tty_digisetedelay() - * - * Ioctl to set the EDELAY setting - * - */ -static int dgap_tty_digisetedelay(struct tty_struct *tty, int __user *new_info) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - int new_digi; - ulong lock_flags; - ulong lock_flags2; - - DPR_IOCTL(("DIGI_SETA start\n")); - - if (!tty || tty->magic != TTY_MAGIC) - return (-EFAULT); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (-EFAULT); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (-EFAULT); - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (-EFAULT); - - if (copy_from_user(&new_digi, new_info, sizeof(int))) { - DPR_IOCTL(("DIGI_SETEDELAY failed copy_from_user\n")); - return(-EFAULT); - } - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - writew((u16) new_digi, &(ch->ch_bs->edelay)); - - dgap_param(tty); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("DIGI_SETA finish\n")); - - return(0); -} - - -/* - * dgap_tty_digigetcustombaud() - * - * Ioctl to get the current custom baud rate setting. - */ -static int dgap_tty_digigetcustombaud(struct tty_struct *tty, int __user *retinfo) -{ - struct channel_t *ch; - struct un_t *un; - int tmp; - ulong lock_flags; - - if (!retinfo) - return (-EFAULT); - - if (!tty || tty->magic != TTY_MAGIC) - return (-EFAULT); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (-EFAULT); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (-EFAULT); - - memset(&tmp, 0, sizeof(tmp)); - - DGAP_LOCK(ch->ch_lock, lock_flags); - tmp = dgap_get_custom_baud(ch); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - DPR_IOCTL(("DIGI_GETCUSTOMBAUD. Returning %d\n", tmp)); - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return (-EFAULT); - - return (0); -} - - -/* - * dgap_tty_digisetcustombaud() - * - * Ioctl to set the custom baud rate setting - */ -static int dgap_tty_digisetcustombaud(struct tty_struct *tty, int __user *new_info) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - uint new_rate; - ulong lock_flags; - ulong lock_flags2; - - DPR_IOCTL(("DIGI_SETCUSTOMBAUD start\n")); - - if (!tty || tty->magic != TTY_MAGIC) - return (-EFAULT); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (-EFAULT); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (-EFAULT); - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (-EFAULT); - - - if (copy_from_user(&new_rate, new_info, sizeof(unsigned int))) { - DPR_IOCTL(("DIGI_SETCUSTOMBAUD failed copy_from_user\n")); - return(-EFAULT); - } - - if (bd->bd_flags & BD_FEP5PLUS) { - - DPR_IOCTL(("DIGI_SETCUSTOMBAUD. Setting %d\n", new_rate)); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - ch->ch_custom_speed = new_rate; - - dgap_param(tty); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - } - - DPR_IOCTL(("DIGI_SETCUSTOMBAUD finish\n")); - - return(0); -} - - -/* - * dgap_set_termios() - */ -static void dgap_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - unsigned long lock_flags; - unsigned long lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - ch->ch_c_cflag = tty->termios.c_cflag; - ch->ch_c_iflag = tty->termios.c_iflag; - ch->ch_c_oflag = tty->termios.c_oflag; - ch->ch_c_lflag = tty->termios.c_lflag; - ch->ch_startc = tty->termios.c_cc[VSTART]; - ch->ch_stopc = tty->termios.c_cc[VSTOP]; - - dgap_carrier(ch); - dgap_param(tty); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); -} - - -static void dgap_tty_throttle(struct tty_struct *tty) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_IOCTL(("dgap_tty_throttle start\n")); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - ch->ch_flags |= (CH_RXBLOCK); -#if 1 - dgap_cmdw(ch, RPAUSE, 0, 0); -#endif - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_throttle finish\n")); -} - - -static void dgap_tty_unthrottle(struct tty_struct *tty) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_IOCTL(("dgap_tty_unthrottle start\n")); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - ch->ch_flags &= ~(CH_RXBLOCK); - -#if 1 - dgap_cmdw(ch, RRESUME, 0, 0); -#endif - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_unthrottle finish\n")); -} - - -static void dgap_tty_start(struct tty_struct *tty) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_IOCTL(("dgap_tty_start start\n")); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - dgap_cmdw(ch, RESUMETX, 0, 0); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_start finish\n")); -} - - -static void dgap_tty_stop(struct tty_struct *tty) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_IOCTL(("dgap_tty_stop start\n")); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - dgap_cmdw(ch, PAUSETX, 0, 0); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_stop finish\n")); -} - - -/* - * dgap_tty_flush_chars() - * - * Flush the cook buffer - * - * Note to self, and any other poor souls who venture here: - * - * flush in this case DOES NOT mean dispose of the data. - * instead, it means "stop buffering and send it if you - * haven't already." Just guess how I figured that out... SRW 2-Jun-98 - * - * It is also always called in interrupt context - JAR 8-Sept-99 - */ -static void dgap_tty_flush_chars(struct tty_struct *tty) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_IOCTL(("dgap_tty_flush_chars start\n")); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - /* TODO: Do something here */ - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_flush_chars finish\n")); -} - - - -/* - * dgap_tty_flush_buffer() - * - * Flush Tx buffer (make in == out) - */ -static void dgap_tty_flush_buffer(struct tty_struct *tty) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - ulong lock_flags; - ulong lock_flags2; - u16 head = 0; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_IOCTL(("dgap_tty_flush_buffer on port: %d start\n", ch->ch_portnum)); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - ch->ch_flags &= ~CH_STOP; - head = readw(&(ch->ch_bs->tx_head)); - dgap_cmdw(ch, FLUSHTX, (u16) head, 0); - dgap_cmdw(ch, RESUMETX, 0, 0); - if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) { - ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY); - wake_up_interruptible(&ch->ch_tun.un_flags_wait); - } - if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) { - ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY); - wake_up_interruptible(&ch->ch_pun.un_flags_wait); - } - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - if (waitqueue_active(&tty->write_wait)) - wake_up_interruptible(&tty->write_wait); - tty_wakeup(tty); - - DPR_IOCTL(("dgap_tty_flush_buffer finish\n")); -} - - - -/***************************************************************************** - * - * The IOCTL function and all of its helpers - * - *****************************************************************************/ - -/* - * dgap_tty_ioctl() - * - * The usual assortment of ioctl's - */ -static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd, - unsigned long arg) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - int rc; - u16 head = 0; - ulong lock_flags = 0; - ulong lock_flags2 = 0; - void __user *uarg = (void __user *) arg; - - if (!tty || tty->magic != TTY_MAGIC) - return (-ENODEV); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (-ENODEV); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (-ENODEV); - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (-ENODEV); - - DPR_IOCTL(("dgap_tty_ioctl start on port %d - cmd %s (%x), arg %lx\n", - ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg)); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - if (un->un_open_count <= 0) { - DPR_BASIC(("dgap_tty_ioctl - unit not open.\n")); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(-EIO); - } - - switch (cmd) { - - /* Here are all the standard ioctl's that we MUST implement */ - - case TCSBRK: - /* - * TCSBRK is SVID version: non-zero arg --> no break - * this behaviour is exploited by tcdrain(). - * - * According to POSIX.1 spec (7.2.2.1.2) breaks should be - * between 0.25 and 0.5 seconds so we'll ask for something - * in the middle: 0.375 seconds. - */ - rc = tty_check_change(tty); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - if (rc) { - return(rc); - } - - rc = dgap_wait_for_drain(tty); - - if (rc) { - DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); - } - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - if(((cmd == TCSBRK) && (!arg)) || (cmd == TCSBRKP)) { - dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0); - } - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n", - ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg)); - - return(0); - - - case TCSBRKP: - /* support for POSIX tcsendbreak() - - * According to POSIX.1 spec (7.2.2.1.2) breaks should be - * between 0.25 and 0.5 seconds so we'll ask for something - * in the middle: 0.375 seconds. - */ - rc = tty_check_change(tty); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - if (rc) { - return(rc); - } - - rc = dgap_wait_for_drain(tty); - if (rc) { - DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); - } - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n", - ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg)); - - return(0); - - case TIOCSBRK: - /* - * FEP5 doesn't support turning on a break unconditionally. - * The FEP5 device will stop sending a break automatically - * after the specified time value that was sent when turning on - * the break. - */ - rc = tty_check_change(tty); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - if (rc) { - return(rc); - } - - rc = dgap_wait_for_drain(tty); - if (rc) { - DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); - } - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n", - ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg)); - - return 0; - - case TIOCCBRK: - /* - * FEP5 doesn't support turning off a break unconditionally. - * The FEP5 device will stop sending a break automatically - * after the specified time value that was sent when turning on - * the break. - */ - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return 0; - - case TIOCGSOFTCAR: - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) arg); - return(rc); - - case TIOCSSOFTCAR: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - rc = get_user(arg, (unsigned long __user *) arg); - if (rc) - return(rc); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - tty->termios.c_cflag = ((tty->termios.c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); - dgap_param(tty); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - return(0); - - case TIOCMGET: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(dgap_get_modem_info(ch, uarg)); - - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(dgap_set_modem_info(tty, cmd, uarg)); - - /* - * Here are any additional ioctl's that we want to implement - */ - - case TCFLSH: - /* - * The linux tty driver doesn't have a flush - * input routine for the driver, assuming all backed - * up data is in the line disc. buffers. However, - * we all know that's not the case. Here, we - * act on the ioctl, but then lie and say we didn't - * so the line discipline will process the flush - * also. - */ - rc = tty_check_change(tty); - if (rc) { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(rc); - } - - if ((arg == TCIFLUSH) || (arg == TCIOFLUSH)) { - if (!(un->un_type == DGAP_PRINT)) { - head = readw(&(ch->ch_bs->rx_head)); - writew(head, &(ch->ch_bs->rx_tail)); - writeb(0, &(ch->ch_bs->orun)); - } - } - - if ((arg == TCOFLUSH) || (arg == TCIOFLUSH)) { - ch->ch_flags &= ~CH_STOP; - head = readw(&(ch->ch_bs->tx_head)); - dgap_cmdw(ch, FLUSHTX, (u16) head, 0 ); - dgap_cmdw(ch, RESUMETX, 0, 0); - if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) { - ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY); - wake_up_interruptible(&ch->ch_tun.un_flags_wait); - } - if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) { - ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY); - wake_up_interruptible(&ch->ch_pun.un_flags_wait); - } - if (waitqueue_active(&tty->write_wait)) - wake_up_interruptible(&tty->write_wait); - - /* Can't hold any locks when calling tty_wakeup! */ - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - tty_wakeup(tty); - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - } - - /* pretend we didn't recognize this IOCTL */ - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_ioctl (LINE:%d) finish on port %d - cmd %s (%x), arg %lx\n", - __LINE__, ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg)); - - return(-ENOIOCTLCMD); - - case TCSETSF: - case TCSETSW: - /* - * The linux tty driver doesn't have a flush - * input routine for the driver, assuming all backed - * up data is in the line disc. buffers. However, - * we all know that's not the case. Here, we - * act on the ioctl, but then lie and say we didn't - * so the line discipline will process the flush - * also. - */ - if (cmd == TCSETSF) { - /* flush rx */ - ch->ch_flags &= ~CH_STOP; - head = readw(&(ch->ch_bs->rx_head)); - writew(head, &(ch->ch_bs->rx_tail)); - } - - /* now wait for all the output to drain */ - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - rc = dgap_wait_for_drain(tty); - if (rc) { - DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); - } - - DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n", - ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg)); - - /* pretend we didn't recognize this */ - return(-ENOIOCTLCMD); - - case TCSETAW: - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - rc = dgap_wait_for_drain(tty); - if (rc) { - DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); - } - - /* pretend we didn't recognize this */ - return(-ENOIOCTLCMD); - - case TCXONC: - /* - * The Linux Line Discipline (LD) would do this for us if we - * let it, but we have the special firmware options to do this - * the "right way" regardless of hardware or software flow - * control so we'll do it outselves instead of letting the LD - * do it. - */ - rc = tty_check_change(tty); - if (rc) { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(rc); - } - - DPR_IOCTL(("dgap_ioctl - in TCXONC - %d\n", cmd)); - switch (arg) { - - case TCOON: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - dgap_tty_start(tty); - return(0); - case TCOOFF: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - dgap_tty_stop(tty); - return(0); - case TCION: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - /* Make the ld do it */ - return(-ENOIOCTLCMD); - case TCIOFF: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - /* Make the ld do it */ - return(-ENOIOCTLCMD); - default: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(-EINVAL); - } - - case DIGI_GETA: - /* get information for ditty */ - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(dgap_tty_digigeta(tty, uarg)); - - case DIGI_SETAW: - case DIGI_SETAF: - - /* set information for ditty */ - if (cmd == (DIGI_SETAW)) { - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - rc = dgap_wait_for_drain(tty); - if (rc) { - DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); - } - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - } - else { - tty_ldisc_flush(tty); - } - /* fall thru */ - - case DIGI_SETA: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(dgap_tty_digiseta(tty, uarg)); - - case DIGI_GEDELAY: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(dgap_tty_digigetedelay(tty, uarg)); - - case DIGI_SEDELAY: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(dgap_tty_digisetedelay(tty, uarg)); - - case DIGI_GETCUSTOMBAUD: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(dgap_tty_digigetcustombaud(tty, uarg)); - - case DIGI_SETCUSTOMBAUD: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(dgap_tty_digisetcustombaud(tty, uarg)); - - case DIGI_RESET_PORT: - dgap_firmware_reset_port(ch); - dgap_param(tty); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return 0; - - default: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_ioctl - in default\n")); - DPR_IOCTL(("dgap_tty_ioctl end - cmd %s (%x), arg %lx\n", - dgap_ioctl_name(cmd), cmd, arg)); - - return(-ENOIOCTLCMD); - } -} diff --git a/drivers/staging/dgap/dgap_tty.h b/drivers/staging/dgap/dgap_tty.h deleted file mode 100644 index 464a460b6be8..000000000000 --- a/drivers/staging/dgap/dgap_tty.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - */ - -#ifndef __DGAP_TTY_H -#define __DGAP_TTY_H - -#include "dgap_driver.h" - -int dgap_tty_register(struct board_t *brd); - -int dgap_tty_preinit(void); -int dgap_tty_init(struct board_t *); - -void dgap_tty_post_uninit(void); -void dgap_tty_uninit(struct board_t *); - -void dgap_carrier(struct channel_t *ch); -void dgap_input(struct channel_t *ch); - - -#endif diff --git a/drivers/staging/dgap/dgap_types.h b/drivers/staging/dgap/dgap_types.h deleted file mode 100644 index eca38c7f359d..000000000000 --- a/drivers/staging/dgap/dgap_types.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - */ - -#ifndef __DGAP_TYPES_H -#define __DGAP_TYPES_H - -#ifndef TRUE -# define TRUE 1 -#endif - -#ifndef FALSE -# define FALSE 0 -#endif - -/* Required for our shared headers! */ -typedef unsigned char uchar; - -#endif diff --git a/drivers/staging/dgap/digi.h b/drivers/staging/dgap/digi.h deleted file mode 100644 index bcea4f734a32..000000000000 --- a/drivers/staging/dgap/digi.h +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: digi.h,v 1.1 2009/10/23 14:01:57 markh Exp $ - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - */ - -#ifndef __DIGI_H -#define __DIGI_H - -/************************************************************************ - *** Definitions for Digi ditty(1) command. - ************************************************************************/ - - -/* - * Copyright (c) 1988-96 Digi International Inc., All Rights Reserved. - */ - -/************************************************************************ - * This module provides application access to special Digi - * serial line enhancements which are not standard UNIX(tm) features. - ************************************************************************/ - -#if !defined(TIOCMODG) - -#define TIOCMODG ('d'<<8) | 250 /* get modem ctrl state */ -#define TIOCMODS ('d'<<8) | 251 /* set modem ctrl state */ - -#ifndef TIOCM_LE -#define TIOCM_LE 0x01 /* line enable */ -#define TIOCM_DTR 0x02 /* data terminal ready */ -#define TIOCM_RTS 0x04 /* request to send */ -#define TIOCM_ST 0x08 /* secondary transmit */ -#define TIOCM_SR 0x10 /* secondary receive */ -#define TIOCM_CTS 0x20 /* clear to send */ -#define TIOCM_CAR 0x40 /* carrier detect */ -#define TIOCM_RNG 0x80 /* ring indicator */ -#define TIOCM_DSR 0x100 /* data set ready */ -#define TIOCM_RI TIOCM_RNG /* ring (alternate) */ -#define TIOCM_CD TIOCM_CAR /* carrier detect (alt) */ -#endif - -#endif - -#if !defined(TIOCMSET) -#define TIOCMSET ('d'<<8) | 252 /* set modem ctrl state */ -#define TIOCMGET ('d'<<8) | 253 /* set modem ctrl state */ -#endif - -#if !defined(TIOCMBIC) -#define TIOCMBIC ('d'<<8) | 254 /* set modem ctrl state */ -#define TIOCMBIS ('d'<<8) | 255 /* set modem ctrl state */ -#endif - - -#if !defined(TIOCSDTR) -#define TIOCSDTR ('e'<<8) | 0 /* set DTR */ -#define TIOCCDTR ('e'<<8) | 1 /* clear DTR */ -#endif - -/************************************************************************ - * Ioctl command arguments for DIGI parameters. - ************************************************************************/ -#define DIGI_GETA ('e'<<8) | 94 /* Read params */ - -#define DIGI_SETA ('e'<<8) | 95 /* Set params */ -#define DIGI_SETAW ('e'<<8) | 96 /* Drain & set params */ -#define DIGI_SETAF ('e'<<8) | 97 /* Drain, flush & set params */ - -#define DIGI_KME ('e'<<8) | 98 /* Read/Write Host */ - /* Adapter Memory */ - -#define DIGI_GETFLOW ('e'<<8) | 99 /* Get startc/stopc flow */ - /* control characters */ -#define DIGI_SETFLOW ('e'<<8) | 100 /* Set startc/stopc flow */ - /* control characters */ -#define DIGI_GETAFLOW ('e'<<8) | 101 /* Get Aux. startc/stopc */ - /* flow control chars */ -#define DIGI_SETAFLOW ('e'<<8) | 102 /* Set Aux. startc/stopc */ - /* flow control chars */ - -#define DIGI_GEDELAY ('d'<<8) | 246 /* Get edelay */ -#define DIGI_SEDELAY ('d'<<8) | 247 /* Set edelay */ - -struct digiflow_t { - unsigned char startc; /* flow cntl start char */ - unsigned char stopc; /* flow cntl stop char */ -}; - - -#ifdef FLOW_2200 -#define F2200_GETA ('e'<<8) | 104 /* Get 2x36 flow cntl flags */ -#define F2200_SETAW ('e'<<8) | 105 /* Set 2x36 flow cntl flags */ -#define F2200_MASK 0x03 /* 2200 flow cntl bit mask */ -#define FCNTL_2200 0x01 /* 2x36 terminal flow cntl */ -#define PCNTL_2200 0x02 /* 2x36 printer flow cntl */ -#define F2200_XON 0xf8 -#define P2200_XON 0xf9 -#define F2200_XOFF 0xfa -#define P2200_XOFF 0xfb - -#define FXOFF_MASK 0x03 /* 2200 flow status mask */ -#define RCVD_FXOFF 0x01 /* 2x36 Terminal XOFF rcvd */ -#define RCVD_PXOFF 0x02 /* 2x36 Printer XOFF rcvd */ -#endif - -/************************************************************************ - * Values for digi_flags - ************************************************************************/ -#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */ -#define DIGI_FAST 0x0002 /* Fast baud rates */ -#define RTSPACE 0x0004 /* RTS input flow control */ -#define CTSPACE 0x0008 /* CTS output flow control */ -#define DSRPACE 0x0010 /* DSR output flow control */ -#define DCDPACE 0x0020 /* DCD output flow control */ -#define DTRPACE 0x0040 /* DTR input flow control */ -#define DIGI_COOK 0x0080 /* Cooked processing done in FEP */ -#define DIGI_FORCEDCD 0x0100 /* Force carrier */ -#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */ -#define DIGI_AIXON 0x0400 /* Aux flow control in fep */ -#define DIGI_PRINTER 0x0800 /* Hold port open for flow cntrl*/ -#define DIGI_PP_INPUT 0x1000 /* Change parallel port to input*/ -#define DIGI_DTR_TOGGLE 0x2000 /* Support DTR Toggle */ -#define DIGI_422 0x4000 /* for 422/232 selectable panel */ -#define DIGI_RTS_TOGGLE 0x8000 /* Support RTS Toggle */ - -/************************************************************************ - * These options are not supported on the comxi. - ************************************************************************/ -#define DIGI_COMXI (DIGI_FAST|DIGI_COOK|DSRPACE|DCDPACE|DTRPACE) - -#define DIGI_PLEN 28 /* String length */ -#define DIGI_TSIZ 10 /* Terminal string len */ - -/************************************************************************ - * Structure used with ioctl commands for DIGI parameters. - ************************************************************************/ -struct digi_t { - unsigned short digi_flags; /* Flags (see above) */ - unsigned short digi_maxcps; /* Max printer CPS */ - unsigned short digi_maxchar; /* Max chars in print queue */ - unsigned short digi_bufsize; /* Buffer size */ - unsigned char digi_onlen; /* Length of ON string */ - unsigned char digi_offlen; /* Length of OFF string */ - char digi_onstr[DIGI_PLEN]; /* Printer on string */ - char digi_offstr[DIGI_PLEN]; /* Printer off string */ - char digi_term[DIGI_TSIZ]; /* terminal string */ -}; - -/************************************************************************ - * KME definitions and structures. - ************************************************************************/ -#define RW_IDLE 0 /* Operation complete */ -#define RW_READ 1 /* Read Concentrator Memory */ -#define RW_WRITE 2 /* Write Concentrator Memory */ - -struct rw_t { - unsigned char rw_req; /* Request type */ - unsigned char rw_board; /* Host Adapter board number */ - unsigned char rw_conc; /* Concentrator number */ - unsigned char rw_reserved; /* Reserved for expansion */ - unsigned long rw_addr; /* Address in concentrator */ - unsigned short rw_size; /* Read/write request length */ - unsigned char rw_data[128]; /* Data to read/write */ -}; - -/*********************************************************************** - * Shrink Buffer and Board Information definitions and structures. - - ************************************************************************/ - /* Board type return codes */ -#define PCXI_TYPE 1 /* Board type at the designated port is a PC/Xi */ -#define PCXM_TYPE 2 /* Board type at the designated port is a PC/Xm */ -#define PCXE_TYPE 3 /* Board type at the designated port is a PC/Xe */ -#define MCXI_TYPE 4 /* Board type at the designated port is a MC/Xi */ -#define COMXI_TYPE 5 /* Board type at the designated port is a COM/Xi */ - - /* Non-Zero Result codes. */ -#define RESULT_NOBDFND 1 /* A Digi product at that port is not config installed */ -#define RESULT_NODESCT 2 /* A memory descriptor was not obtainable */ -#define RESULT_NOOSSIG 3 /* FEP/OS signature was not detected on the board */ -#define RESULT_TOOSML 4 /* Too small an area to shrink. */ -#define RESULT_NOCHAN 5 /* Channel structure for the board was not found */ - -struct shrink_buf_struct { - unsigned long shrink_buf_vaddr; /* Virtual address of board */ - unsigned long shrink_buf_phys; /* Physical address of board */ - unsigned long shrink_buf_bseg; /* Amount of board memory */ - unsigned long shrink_buf_hseg; /* '186 Beginning of Dual-Port */ - - unsigned long shrink_buf_lseg; /* '186 Beginning of freed memory */ - unsigned long shrink_buf_mseg; /* Linear address from start of - dual-port were freed memory - begins, host viewpoint. */ - - unsigned long shrink_buf_bdparam; /* Parameter for xxmemon and - xxmemoff */ - - unsigned long shrink_buf_reserva; /* Reserved */ - unsigned long shrink_buf_reservb; /* Reserved */ - unsigned long shrink_buf_reservc; /* Reserved */ - unsigned long shrink_buf_reservd; /* Reserved */ - - unsigned char shrink_buf_result; /* Reason for call failing - Zero is Good return */ - unsigned char shrink_buf_init; /* Non-Zero if it caused an - xxinit call. */ - - unsigned char shrink_buf_anports; /* Number of async ports */ - unsigned char shrink_buf_snports; /* Number of sync ports */ - unsigned char shrink_buf_type; /* Board type 1 = PC/Xi, - 2 = PC/Xm, - 3 = PC/Xe - 4 = MC/Xi - 5 = COMX/i */ - unsigned char shrink_buf_card; /* Card number */ - -}; - -/************************************************************************ - * Structure to get driver status information - ************************************************************************/ -struct digi_dinfo { - unsigned long dinfo_nboards; /* # boards configured */ - char dinfo_reserved[12]; /* for future expansion */ - char dinfo_version[16]; /* driver version */ -}; - -#define DIGI_GETDD ('d'<<8) | 248 /* get driver info */ - -/************************************************************************ - * Structure used with ioctl commands for per-board information - * - * physsize and memsize differ when board has "windowed" memory - ************************************************************************/ -struct digi_info { - unsigned long info_bdnum; /* Board number (0 based) */ - unsigned long info_ioport; /* io port address */ - unsigned long info_physaddr; /* memory address */ - unsigned long info_physsize; /* Size of host mem window */ - unsigned long info_memsize; /* Amount of dual-port mem */ - /* on board */ - unsigned short info_bdtype; /* Board type */ - unsigned short info_nports; /* number of ports */ - char info_bdstate; /* board state */ - char info_reserved[7]; /* for future expansion */ -}; - -#define DIGI_GETBD ('d'<<8) | 249 /* get board info */ - -struct digi_stat { - unsigned int info_chan; /* Channel number (0 based) */ - unsigned int info_brd; /* Board number (0 based) */ - unsigned long info_cflag; /* cflag for channel */ - unsigned long info_iflag; /* iflag for channel */ - unsigned long info_oflag; /* oflag for channel */ - unsigned long info_mstat; /* mstat for channel */ - unsigned long info_tx_data; /* tx_data for channel */ - unsigned long info_rx_data; /* rx_data for channel */ - unsigned long info_hflow; /* hflow for channel */ - unsigned long info_reserved[8]; /* for future expansion */ -}; - -#define DIGI_GETSTAT ('d'<<8) | 244 /* get board info */ -/************************************************************************ - * - * Structure used with ioctl commands for per-channel information - * - ************************************************************************/ -struct digi_ch { - unsigned long info_bdnum; /* Board number (0 based) */ - unsigned long info_channel; /* Channel index number */ - unsigned long info_ch_cflag; /* Channel cflag */ - unsigned long info_ch_iflag; /* Channel iflag */ - unsigned long info_ch_oflag; /* Channel oflag */ - unsigned long info_chsize; /* Channel structure size */ - unsigned long info_sleep_stat; /* sleep status */ - dev_t info_dev; /* device number */ - unsigned char info_initstate; /* Channel init state */ - unsigned char info_running; /* Channel running state */ - long reserved[8]; /* reserved for future use */ -}; - -/* -* This structure is used with the DIGI_FEPCMD ioctl to -* tell the driver which port to send the command for. -*/ -struct digi_cmd { - int cmd; - int word; - int ncmds; - int chan; /* channel index (zero based) */ - int bdid; /* board index (zero based) */ -}; - -/* -* info_sleep_stat defines -*/ -#define INFO_RUNWAIT 0x0001 -#define INFO_WOPEN 0x0002 -#define INFO_TTIOW 0x0004 -#define INFO_CH_RWAIT 0x0008 -#define INFO_CH_WEMPTY 0x0010 -#define INFO_CH_WLOW 0x0020 -#define INFO_XXBUF_BUSY 0x0040 - -#define DIGI_GETCH ('d'<<8) | 245 /* get board info */ - -/* Board type definitions */ - -#define SUBTYPE 0007 -#define T_PCXI 0000 -#define T_PCXM 0001 -#define T_PCXE 0002 -#define T_PCXR 0003 -#define T_SP 0004 -#define T_SP_PLUS 0005 -# define T_HERC 0000 -# define T_HOU 0001 -# define T_LON 0002 -# define T_CHA 0003 -#define FAMILY 0070 -#define T_COMXI 0000 -#define T_PCXX 0010 -#define T_CX 0020 -#define T_EPC 0030 -#define T_PCLITE 0040 -#define T_SPXX 0050 -#define T_AVXX 0060 -#define T_DXB 0070 -#define T_A2K_4_8 0070 -#define BUSTYPE 0700 -#define T_ISABUS 0000 -#define T_MCBUS 0100 -#define T_EISABUS 0200 -#define T_PCIBUS 0400 - -/* Board State Definitions */ - -#define BD_RUNNING 0x0 -#define BD_REASON 0x7f -#define BD_NOTFOUND 0x1 -#define BD_NOIOPORT 0x2 -#define BD_NOMEM 0x3 -#define BD_NOBIOS 0x4 -#define BD_NOFEP 0x5 -#define BD_FAILED 0x6 -#define BD_ALLOCATED 0x7 -#define BD_TRIBOOT 0x8 -#define BD_BADKME 0x80 - -#define DIGI_LOOPBACK ('d'<<8) | 252 /* Enable/disable UART internal loopback */ -#define DIGI_SPOLL ('d'<<8) | 254 /* change poller rate */ - -#define DIGI_SETCUSTOMBAUD _IOW('e', 106, int) /* Set integer baud rate */ -#define DIGI_GETCUSTOMBAUD _IOR('e', 107, int) /* Get integer baud rate */ -#define DIGI_RESET_PORT ('e'<<8) | 93 /* Reset port */ - -#endif /* DIGI_H */ diff --git a/drivers/staging/dgap/downld.c b/drivers/staging/dgap/downld.c deleted file mode 100644 index 1f4aa2eca437..000000000000 --- a/drivers/staging/dgap/downld.c +++ /dev/null @@ -1,798 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: downld.c,v 1.6 2009/01/14 14:10:54 markh Exp $ - */ - -/* -** downld.c -** -** This is the daemon that sends the fep, bios, and concentrator images -** from user space to the driver. -** BUGS: -** If the file changes in the middle of the download, you probably -** will get what you deserve. -** -*/ - -#include -#include -#include -#include -#include -#include - -#include "dgap_types.h" -#include "digi.h" -#include "dgap_fep5.h" - -#include "dgap_downld.h" - -#include -#include -#include -#include - -char *pgm; -void myperror(); - -/* -** This structure is used to keep track of the different images available -** to give to the driver. It is arranged so that the things that are -** constants or that have defaults are first inthe strucutre to simplify -** the table of initializers. -*/ -struct image_info { - short type; /* bios, fep, conc */ - short family; /* boards this applies to */ - short subtype; /* subtype */ - int len; /* size of image */ - char *image; /* ioctl struct + image */ - char *name; - char *fname; /* filename of binary (i.e. "asfep.bin") */ - char *pathname; /* pathname to this binary ("/etc/dgap/xrfep.bin"); */ - time_t mtime; /* Last modification time */ -}; - -#define IBIOS 0 -#define IFEP 1 -#define ICONC 2 -#define ICONFIG 3 -#define IBAD 4 - -#define DEFAULT_LOC "/lib/firmware/dgap/" - -struct image_info *image_list; -int nimages, count; - -struct image_info images[] = { -{IBIOS, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxbios.bin", DEFAULT_LOC "fxbios.bin", 0 }, -{IFEP, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxfep.bin", DEFAULT_LOC "fxfep.bin", 0 }, -{ICONC, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxcon.bin", DEFAULT_LOC "fxcon.bin", 0 }, - -{IBIOS, T_CX, SUBTYPE, 0, NULL, "C/X", "cxbios.bin", DEFAULT_LOC "cxbios.bin", 0 }, -{IFEP, T_CX, SUBTYPE, 0, NULL, "C/X", "cxhost.bin", DEFAULT_LOC "cxhost.bin", 0 }, - -{IBIOS, T_CX, T_PCIBUS, 0, NULL, "C/X PCI", "cxpbios.bin", DEFAULT_LOC "cxpbios.bin", 0 }, -{IFEP, T_CX, T_PCIBUS, 0, NULL, "C/X PCI", "cxpfep.bin", DEFAULT_LOC "cxpfep.bin", 0 }, - -{ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "cxcon.bin", DEFAULT_LOC "cxcon.bin", 0 }, -{ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "ibmcxcon.bin", DEFAULT_LOC "ibmcxcon.bin", 0 }, -{ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "ibmencon.bin", DEFAULT_LOC "ibmencon.bin", 0 }, - -{IBIOS, FAMILY, T_PCXR, 0, NULL, "PCXR", "xrbios.bin", DEFAULT_LOC "xrbios.bin", 0 }, -{IFEP, FAMILY, T_PCXR, 0, NULL, "PCXR", "xrfep.bin", DEFAULT_LOC "xrfep.bin", 0 }, - -{IBIOS, T_PCLITE, SUBTYPE, 0, NULL, "X/em", "sxbios.bin", DEFAULT_LOC "sxbios.bin", 0 }, -{IFEP, T_PCLITE, SUBTYPE, 0, NULL, "X/em", "sxfep.bin", DEFAULT_LOC "sxfep.bin", 0 }, - -{IBIOS, T_EPC, T_PCIBUS, 0, NULL, "PCI", "pcibios.bin", DEFAULT_LOC "pcibios.bin", 0 }, -{IFEP, T_EPC, T_PCIBUS, 0, NULL, "PCI", "pcifep.bin", DEFAULT_LOC "pcifep.bin", 0 }, -{ICONFIG, 0, 0, 0, NULL, NULL, "dgap.conf", "/etc/dgap.conf", 0 }, - -/* IBAD/NULL entry indicating end-of-table */ - -{IBAD, 0, 0, 0, NULL, NULL, NULL, NULL, 0 } - -} ; - -int errorprint = 1; -int nodldprint = 1; -int debugflag; -int fd; - -struct downld_t *ip; /* Image pointer in current image */ -struct downld_t *dp; /* conc. download */ - - -/* - * The same for either the FEP or the BIOS. - * Append the downldio header, issue the ioctl, then free - * the buffer. Not horribly CPU efficient, but quite RAM efficient. - */ - -void squirt(int req_type, int bdid, struct image_info *ii) -{ - struct downldio *dliop; - int size_buf; - int sfd; - struct stat sb; - - /* - * If this binary comes from a file, stat it to see how - * large it is. Yes, we intentionally do this each - * time for the binary may change between loads. - */ - - if (ii->pathname) { - sfd = open(ii->pathname, O_RDONLY); - - if (sfd < 0 ) { - myperror(ii->pathname); - goto squirt_end; - } - - if (fstat(sfd, &sb) == -1 ) { - myperror(ii->pathname); - goto squirt_end; - } - - ii->len = sb.st_size; - } - - size_buf = ii->len + sizeof(struct downldio); - - /* - * This buffer will be freed at the end of this function. It is - * not resilient and should be around only long enough for the d/l - * to happen. - */ - dliop = (struct downldio *) malloc(size_buf); - - if (dliop == NULL) { - fprintf(stderr,"%s: can't get %d bytes of memory; aborting\n", - pgm, size_buf); - exit (1); - } - - /* Now, stick the image in fepimage. This can come from either - * the compiled-in image or from the filesystem. - */ - if (ii->pathname) - read(sfd, dliop->image.fi.fepimage, ii->len); - else - memcpy(dliop ->image.fi.fepimage, ii->image, ii->len); - - dliop->req_type = req_type; - dliop->bdid = bdid; - - dliop->image.fi.len = ii->len; - - if (debugflag) - printf("sending %d bytes of %s %s from %s\n", - ii->len, - (ii->type == IFEP) ? "FEP" : (ii->type == IBIOS) ? "BIOS" : "CONFIG", - ii->name ? ii->name : "", - (ii->pathname) ? ii->pathname : "internal image" ); - - if (ioctl(fd, DIGI_DLREQ_SET, (char *) dliop) == -1) { - if(errorprint) { - fprintf(stderr, - "%s: warning - download ioctl failed\n",pgm); - errorprint = 0; - } - sleep(2); - } - -squirt_end: - - if (ii->pathname) { - close(sfd); - } - free(dliop); -} - - -/* - * See if we need to reload the download image in core - * - */ -void consider_file_rescan(struct image_info *ii) -{ - int sfd; - int len; - struct stat sb; - - /* This operation only makes sense when we're working from a file */ - - if (ii->pathname) { - - sfd = open (ii->pathname, O_RDONLY) ; - if (sfd < 0 ) { - myperror(ii->pathname); - exit(1) ; - } - - if( fstat(sfd,&sb) == -1 ) { - myperror(ii->pathname); - exit(1); - } - - /* If the file hasn't changed since we last did this, - * and we have not done a free() on the image, bail - */ - if (ii->image && (sb.st_mtime == ii->mtime)) - goto end_rescan; - - ii->len = len = sb.st_size; - - /* Record the timestamp of the file */ - ii->mtime = sb.st_mtime; - - /* image should be NULL unless there is an image malloced - * in already. Before we malloc again, make sure we don't - * have a memory leak. - */ - if ( ii->image ) { - free( ii->image ); - /* ii->image = NULL; */ /* not necessary */ - } - - /* This image will be kept only long enough for the - * download to happen. After sending the last block, - * it will be freed - */ - ii->image = malloc(len) ; - - if (ii->image == NULL) { - fprintf(stderr, - "%s: can't get %d bytes of memory; aborting\n", - pgm, len); - exit (1); - } - - if (read(sfd, ii->image, len) < len) { - fprintf(stderr,"%s: read error on %s; aborting\n", - pgm, ii->pathname); - exit (1); - } - -end_rescan: - close(sfd); - - } -} - -/* - * Scan for images to match the driver requests - */ - -struct image_info * find_conc_image() -{ - int x; - struct image_info *i = NULL; - - for ( x = 0; x < nimages; x++ ) { - i=&image_list[x]; - - if(i->type != ICONC) - continue; - - consider_file_rescan(i) ; - - ip = (struct downld_t *) image_list[x].image; - if (ip == NULL) continue; - - /* - * When I removed Clusterport, I kept only the code that I - * was SURE wasn't ClusterPort. We may not need the next two - * lines of code. - */ - if ((dp->dl_type != 'P' ) && ( ip->dl_srev == dp->dl_srev )) - return i; - } - return NULL; -} - - -int main(int argc, char **argv) -{ - struct downldio dlio; - int offset, bsize; - int x; - char *down, *image, *fname; - struct image_info *ii; - - pgm = argv[0]; - dp = &dlio.image.dl; /* conc. download */ - - while((argc > 2) && !strcmp(argv[1],"-d")) { - debugflag++ ; - argc-- ; - argv++ ; - } - - if(argc < 2) { - fprintf(stderr, - "usage: %s download-device [image-file] ...\n", - pgm); - exit(1); - } - - - - /* - * Daemonize, unless debugging is turned on. - */ - if (debugflag == 0) { - switch (fork()) - { - case 0: - break; - - case -1: - return 1; - - default: - return 0; - } - - setsid(); - - /* - * The child no longer needs "stdin", "stdout", or "stderr", - * and should not block processes waiting for them to close. - */ - fclose(stdin); - fclose(stdout); - fclose(stderr); - - } - - while (1) { - if( (fd = open(argv[1], O_RDWR)) == -1 ) { - sleep(1); - } - else - break; - } - - /* - ** create a list of images to search through when trying to match - ** requests from the driver. Put images from the command line in - ** the list before built in images so that the command line images - ** can override the built in ones. - */ - - /* allocate space for the list */ - - nimages = argc - 2; - - /* count the number of default list entries */ - - for (count = 0; images[count].type != IBAD; ++count) ; - - nimages += count; - - /* Really should just remove the variable "image_list".... robertl */ - image_list = images; - - /* get the images from the command line */ - for(x = 2; x < argc; x++) { - int xx; - - /* - * strip off any leading path information for - * determining file type - */ - if( (fname = strrchr(argv[x],'/')) == NULL) - fname = argv[x]; - else - fname++; /* skip the slash */ - - for (xx = 0; xx < count; xx++) { - if (strcmp(fname, images[xx].fname) == 0 ) { - images[xx].pathname = argv[x]; - - /* image should be NULL until */ - /* space is malloced */ - images[xx].image = NULL; - } - } - } - - sleep(3); - - /* - ** Endless loop: get a request from the fep, and service that request. - */ - for(;;) { - /* get the request */ - if (debugflag) - printf("b4 get ioctl..."); - - if (ioctl(fd,DIGI_DLREQ_GET, &dlio) == -1 ) { - if (errorprint) { - fprintf(stderr, - "%s: warning - download ioctl failed\n", - pgm); - errorprint = 0; - } - sleep(2); - } else { - if (debugflag) - printf("dlio.req_type is %d bd %d\n", - dlio.req_type,dlio.bdid); - - switch(dlio.req_type) { - case DLREQ_BIOS: - /* - ** find the bios image for this type - */ - for ( x = 0; x < nimages; x++ ) { - if(image_list[x].type != IBIOS) - continue; - - if ((dlio.image.fi.type & FAMILY) == - image_list[x].family) { - - if ( image_list[x].family == T_CX ) { - if ((dlio.image.fi.type & BUSTYPE) - == T_PCIBUS ) { - if ( image_list[x].subtype - == T_PCIBUS ) - break; - } - else { - break; - } - } - else if ( image_list[x].family == T_EPC ) { - /* If subtype of image is T_PCIBUS, it is */ - /* a PCI EPC image, so the board must */ - /* have bus type T_PCIBUS to match */ - if ((dlio.image.fi.type & BUSTYPE) - == T_PCIBUS ) { - if ( image_list[x].subtype - == T_PCIBUS ) - break; - } - else { - /* NON PCI EPC doesn't use PCI image */ - if ( image_list[x].subtype - != T_PCIBUS ) - break; - } - } - else - break; - } - else if ((dlio.image.fi.type & SUBTYPE) == image_list[x].subtype) { - /* PCXR board will break out of the loop here */ - if ( image_list[x].subtype == T_PCXR ) { - break; - } - } - } - - if ( x >= nimages) { - /* - ** no valid images exist - */ - if(nodldprint) { - fprintf(stderr, - "%s: cannot find correct BIOS image\n", - pgm); - nodldprint = 0; - } - dlio.image.fi.type = -1; - if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1) { - if (errorprint) { - fprintf(stderr, - "%s: warning - download ioctl failed\n", - pgm); - errorprint = 0; - } - sleep(2); - } - break; - } - squirt(dlio.req_type, dlio.bdid, &image_list[x]); - break ; - - case DLREQ_FEP: - /* - ** find the fep image for this type - */ - for ( x = 0; x < nimages; x++ ) { - if(image_list[x].type != IFEP) - continue; - if( (dlio.image.fi.type & FAMILY) == - image_list[x].family ) { - if ( image_list[x].family == T_CX ) { - /* C/X PCI board */ - if ((dlio.image.fi.type & BUSTYPE) - == T_PCIBUS ) { - if ( image_list[x].subtype - == T_PCIBUS ) - break; - } - else { - /* Regular CX */ - break; - } - } - else if ( image_list[x].family == T_EPC ) { - /* If subtype of image is T_PCIBUS, it is */ - /* a PCI EPC image, so the board must */ - /* have bus type T_PCIBUS to match */ - if ((dlio.image.fi.type & BUSTYPE) - == T_PCIBUS ) { - if ( image_list[x].subtype - == T_PCIBUS ) - break; - } - else { - /* NON PCI EPC doesn't use PCI image */ - if ( image_list[x].subtype - != T_PCIBUS ) - break; - } - } - else - break; - } - else if ((dlio.image.fi.type & SUBTYPE) == image_list[x].subtype) { - /* PCXR board will break out of the loop here */ - if ( image_list[x].subtype == T_PCXR ) { - break; - } - } - } - - if ( x >= nimages) { - /* - ** no valid images exist - */ - if(nodldprint) { - fprintf(stderr, - "%s: cannot find correct FEP image\n", - pgm); - nodldprint = 0; - } - dlio.image.fi.type=-1; - if( ioctl(fd,DIGI_DLREQ_SET,&dlio) == -1 ) { - if(errorprint) { - fprintf(stderr, - "%s: warning - download ioctl failed\n", - pgm); - errorprint=0; - } - sleep(2); - } - break; - } - squirt(dlio.req_type, dlio.bdid, &image_list[x]); - break; - - case DLREQ_DEVCREATE: - { - char string[1024]; -#if 0 - sprintf(string, "%s /proc/dgap/%d/mknod", DEFSHELL, dlio.bdid); -#endif - sprintf(string, "%s /usr/sbin/dgap_updatedevs %d", DEFSHELL, dlio.bdid); - system(string); - - if (debugflag) - printf("Created Devices.\n"); - if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) { - if(errorprint) { - fprintf(stderr, "%s: warning - DEVCREATE ioctl failed\n",pgm); - errorprint = 0; - } - sleep(2); - } - if (debugflag) - printf("After ioctl set - Created Device.\n"); - } - - break; - - case DLREQ_CONFIG: - for ( x = 0; x < nimages; x++ ) { - if(image_list[x].type != ICONFIG) - continue; - else - break; - } - - if ( x >= nimages) { - /* - ** no valid images exist - */ - if(nodldprint) { - fprintf(stderr, - "%s: cannot find correct CONFIG image\n", - pgm); - nodldprint = 0; - } - dlio.image.fi.type=-1; - if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) { - if(errorprint) { - fprintf(stderr, - "%s: warning - download ioctl failed\n", - pgm); - errorprint=0; - } - sleep(2); - } - break; - } - - squirt(dlio.req_type, dlio.bdid, &image_list[x]); - break; - - case DLREQ_CONC: - /* - ** find the image needed for this download - */ - if ( dp->dl_seq == 0 ) { - /* - ** find image for hardware rev range - */ - for ( x = 0; x < nimages; x++ ) { - ii=&image_list[x]; - - if(image_list[x].type != ICONC) - continue; - - consider_file_rescan(ii) ; - - ip = (struct downld_t *) image_list[x].image; - if (ip == NULL) continue; - - /* - * When I removed Clusterport, I kept only the - * code that I was SURE wasn't ClusterPort. - * We may not need the next four lines of code. - */ - - if ((dp->dl_type != 'P' ) && - (ip->dl_lrev <= dp->dl_lrev ) && - ( dp->dl_lrev <= ip->dl_hrev)) - break; - } - - if ( x >= nimages ) { - /* - ** No valid images exist - */ - if(nodldprint) { - fprintf(stderr, - "%s: cannot find correct download image %d\n", - pgm, dp->dl_lrev); - nodldprint=0; - } - continue; - } - - } else { - /* - ** find image version required - */ - if ((ii = find_conc_image()) == NULL ) { - /* - ** No valid images exist - */ - fprintf(stderr, - "%s: can't find rest of download image??\n", - pgm); - continue; - } - } - - /* - ** download block of image - */ - - offset = 1024 * dp->dl_seq; - - /* - ** test if block requested within image - */ - if ( offset < ii->len ) { - - /* - ** if it is, determine block size, set segment, - ** set size, set pointers, and copy block - */ - if (( bsize = ii->len - offset ) > 1024 ) - bsize = 1024; - - /* - ** copy image version info to download area - */ - dp->dl_srev = ip->dl_srev; - dp->dl_lrev = ip->dl_lrev; - dp->dl_hrev = ip->dl_hrev; - - dp->dl_seg = (64 * dp->dl_seq) + ip->dl_seg; - dp->dl_size = bsize; - - down = (char *)&dp->dl_data[0]; - image = (char *)((char *)ip + offset); - - memcpy(down, image, bsize); - } - else { - /* - ** Image has been downloaded, set segment and - ** size to indicate no more blocks - */ - dp->dl_seg = ip->dl_seg; - dp->dl_size = 0; - - /* Now, we can release the concentrator */ - /* image from memory if we're running */ - /* from filesystem images */ - - if (ii->pathname) - if (ii->image) { - free(ii->image); - ii->image = NULL; - } - } - - if (debugflag) - printf( - "sending conc dl section %d to %s from %s\n", - dp->dl_seq, ii->name, - ii->pathname ? ii->pathname : "Internal Image"); - - if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) { - if (errorprint) { - fprintf(stderr, - "%s: warning - download ioctl failed\n", - pgm); - errorprint=0; - } - sleep(2); - } - break; - } /* switch */ - } - if (debugflag > 1) { - printf("pausing: "); fflush(stdout); - fflush(stdin); - while(getchar() != '\n'); - printf("continuing\n"); - } - } -} - -/* -** myperror() -** -** Same as normal perror(), but places the program name at the beginning -** of the message. -*/ -void myperror(char *s) -{ - fprintf(stderr,"%s: %s: %s.\n",pgm, s, strerror(errno)); -} diff --git a/drivers/staging/dgnc/dgnc_cls.c b/drivers/staging/dgnc/dgnc_cls.c index 708adbbcedbd..60d9b62c6f1f 100644 --- a/drivers/staging/dgnc/dgnc_cls.c +++ b/drivers/staging/dgnc/dgnc_cls.c @@ -827,9 +827,8 @@ static irqreturn_t cls_intr(int irq, void *voidbrd) * Check to make sure its for us. */ if (brd->magic != DGNC_BOARD_MAGIC) { - APR(( - "Received interrupt (%d) with a board pointer " - "that wasn't ours!\n", irq)); + APR(("Received interrupt (%d) with a board pointer that wasn't ours!\n", + irq)); return IRQ_NONE; } @@ -846,8 +845,7 @@ static irqreturn_t cls_intr(int irq, void *voidbrd) /* If 0, no interrupts pending */ if (!poll_reg) { DPR_INTR(( - "Kernel interrupted to me, but no pending " - "interrupts...\n")); + "Kernel interrupted to me, but no pending interrupts...\n")); DGNC_UNLOCK(brd->bd_intr_lock, lock_flags); return IRQ_NONE; } @@ -1388,8 +1386,7 @@ static void cls_send_break(struct channel_t *ch, int msecs) writeb((temp | UART_LCR_SBC), &ch->ch_cls_uart->lcr); ch->ch_flags |= (CH_BREAK_SENDING); DPR_IOCTL(( - "Port %d. Starting UART_LCR_SBC! start: %lx " - "should end: %lx\n", + "Port %d. Starting UART_LCR_SBC! start: %lx should end: %lx\n", ch->ch_portnum, jiffies, ch->ch_stop_sending_break)); } } diff --git a/drivers/staging/dgnc/dgnc_driver.c b/drivers/staging/dgnc/dgnc_driver.c index c204266cb69f..b1a39b25b419 100644 --- a/drivers/staging/dgnc/dgnc_driver.c +++ b/drivers/staging/dgnc/dgnc_driver.c @@ -88,7 +88,7 @@ module_exit(dgnc_cleanup_module); /* * File operations permitted on Control/Management major. */ -static struct file_operations dgnc_BoardFops = +static const struct file_operations dgnc_BoardFops = { .owner = THIS_MODULE, .unlocked_ioctl = dgnc_mgmt_ioctl, @@ -236,7 +236,7 @@ int dgnc_init_module(void) if (dgnc_NumBoards) pci_unregister_driver(&dgnc_driver); else - printk("WARNING: dgnc driver load failed. No Digi Neo or Classic boards found.\n"); + pr_warn("WARNING: dgnc driver load failed. No Digi Neo or Classic boards found.\n"); dgnc_cleanup_module(); } diff --git a/drivers/staging/dgnc/dgnc_mgmt.c b/drivers/staging/dgnc/dgnc_mgmt.c index 1c5ab3d007b0..c5b425bf6692 100644 --- a/drivers/staging/dgnc/dgnc_mgmt.c +++ b/drivers/staging/dgnc/dgnc_mgmt.c @@ -42,7 +42,7 @@ #include /* For tasklet and interrupt structs/defines */ #include #include -#include /* For copy_from_user/copy_to_user */ +#include /* For copy_from_user/copy_to_user */ #include "dgnc_driver.h" #include "dgnc_pci.h" @@ -77,8 +77,7 @@ int dgnc_mgmt_open(struct inode *inode, struct file *file) return -EBUSY; } dgnc_mgmt_in_use[minor]++; - } - else { + } else { DGNC_UNLOCK(dgnc_global_lock, lock_flags); return -ENXIO; } @@ -107,9 +106,8 @@ int dgnc_mgmt_close(struct inode *inode, struct file *file) /* mgmt device */ if (minor < MAXMGMTDEVICES) { - if (dgnc_mgmt_in_use[minor]) { + if (dgnc_mgmt_in_use[minor]) dgnc_mgmt_in_use[minor] = 0; - } } DGNC_UNLOCK(dgnc_global_lock, lock_flags); @@ -153,7 +151,7 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) DPR_MGMT(("DIGI_GETDD returning numboards: %d version: %s\n", ddi.dinfo_nboards, ddi.dinfo_version)); - if (copy_to_user(uarg, &ddi, sizeof (ddi))) + if (copy_to_user(uarg, &ddi, sizeof(ddi))) return -EFAULT; break; @@ -165,13 +163,13 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct digi_info di; - if (copy_from_user(&brd, uarg, sizeof(int))) { + if (copy_from_user(&brd, uarg, sizeof(int))) return -EFAULT; - } DPR_MGMT(("DIGI_GETBD asking about board: %d\n", brd)); - if ((brd < 0) || (brd > dgnc_NumBoards) || (dgnc_NumBoards == 0)) + if ((brd < 0) || (brd > dgnc_NumBoards) || + (dgnc_NumBoards == 0)) return -ENODEV; memset(&di, 0, sizeof(di)); @@ -195,7 +193,7 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) DPR_MGMT(("DIGI_GETBD returning type: %x state: %x ports: %x size: %x\n", di.info_bdtype, di.info_bdstate, di.info_nports, di.info_physsize)); - if (copy_to_user(uarg, &di, sizeof (di))) + if (copy_to_user(uarg, &di, sizeof(di))) return -EFAULT; break; @@ -209,9 +207,8 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) uint board = 0; uint channel = 0; - if (copy_from_user(&ni, uarg, sizeof(ni))) { + if (copy_from_user(&ni, uarg, sizeof(ni))) return -EFAULT; - } DPR_MGMT(("DIGI_GETBD asking about board: %d channel: %d\n", ni.board, ni.channel)); @@ -268,12 +265,14 @@ long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ni.cflag = ch->ch_c_cflag; ni.lflag = ch->ch_c_lflag; - if (ch->ch_digi.digi_flags & CTSPACE || ch->ch_c_cflag & CRTSCTS) + if (ch->ch_digi.digi_flags & CTSPACE || + ch->ch_c_cflag & CRTSCTS) ni.hflow = 1; else ni.hflow = 0; - if ((ch->ch_flags & CH_STOPI) || (ch->ch_flags & CH_FORCED_STOPI)) + if ((ch->ch_flags & CH_STOPI) || + (ch->ch_flags & CH_FORCED_STOPI)) ni.recv_stopped = 1; else ni.recv_stopped = 0; diff --git a/drivers/staging/dgnc/dgnc_neo.c b/drivers/staging/dgnc/dgnc_neo.c index dc5a138d8d4a..cf22c7b725f9 100644 --- a/drivers/staging/dgnc/dgnc_neo.c +++ b/drivers/staging/dgnc/dgnc_neo.c @@ -1201,7 +1201,8 @@ static void neo_copy_data_from_uart_to_queue(struct channel_t *ch) ch->ch_cached_lsr = 0; /* Store how much space we have left in the queue */ - if ((qleft = tail - head - 1) < 0) + qleft = tail - head - 1; + if (qleft < 0) qleft += RQUEUEMASK + 1; /* diff --git a/drivers/staging/dgnc/dgnc_tty.c b/drivers/staging/dgnc/dgnc_tty.c index a6c6aba82d72..f0b17c36edd8 100644 --- a/drivers/staging/dgnc/dgnc_tty.c +++ b/drivers/staging/dgnc/dgnc_tty.c @@ -964,8 +964,10 @@ static void dgnc_set_custom_speed(struct channel_t *ch, uint newrate) int deltahigh; int deltalow; - if (newrate < 0) - newrate = 0; + if (newrate <= 0) { + ch->ch_custom_speed = 0; + return; + } /* * Since the divisor is stored in a 16-bit integer, we make sure @@ -978,7 +980,7 @@ static void dgnc_set_custom_speed(struct channel_t *ch, uint newrate) if (newrate && newrate > ch->ch_bd->bd_dividend) newrate = ch->ch_bd->bd_dividend; - while (newrate > 0) { + if (newrate > 0) { testdiv = ch->ch_bd->bd_dividend / newrate; /* @@ -995,28 +997,23 @@ static void dgnc_set_custom_speed(struct channel_t *ch, uint newrate) * If the rate for the requested divisor is correct, just * use it and be done. */ - if (testrate_high == newrate ) - break; + if (testrate_high != newrate) { + /* + * Otherwise, pick the rate that is closer (i.e. whichever rate + * has a smaller delta). + */ + deltahigh = testrate_high - newrate; + deltalow = newrate - testrate_low; - /* - * Otherwise, pick the rate that is closer (i.e. whichever rate - * has a smaller delta). - */ - deltahigh = testrate_high - newrate; - deltalow = newrate - testrate_low; - - if (deltahigh < deltalow) { - newrate = testrate_high; - } else { - newrate = testrate_low; + if (deltahigh < deltalow) { + newrate = testrate_high; + } else { + newrate = testrate_low; + } } - - break; } ch->ch_custom_speed = newrate; - - return; } @@ -1025,7 +1022,8 @@ void dgnc_check_queue_flow_control(struct channel_t *ch) int qleft = 0; /* Store how much space we have left in the queue */ - if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0) + qleft = ch->ch_r_tail - ch->ch_r_head - 1; + if (qleft < 0) qleft += RQUEUEMASK + 1; /* @@ -1119,7 +1117,8 @@ void dgnc_wakeup_writes(struct channel_t *ch) /* * If channel now has space, wake up anyone waiting on the condition. */ - if ((qlen = ch->ch_w_head - ch->ch_w_tail) < 0) + qlen = ch->ch_w_head - ch->ch_w_tail; + if (qlen < 0) qlen += WQUEUESIZE; if (qlen >= (WQUEUESIZE - 256)) { @@ -1917,7 +1916,8 @@ static int dgnc_tty_write_room(struct tty_struct *tty) head = (ch->ch_w_head) & tmask; tail = (ch->ch_w_tail) & tmask; - if ((ret = tail - head - 1) < 0) + ret = tail - head - 1; + if (ret < 0) ret += WQUEUESIZE; /* Limit printer to maxcps */ @@ -2017,7 +2017,8 @@ static int dgnc_tty_write(struct tty_struct *tty, head = (ch->ch_w_head) & tmask; tail = (ch->ch_w_tail) & tmask; - if ((bufcount = tail - head - 1) < 0) + bufcount = tail - head - 1; + if (bufcount < 0) bufcount += WQUEUESIZE; DPR_WRITE(("%d: bufcount: %x count: %x tail: %x head: %x tmask: %x\n", @@ -3316,10 +3317,10 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, case DIGI_SETCUSTOMBAUD: { - uint new_rate; + int new_rate; /* Let go of locks when accessing user space, could sleep */ DGNC_UNLOCK(ch->ch_lock, lock_flags); - rc = get_user(new_rate, (unsigned int __user *) arg); + rc = get_user(new_rate, (int __user *) arg); if (rc) return rc; DGNC_LOCK(ch->ch_lock, lock_flags); diff --git a/drivers/staging/dgrp/dgrp_sysfs.c b/drivers/staging/dgrp/dgrp_sysfs.c index 9a18a2c9e73b..2f9345ff0abb 100644 --- a/drivers/staging/dgrp/dgrp_sysfs.c +++ b/drivers/staging/dgrp/dgrp_sysfs.c @@ -65,7 +65,9 @@ static ssize_t dgrp_class_pollrate_store(struct device *c, struct device_attribute *attr, const char *buf, size_t count) { - sscanf(buf, "0x%x\n", &dgrp_poll_tick); + if (sscanf(buf, "0x%x\n", &dgrp_poll_tick) != 1) + return -EINVAL; + return count; } static DEVICE_ATTR(pollrate, 0600, dgrp_class_pollrate_show, diff --git a/drivers/staging/dgrp/dgrp_tty.c b/drivers/staging/dgrp/dgrp_tty.c index 7a9694c1d9c4..30d26029b21e 100644 --- a/drivers/staging/dgrp/dgrp_tty.c +++ b/drivers/staging/dgrp/dgrp_tty.c @@ -1319,7 +1319,8 @@ static int dgrp_calculate_txprint_bounds(struct ch_struct *ch, int space, if (ch->ch_tun.un_open_count != 0 && ch->ch_tun.un_tty->ops->chars_in_buffer && - ((ch->ch_tun.un_tty->ops->chars_in_buffer)(ch->ch_tun.un_tty) != 0)) { + ((ch->ch_tun.un_tty->ops->chars_in_buffer) + (ch->ch_tun.un_tty) != 0)) { *un_flag = UN_PWAIT; return 0; } @@ -1501,7 +1502,8 @@ static int dgrp_tty_write(struct tty_struct *tty, */ if (ch->ch_tun.un_open_count != 0 && - ((ch->ch_tun.un_tty->ops->chars_in_buffer)(ch->ch_tun.un_tty) != 0)) { + ((ch->ch_tun.un_tty->ops->chars_in_buffer) + (ch->ch_tun.un_tty) != 0)) { un->un_flag |= UN_PWAIT; count = 0; goto out; @@ -1666,7 +1668,8 @@ static int dgrp_tty_write(struct tty_struct *tty, if (n >= t) { memcpy(ch->ch_tbuf + ch->ch_tin, buf, t); - if (nd->nd_dpa_debug && nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(un->un_tty)))) + if (nd->nd_dpa_debug && nd->nd_dpa_port == + PORT_NUM(MINOR(tty_devnum(un->un_tty)))) dgrp_dpa_data(nd, 0, (char *) buf, t); buf += t; n -= t; @@ -1675,7 +1678,8 @@ static int dgrp_tty_write(struct tty_struct *tty, } memcpy(ch->ch_tbuf + ch->ch_tin, buf, n); - if (nd->nd_dpa_debug && nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(un->un_tty)))) + if (nd->nd_dpa_debug && nd->nd_dpa_port == + PORT_NUM(MINOR(tty_devnum(un->un_tty)))) dgrp_dpa_data(nd, 0, (char *) buf, n); buf += n; ch->ch_tin += n; @@ -2656,7 +2660,8 @@ static int dgrp_tty_ioctl(struct tty_struct *tty, unsigned int cmd, ch->ch_send |= RR_RX_FLUSH; (ch->ch_nd)->nd_tx_work = 1; (ch->ch_nd)->nd_tx_ready = 1; - wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); + wake_up_interruptible( + &(ch->ch_nd)->nd_tx_waitq); } if (arg == TCIFLUSH) break; @@ -2682,7 +2687,8 @@ static int dgrp_tty_ioctl(struct tty_struct *tty, unsigned int cmd, Linux HPUX Function TCSETA TCSETA - set the termios TCSETAF TCSETAF - wait for drain first, then set termios - TCSETAW TCSETAW - wait for drain, flush the input queue, then set termios + TCSETAW TCSETAW - wait for drain, + flush the input queue, then set termios - looking at the tty_ioctl code, these command all call our tty_set_termios at the driver's end, when a TCSETA* is sent, it is expecting the tty to have a termio structure, @@ -2798,6 +2804,7 @@ static int dgrp_tty_ioctl(struct tty_struct *tty, unsigned int cmd, } /* pretend we didn't recognize this */ + /* fall-through */ case DIGI_SETA: return dgrp_tty_digiseta(tty, (struct digi_struct *) arg); @@ -3207,7 +3214,8 @@ dgrp_tty_init(struct nd_struct *nd) int max_majors = 1U << (32 - MINORBITS); for (i = 256; i < max_majors; i++) { nd->nd_serial_ttdriver->major = i; - rc = tty_register_driver(nd->nd_serial_ttdriver); + rc = tty_register_driver + (nd->nd_serial_ttdriver); if (rc >= 0) break; } diff --git a/drivers/staging/echo/TODO b/drivers/staging/echo/TODO deleted file mode 100644 index 72a311a5a9cc..000000000000 --- a/drivers/staging/echo/TODO +++ /dev/null @@ -1,5 +0,0 @@ -TODO: - - send to lkml for review - -Please send patches to Greg Kroah-Hartman and Cc: Steve -Underwood and David Rowe diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c index e516bb69f3b4..d329cf314360 100644 --- a/drivers/staging/et131x/et131x.c +++ b/drivers/staging/et131x/et131x.c @@ -485,8 +485,6 @@ struct et131x_adapter { u8 eeprom_data[2]; /* Spinlocks */ - spinlock_t lock; - spinlock_t tcb_send_qlock; spinlock_t tcb_ready_qlock; spinlock_t send_hw_lock; @@ -1388,6 +1386,7 @@ static int et131x_phy_mii_read(struct et131x_adapter *adapter, u8 addr, mii_indicator); status = -EIO; + goto out; } /* If we hit here we were able to read the register and we need to @@ -1395,6 +1394,7 @@ static int et131x_phy_mii_read(struct et131x_adapter *adapter, u8 addr, */ *value = readl(&mac->mii_mgmt_stat) & ET_MAC_MIIMGMT_STAT_PHYCRTL_MASK; +out: /* Stop the read operation */ writel(0, &mac->mii_mgmt_cmd); @@ -2124,7 +2124,11 @@ static int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter) /* Alloc memory for the lookup table */ rx_ring->fbr[0] = kmalloc(sizeof(struct fbr_lookup), GFP_KERNEL); + if (rx_ring->fbr[0] == NULL) + return -ENOMEM; rx_ring->fbr[1] = kmalloc(sizeof(struct fbr_lookup), GFP_KERNEL); + if (rx_ring->fbr[1] == NULL) + return -ENOMEM; /* The first thing we will do is configure the sizes of the buffer * rings. These will change based on jumbo packet support. Larger @@ -2289,7 +2293,7 @@ static void et131x_rx_dma_memory_free(struct et131x_adapter *adapter) for (id = 0; id < NUM_FBRS; id++) { fbr = rx_ring->fbr[id]; - if (!fbr->ring_virtaddr) + if (!fbr || !fbr->ring_virtaddr) continue; /* First the packet memory */ @@ -3523,7 +3527,7 @@ static int et131x_pci_init(struct et131x_adapter *adapter, goto err_out; } } - memcpy(adapter->addr, adapter->rom_addr, ETH_ALEN); + ether_addr_copy(adapter->addr, adapter->rom_addr); out: return rc; err_out: @@ -3591,6 +3595,7 @@ static int et131x_adapter_memory_alloc(struct et131x_adapter *adapter) if (status) { dev_err(&adapter->pdev->dev, "et131x_tx_dma_memory_alloc FAILED\n"); + et131x_tx_dma_memory_free(adapter); return status; } /* Receive buffer memory allocation */ @@ -3598,7 +3603,7 @@ static int et131x_adapter_memory_alloc(struct et131x_adapter *adapter) if (status) { dev_err(&adapter->pdev->dev, "et131x_rx_dma_memory_alloc FAILED\n"); - et131x_tx_dma_memory_free(adapter); + et131x_adapter_memory_free(adapter); return status; } @@ -3760,7 +3765,6 @@ static struct et131x_adapter *et131x_adapter_init(struct net_device *netdev, adapter->netdev = netdev; /* Initialize spinlocks here */ - spin_lock_init(&adapter->lock); spin_lock_init(&adapter->tcb_send_qlock); spin_lock_init(&adapter->tcb_ready_qlock); spin_lock_init(&adapter->send_hw_lock); @@ -3770,7 +3774,7 @@ static struct et131x_adapter *et131x_adapter_init(struct net_device *netdev, adapter->registry_jumbo_packet = 1514; /* 1514-9216 */ /* Set the MAC address to a default */ - memcpy(adapter->addr, default_mac, ETH_ALEN); + ether_addr_copy(adapter->addr, default_mac); return adapter; } @@ -4292,12 +4296,9 @@ static void et131x_multicast(struct net_device *netdev) { struct et131x_adapter *adapter = netdev_priv(netdev); int packet_filter; - unsigned long flags; struct netdev_hw_addr *ha; int i; - spin_lock_irqsave(&adapter->lock, flags); - /* Before we modify the platform-independent filter flags, store them * locally. This allows us to determine if anything's changed and if * we even need to bother the hardware @@ -4349,8 +4350,6 @@ static void et131x_multicast(struct net_device *netdev) */ if (packet_filter != adapter->packet_filter) et131x_set_packet_filter(adapter); - - spin_unlock_irqrestore(&adapter->lock, flags); } /* et131x_tx - The handler to tx a packet on the device */ diff --git a/drivers/staging/frontier/alphatrack.c b/drivers/staging/frontier/alphatrack.c index edd5cef300d0..226b23163109 100644 --- a/drivers/staging/frontier/alphatrack.c +++ b/drivers/staging/frontier/alphatrack.c @@ -208,7 +208,9 @@ static void usb_alphatrack_delete(struct usb_alphatrack *dev) kfree(dev->ring_buffer); kfree(dev->interrupt_in_buffer); kfree(dev->interrupt_out_buffer); - kfree(dev); /* fixme oldi_buffer */ + kfree(dev->oldi_buffer); + kfree(dev->write_buffer); + kfree(dev); } /** usb_alphatrack_interrupt_in_callback */ @@ -233,8 +235,8 @@ static void usb_alphatrack_interrupt_in_callback(struct urb *urb) if (urb->actual_length != INPUT_CMD_SIZE) { dev_warn(&dev->intf->dev, - "Urb length was %d bytes!!" - "Do something intelligent\n", urb->actual_length); + "Urb length was %d bytes!! Do something intelligent\n", + urb->actual_length); } else { alphatrack_ocmd_info(&dev->intf->dev, &(*dev->ring_buffer)[dev->ring_tail].cmd, @@ -688,8 +690,7 @@ static int usb_alphatrack_probe(struct usb_interface *intf, } if (dev->interrupt_out_endpoint == NULL) dev_warn(&intf->dev, - "Interrupt out endpoint not found" - "(using control endpoint instead)\n"); + "Interrupt out endpoint not found (using control endpoint instead)\n"); dev->interrupt_in_endpoint_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize); diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c index 0e499ce5f0d7..0571988c58fc 100644 --- a/drivers/staging/frontier/tranzport.c +++ b/drivers/staging/frontier/tranzport.c @@ -257,8 +257,7 @@ static void usb_tranzport_interrupt_in_callback(struct urb *urb) if (urb->actual_length != 8) { dev_warn(&dev->intf->dev, - "Urb length was %d bytes!!" - "Do something intelligent\n", + "Urb length was %d bytes!! Do something intelligent\n", urb->actual_length); } else { dbg_info(&dev->intf->dev, @@ -542,8 +541,7 @@ static ssize_t usb_tranzport_read(struct file *file, char __user *buffer, } dbg_info(&dev->intf->dev, - "%s: copying to userspace: " - "%02x%02x%02x%02x%02x%02x%02x%02x\n", + "%s: copying to userspace: %02x%02x%02x%02x%02x%02x%02x%02x\n", __func__, (*dev->ring_buffer)[dev->ring_tail].cmd[0], (*dev->ring_buffer)[dev->ring_tail].cmd[1], @@ -570,8 +568,7 @@ static ssize_t usb_tranzport_read(struct file *file, char __user *buffer, * and we are the same sign, we can compress +- 7F */ dbg_info(&dev->intf->dev, - "%s: trying to compress: " - "%02x%02x%02x%02x%02x%02x%02x%02x\n", + "%s: trying to compress: %02x%02x%02x%02x%02x%02x%02x%02x\n", __func__, (*dev->ring_buffer)[dev->ring_tail].cmd[0], (*dev->ring_buffer)[dev->ring_tail].cmd[1], @@ -830,8 +827,7 @@ static int usb_tranzport_probe(struct usb_interface *intf, } if (dev->interrupt_out_endpoint == NULL) dev_warn(&intf->dev, - "Interrupt out endpoint not found" - "(using control endpoint instead)\n"); + "Interrupt out endpoint not found (using control endpoint instead)\n"); dev->interrupt_in_endpoint_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize); diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index a433e33049b5..b6a77088cfe4 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -1145,7 +1145,7 @@ static int ft1000_proc_drvmsg(struct ft1000_usb *dev, u16 size) char *cmdbuffer = kmalloc(1600, GFP_KERNEL); if (!cmdbuffer) - return -1; + return -ENOMEM; status = ft1000_read_dpram32(dev, 0x200, cmdbuffer, size); diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h b/drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h index 24b8d77a132c..419e534874f9 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h @@ -30,7 +30,7 @@ typedef struct _IOCTL_GET_VER { unsigned long drv_ver; -} __attribute__ ((packed)) IOCTL_GET_VER, *PIOCTL_GET_VER; +} __packed IOCTL_GET_VER, *PIOCTL_GET_VER; /* Data structure for Dsp statistics */ typedef struct _IOCTL_GET_DSP_STAT { @@ -67,19 +67,19 @@ typedef struct _IOCTL_GET_DSP_STAT { unsigned long ConTm; /* Current session connection time in seconds */ unsigned char CalVer[CALVERSZ]; /* Proprietary Calibration Version */ unsigned char CalDate[CALDATESZ]; /* Proprietary Calibration Date */ -} __attribute__ ((packed)) IOCTL_GET_DSP_STAT, *PIOCTL_GET_DSP_STAT; +} __packed IOCTL_GET_DSP_STAT, *PIOCTL_GET_DSP_STAT; /* Data structure for Dual Ported RAM messaging between Host and Dsp */ typedef struct _IOCTL_DPRAM_BLK { unsigned short total_len; struct pseudo_hdr pseudohdr; unsigned char buffer[1780]; -} __attribute__ ((packed)) IOCTL_DPRAM_BLK, *PIOCTL_DPRAM_BLK; +} __packed IOCTL_DPRAM_BLK, *PIOCTL_DPRAM_BLK; typedef struct _IOCTL_DPRAM_COMMAND { unsigned short extra; IOCTL_DPRAM_BLK dpram_blk; -} __attribute__ ((packed)) IOCTL_DPRAM_COMMAND, *PIOCTL_DPRAM_COMMAND; +} __packed IOCTL_DPRAM_COMMAND, *PIOCTL_DPRAM_COMMAND; /* * Custom IOCTL command codes diff --git a/drivers/staging/ft1000/ft1000.h b/drivers/staging/ft1000/ft1000.h index 175abfa7682e..ccb821a1f370 100644 --- a/drivers/staging/ft1000/ft1000.h +++ b/drivers/staging/ft1000/ft1000.h @@ -21,34 +21,64 @@ #define FT1000_REG_SUP_CTRL 0x0020 /* HCTR - Host Control Register */ #define FT1000_REG_SUP_STAT 0x0022 /* HSTAT - Host Status Register */ #define FT1000_REG_RESET 0x0024 /* HCTR - Host Control Register */ -#define FT1000_REG_SUP_ISR 0x0026 /* HISR - Host Interrupt Status Register */ +#define FT1000_REG_SUP_ISR 0x0026 /* HISR - Host Interrupt Status + * Register + */ #define FT1000_REG_SUP_IMASK 0x0028 /* HIMASK - Host Interrupt Mask */ #define FT1000_REG_DOORBELL 0x002a /* DBELL - Door Bell Register */ -#define FT1000_REG_ASIC_ID 0x002e /* ASICID - ASIC Identification Number */ +#define FT1000_REG_ASIC_ID 0x002e /* ASICID - ASIC Identification + * Number + */ /* MEMORY MAP FOR ELECTRABUZZ ASIC */ #define FT1000_REG_UFIFO_STAT 0x0000 /* UFSR - Uplink FIFO status register */ -#define FT1000_REG_UFIFO_BEG 0x0002 /* UFBR - Uplink FIFO beginning register */ +#define FT1000_REG_UFIFO_BEG 0x0002 /* UFBR - Uplink FIFO beginning + * register + */ #define FT1000_REG_UFIFO_MID 0x0004 /* UFMR - Uplink FIFO middle register */ #define FT1000_REG_UFIFO_END 0x0006 /* UFER - Uplink FIFO end register */ -#define FT1000_REG_DFIFO_STAT 0x0008 /* DFSR - Downlink FIFO status register */ +#define FT1000_REG_DFIFO_STAT 0x0008 /* DFSR - Downlink FIFO status + * register + */ #define FT1000_REG_DFIFO 0x000A /* DFR - Downlink FIFO Register */ -#define FT1000_REG_DPRAM_DATA 0x000C /* DPRAM - Dual Port Indirect Data Register */ +#define FT1000_REG_DPRAM_DATA 0x000C /* DPRAM - Dual Port Indirect + * Data Register + */ #define FT1000_REG_WATERMARK 0x0010 /* WMARK - Watermark Register */ /* MEMORY MAP FOR MAGNEMITE */ -#define FT1000_REG_MAG_UFDR 0x0000 /* UFDR - Uplink FIFO Data Register (32-bits) */ -#define FT1000_REG_MAG_UFDRL 0x0000 /* UFDRL - Uplink FIFO Data Register low-word (16-bits) */ -#define FT1000_REG_MAG_UFDRH 0x0002 /* UFDRH - Uplink FIFO Data Register high-word (16-bits) */ +#define FT1000_REG_MAG_UFDR 0x0000 /* UFDR - Uplink FIFO Data + * Register (32-bits) + */ +#define FT1000_REG_MAG_UFDRL 0x0000 /* UFDRL - Uplink FIFO Data + * Register low-word (16-bits) + */ +#define FT1000_REG_MAG_UFDRH 0x0002 /* UFDRH - Uplink FIFO Data Register + * high-word (16-bits) + */ #define FT1000_REG_MAG_UFER 0x0004 /* UFER - Uplink FIFO End Register */ #define FT1000_REG_MAG_UFSR 0x0006 /* UFSR - Uplink FIFO Status Register */ -#define FT1000_REG_MAG_DFR 0x0008 /* DFR - Downlink FIFO Register (32-bits) */ -#define FT1000_REG_MAG_DFRL 0x0008 /* DFRL - Downlink FIFO Register low-word (16-bits) */ -#define FT1000_REG_MAG_DFRH 0x000a /* DFRH - Downlink FIFO Register high-word (16-bits) */ -#define FT1000_REG_MAG_DFSR 0x000c /* DFSR - Downlink FIFO Status Register */ -#define FT1000_REG_MAG_DPDATA 0x0010 /* DPDATA - Dual Port RAM Indirect Data Register (32-bits) */ -#define FT1000_REG_MAG_DPDATAL 0x0010 /* DPDATAL - Dual Port RAM Indirect Data Register low-word (16-bits) */ -#define FT1000_REG_MAG_DPDATAH 0x0012 /* DPDATAH - Dual Port RAM Indirect Data Register high-word (16-bits) */ +#define FT1000_REG_MAG_DFR 0x0008 /* DFR - Downlink FIFO Register + * (32-bits) + */ +#define FT1000_REG_MAG_DFRL 0x0008 /* DFRL - Downlink FIFO Register + * low-word (16-bits) + */ +#define FT1000_REG_MAG_DFRH 0x000a /* DFRH - Downlink FIFO Register + * high-word (16-bits) + */ +#define FT1000_REG_MAG_DFSR 0x000c /* DFSR - Downlink FIFO Status + * Register + */ +#define FT1000_REG_MAG_DPDATA 0x0010 /* DPDATA - Dual Port RAM Indirect + * Data Register (32-bits) + */ +#define FT1000_REG_MAG_DPDATAL 0x0010 /* DPDATAL - Dual Port RAM Indirect + * Data Register low-word (16-bits) + */ +#define FT1000_REG_MAG_DPDATAH 0x0012 /* DPDATAH - Dual Port RAM Indirect Data + * Register high-word (16-bits) + */ #define FT1000_REG_MAG_WATERMARK 0x002c /* WMARK - Watermark Register */ #define FT1000_REG_MAG_VERSION 0x0030 /* LLC Version */ @@ -57,7 +87,9 @@ #define FT1000_DPRAM_RX_BASE 0x0800 /* PC Card to Host Messaging Area */ #define FT1000_FIFO_LEN 0x07FC /* total length for DSP FIFO tracking */ #define FT1000_HI_HO 0x07FE /* heartbeat with HI/HO */ -#define FT1000_DSP_STATUS 0x0FFE /* dsp status - non-zero is a request to reset dsp */ +#define FT1000_DSP_STATUS 0x0FFE /* dsp status - non-zero is a request + * to reset dsp + */ #define FT1000_DSP_LED 0x0FFA /* dsp led status for PAD device */ #define FT1000_DSP_CON_STATE 0x0FF8 /* DSP Connection Status Info */ #define FT1000_DPRAM_FEFE 0x0002 /* location for dsp ready indicator */ @@ -67,26 +99,48 @@ #define FT1000_DSP_TIMER3 0x1FF6 /* Timer Field from Basestation */ /* Reserved Dual Port RAM offsets for Magnemite */ -#define FT1000_DPRAM_MAG_TX_BASE 0x0000 /* Host to PC Card Messaging Area */ -#define FT1000_DPRAM_MAG_RX_BASE 0x0200 /* PC Card to Host Messaging Area */ +#define FT1000_DPRAM_MAG_TX_BASE 0x0000 /* Host to PC Card + * Messaging Area + */ +#define FT1000_DPRAM_MAG_RX_BASE 0x0200 /* PC Card to Host + * Messaging Area + */ -#define FT1000_MAG_FIFO_LEN 0x1FF /* total length for DSP FIFO tracking */ +#define FT1000_MAG_FIFO_LEN 0x1FF /* total length for DSP + * FIFO tracking + */ #define FT1000_MAG_FIFO_LEN_INDX 0x1 /* low-word index */ #define FT1000_MAG_HI_HO 0x1FF /* heartbeat with HI/HO */ #define FT1000_MAG_HI_HO_INDX 0x0 /* high-word index */ -#define FT1000_MAG_DSP_LED 0x3FE /* dsp led status for PAD device */ -#define FT1000_MAG_DSP_LED_INDX 0x0 /* dsp led status for PAD device */ +#define FT1000_MAG_DSP_LED 0x3FE /* dsp led status for + * PAD device + */ +#define FT1000_MAG_DSP_LED_INDX 0x0 /* dsp led status for + * PAD device + */ #define FT1000_MAG_DSP_CON_STATE 0x3FE /* DSP Connection Status Info */ #define FT1000_MAG_DSP_CON_STATE_INDX 0x1 /* DSP Connection Status Info */ -#define FT1000_MAG_DPRAM_FEFE 0x000 /* location for dsp ready indicator */ -#define FT1000_MAG_DPRAM_FEFE_INDX 0x0 /* location for dsp ready indicator */ -#define FT1000_MAG_DSP_TIMER0 0x3FC /* Timer Field from Basestation */ +#define FT1000_MAG_DPRAM_FEFE 0x000 /* location for dsp ready + * indicator + */ +#define FT1000_MAG_DPRAM_FEFE_INDX 0x0 /* location for dsp ready + * indicator + */ +#define FT1000_MAG_DSP_TIMER0 0x3FC /* Timer Field from + * Basestation + */ #define FT1000_MAG_DSP_TIMER0_INDX 0x1 -#define FT1000_MAG_DSP_TIMER1 0x3FC /* Timer Field from Basestation */ +#define FT1000_MAG_DSP_TIMER1 0x3FC /* Timer Field from + * Basestation + */ #define FT1000_MAG_DSP_TIMER1_INDX 0x0 -#define FT1000_MAG_DSP_TIMER2 0x3FD /* Timer Field from Basestation */ +#define FT1000_MAG_DSP_TIMER2 0x3FD /* Timer Field from + * Basestation + */ #define FT1000_MAG_DSP_TIMER2_INDX 0x1 -#define FT1000_MAG_DSP_TIMER3 0x3FD /* Timer Field from Basestation */ +#define FT1000_MAG_DSP_TIMER3 0x3FD /* Timer Field from + * Basestation + */ #define FT1000_MAG_DSP_TIMER3_INDX 0x0 #define FT1000_MAG_TOTAL_LEN 0x200 #define FT1000_MAG_TOTAL_LEN_INDX 0x1 @@ -99,24 +153,38 @@ #define HOST_INTF_BE 0x1 /* Host interface big endian mode */ /* FT1000 to Host Doorbell assignments */ -#define FT1000_DB_DPRAM_RX 0x0001 /* this value indicates that DSP has data for host in DPRAM */ +#define FT1000_DB_DPRAM_RX 0x0001 /* this value indicates that DSP + * has data for host in DPRAM + */ #define FT1000_DB_DNLD_RX 0x0002 /* Downloader handshake doorbell */ -#define FT1000_ASIC_RESET_REQ 0x0004 /* DSP requesting host to reset the ASIC */ -#define FT1000_DSP_ASIC_RESET 0x0008 /* DSP indicating host that it will reset the ASIC */ +#define FT1000_ASIC_RESET_REQ 0x0004 /* DSP requesting host to + * reset the ASIC + */ +#define FT1000_DSP_ASIC_RESET 0x0008 /* DSP indicating host that + * it will reset the ASIC + */ #define FT1000_DB_COND_RESET 0x0010 /* DSP request for a card reset. */ /* Host to FT1000 Doorbell assignments */ -#define FT1000_DB_DPRAM_TX 0x0100 /* this value indicates that host has data for DSP in DPRAM. */ +#define FT1000_DB_DPRAM_TX 0x0100 /* this value indicates that host + * has data for DSP in DPRAM. + */ #define FT1000_DB_DNLD_TX 0x0200 /* Downloader handshake doorbell */ #define FT1000_ASIC_RESET_DSP 0x0400 /* Responds to FT1000_ASIC_RESET_REQ */ -#define FT1000_DB_HB 0x1000 /* Indicates that supervisor has a heartbeat message for DSP. */ +#define FT1000_DB_HB 0x1000 /* Indicates that supervisor has a + * heartbeat message for DSP. + */ #define hi 0x6869 /* PC Card heartbeat values */ #define ho 0x686f /* PC Card heartbeat values */ /* Magnemite specific defines */ -#define hi_mag 0x6968 /* Byte swap hi to avoid additional system call */ -#define ho_mag 0x6f68 /* Byte swap ho to avoid additional system call */ +#define hi_mag 0x6968 /* Byte swap hi to avoid + * additional system call + */ +#define ho_mag 0x6f68 /* Byte swap ho to avoid + * additional system call + */ /* Bit field definitions for Host Interrupt Status Register */ /* Indicate the cause of an interrupt. */ @@ -133,13 +201,19 @@ #define ISR_MASK_RCV 0x0004 /* Downlink Packet available mask */ #define ISR_MASK_WATERMARK 0x0008 /* Watermark interrupt mask */ #define ISR_MASK_ALL 0xffff /* Mask all interrupts */ -/* Default interrupt mask (Enable Doorbell pending and Packet available interrupts) */ +/* Default interrupt mask + * (Enable Doorbell pending and Packet available interrupts) + */ #define ISR_DEFAULT_MASK 0x7ff9 /* Bit field definition for Host Control Register */ -#define DSP_RESET_BIT 0x0001 /* Bit field to control dsp reset state */ +#define DSP_RESET_BIT 0x0001 /* Bit field to control + * dsp reset state + */ /* (0 = out of reset 1 = reset) */ -#define ASIC_RESET_BIT 0x0002 /* Bit field to control ASIC reset state */ +#define ASIC_RESET_BIT 0x0002 /* Bit field to control + * ASIC reset state + */ /* (0 = out of reset 1 = reset) */ #define DSP_UNENCRYPTED 0x0004 #define DSP_ENCRYPTED 0x0008 @@ -195,7 +269,9 @@ struct pseudo_hdr { unsigned char source; /* hardware source id */ /* Host = 0x10 */ /* Dsp = 0x20 */ - unsigned char destination; /* hardware destination id (refer to source) */ + unsigned char destination; /* hardware destination id + * (refer to source) + */ unsigned char portdest; /* software destination port id */ /* Host = 0x00 */ /* Applicaton Broadcast = 0x10 */ @@ -204,7 +280,9 @@ struct pseudo_hdr { /* Dsp Airlink = 0x90 */ /* Dsp Loader = 0xa0 */ /* Dsp MIP = 0xb0 */ - unsigned char portsrc; /* software source port id (refer to portdest) */ + unsigned char portsrc; /* software source port id + * (refer to portdest) + */ unsigned short sh_str_id; /* not used */ unsigned char control; /* not used */ unsigned char rsvd1; diff --git a/drivers/staging/gdm724x/gdm_lte.c b/drivers/staging/gdm724x/gdm_lte.c index 74a03608b2dd..64c55b99fda4 100644 --- a/drivers/staging/gdm724x/gdm_lte.c +++ b/drivers/staging/gdm724x/gdm_lte.c @@ -131,7 +131,8 @@ static int gdm_lte_emulate_arp(struct sk_buff *skb_in, u32 nic_type) /* Get the pointer of the original request */ arp_in = (struct arphdr *)(skb_in->data + mac_header_len); - arp_data_in = (struct arpdata *)(skb_in->data + mac_header_len + sizeof(struct arphdr)); + arp_data_in = (struct arpdata *)(skb_in->data + mac_header_len + + sizeof(struct arphdr)); /* Get the pointer of the outgoing response */ arp_out = (struct arphdr *)arp_temp; @@ -160,9 +161,12 @@ static int gdm_lte_emulate_arp(struct sk_buff *skb_in, u32 nic_type) return -ENOMEM; skb_reserve(skb_out, NET_IP_ALIGN); - memcpy(skb_put(skb_out, mac_header_len), mac_header_data, mac_header_len); - memcpy(skb_put(skb_out, sizeof(struct arphdr)), arp_out, sizeof(struct arphdr)); - memcpy(skb_put(skb_out, sizeof(struct arpdata)), arp_data_out, sizeof(struct arpdata)); + memcpy(skb_put(skb_out, mac_header_len), mac_header_data, + mac_header_len); + memcpy(skb_put(skb_out, sizeof(struct arphdr)), arp_out, + sizeof(struct arphdr)); + memcpy(skb_put(skb_out, sizeof(struct arpdata)), arp_data_out, + sizeof(struct arpdata)); skb_out->protocol = ((struct ethhdr *)mac_header_data)->h_proto; skb_out->dev = skb_in->dev; @@ -198,7 +202,7 @@ static int icmp6_checksum(struct ipv6hdr *ipv6, u16 *ptr, int len) pseudo_header.ph.ph_nxt = ipv6->nexthdr; w = (u16 *)&pseudo_header; - for (i = 0; i < sizeof(pseudo_header.pa) / sizeof(pseudo_header.pa[0]); i++) + for (i = 0; i < ARRAY_SIZE(pseudo_header.pa); i++) sum += pseudo_header.pa[i]; w = ptr; @@ -260,11 +264,14 @@ static int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type) return -1; /* Check if this is NDP packet */ - icmp6_in = (struct icmp6hdr *)(skb_in->data + mac_header_len + sizeof(struct ipv6hdr)); + icmp6_in = (struct icmp6hdr *)(skb_in->data + mac_header_len + + sizeof(struct ipv6hdr)); if (icmp6_in->icmp6_type == NDISC_ROUTER_SOLICITATION) { /* Check RS */ return -1; - } else if (icmp6_in->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) { /* Check NS */ - u8 icmp_na[sizeof(struct icmp6hdr) + sizeof(struct neighbour_advertisement)]; + } else if (icmp6_in->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) { + /* Check NS */ + u8 icmp_na[sizeof(struct icmp6hdr) + + sizeof(struct neighbour_advertisement)]; u8 zero_addr8[16] = {0,}; if (memcmp(ipv6_in->saddr.in6_u.u6_addr8, zero_addr8, 16) == 0) @@ -276,7 +283,9 @@ static int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type) icmp6_out.icmp6_cksum = 0; icmp6_out.icmp6_dataun.un_data32[0] = htonl(0x60000000); /* R=0, S=1, O=1 */ - ns = (struct neighbour_solicitation *)(skb_in->data + mac_header_len + sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr)); + ns = (struct neighbour_solicitation *) + (skb_in->data + mac_header_len + + sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr)); memcpy(&na.target_address, ns->target_address, 16); na.type = 0x02; na.length = 1; @@ -289,13 +298,17 @@ static int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type) memcpy(&ipv6_out, ipv6_in, sizeof(struct ipv6hdr)); memcpy(ipv6_out.saddr.in6_u.u6_addr8, &na.target_address, 16); - memcpy(ipv6_out.daddr.in6_u.u6_addr8, ipv6_in->saddr.in6_u.u6_addr8, 16); - ipv6_out.payload_len = htons(sizeof(struct icmp6hdr) + sizeof(struct neighbour_advertisement)); + memcpy(ipv6_out.daddr.in6_u.u6_addr8, + ipv6_in->saddr.in6_u.u6_addr8, 16); + ipv6_out.payload_len = htons(sizeof(struct icmp6hdr) + + sizeof(struct neighbour_advertisement)); memcpy(icmp_na, &icmp6_out, sizeof(struct icmp6hdr)); - memcpy(icmp_na + sizeof(struct icmp6hdr), &na, sizeof(struct neighbour_advertisement)); + memcpy(icmp_na + sizeof(struct icmp6hdr), &na, + sizeof(struct neighbour_advertisement)); - icmp6_out.icmp6_cksum = icmp6_checksum(&ipv6_out, (u16 *)icmp_na, sizeof(icmp_na)); + icmp6_out.icmp6_cksum = icmp6_checksum(&ipv6_out, + (u16 *)icmp_na, sizeof(icmp_na)); } else { return -1; } @@ -311,10 +324,14 @@ static int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type) return -ENOMEM; skb_reserve(skb_out, NET_IP_ALIGN); - memcpy(skb_put(skb_out, mac_header_len), mac_header_data, mac_header_len); - memcpy(skb_put(skb_out, sizeof(struct ipv6hdr)), &ipv6_out, sizeof(struct ipv6hdr)); - memcpy(skb_put(skb_out, sizeof(struct icmp6hdr)), &icmp6_out, sizeof(struct icmp6hdr)); - memcpy(skb_put(skb_out, sizeof(struct neighbour_advertisement)), &na, sizeof(struct neighbour_advertisement)); + memcpy(skb_put(skb_out, mac_header_len), mac_header_data, + mac_header_len); + memcpy(skb_put(skb_out, sizeof(struct ipv6hdr)), &ipv6_out, + sizeof(struct ipv6hdr)); + memcpy(skb_put(skb_out, sizeof(struct icmp6hdr)), &icmp6_out, + sizeof(struct icmp6hdr)); + memcpy(skb_put(skb_out, sizeof(struct neighbour_advertisement)), &na, + sizeof(struct neighbour_advertisement)); skb_out->protocol = ((struct ethhdr *)mac_header_data)->h_proto; skb_out->dev = skb_in->dev; @@ -363,7 +380,8 @@ static s32 gdm_lte_tx_nic_type(struct net_device *dev, struct sk_buff *skb) /* Check DHCPv4 */ if (ip->protocol == IPPROTO_UDP) { - struct udphdr *udp = (struct udphdr *)(network_data + sizeof(struct iphdr)); + struct udphdr *udp = (struct udphdr *) + (network_data + sizeof(struct iphdr)); if (ntohs(udp->dest) == 67 || ntohs(udp->dest) == 68) nic_type |= NIC_TYPE_F_DHCP; } @@ -373,12 +391,13 @@ static s32 gdm_lte_tx_nic_type(struct net_device *dev, struct sk_buff *skb) ipv6 = (struct ipv6hdr *)network_data; if (ipv6->nexthdr == IPPROTO_ICMPV6) /* Check NDP request */ { - struct icmp6hdr *icmp6 = (struct icmp6hdr *)(network_data + sizeof(struct ipv6hdr)); - if (/*icmp6->icmp6_type == NDISC_ROUTER_SOLICITATION || */ - icmp6->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) + struct icmp6hdr *icmp6 = (struct icmp6hdr *) + (network_data + sizeof(struct ipv6hdr)); + if (icmp6->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) nic_type |= NIC_TYPE_ICMPV6; } else if (ipv6->nexthdr == IPPROTO_UDP) /* Check DHCPv6 */ { - struct udphdr *udp = (struct udphdr *)(network_data + sizeof(struct ipv6hdr)); + struct udphdr *udp = (struct udphdr *) + (network_data + sizeof(struct ipv6hdr)); if (ntohs(udp->dest) == 546 || ntohs(udp->dest) == 547) nic_type |= NIC_TYPE_F_DHCP; } @@ -420,11 +439,12 @@ static int gdm_lte_tx(struct sk_buff *skb, struct net_device *dev) } /* - Need byte shift (that is, remove VLAN tag) if there is one - For the case of ARP, this breaks the offset as vlan_ethhdr+4 is treated as ethhdr - However, it shouldn't be a problem as the response starts from arp_hdr and ethhdr - is created by this driver based on the NIC mac - */ + * Need byte shift (that is, remove VLAN tag) if there is one + * For the case of ARP, this breaks the offset as vlan_ethhdr+4 + * is treated as ethhdr However, it shouldn't be a problem as + * the response starts from arp_hdr and ethhdr is created by this + * driver based on the NIC mac + */ if (nic_type & NIC_TYPE_F_VLAN) { struct vlan_ethhdr *vlan_eth = (struct vlan_ethhdr *)skb->data; nic->vlan_id = ntohs(vlan_eth->h_vlan_TCI) & VLAN_VID_MASK; @@ -436,15 +456,23 @@ static int gdm_lte_tx(struct sk_buff *skb, struct net_device *dev) data_len = skb->len; } - /* If it is a ICMPV6 packet, clear all the other bits : for backward compatibility with the firmware */ + /* If it is a ICMPV6 packet, clear all the other bits : + * for backward compatibility with the firmware + */ if (nic_type & NIC_TYPE_ICMPV6) nic_type = NIC_TYPE_ICMPV6; - /* If it is not a dhcp packet, clear all the flag bits : original NIC, otherwise the special flag (IPVX | DHCP) */ + /* If it is not a dhcp packet, clear all the flag bits : + * original NIC, otherwise the special flag (IPVX | DHCP) + */ if (!(nic_type & NIC_TYPE_F_DHCP)) nic_type &= NIC_TYPE_MASK; - sscanf(dev->name, "lte%d", &idx); + ret = sscanf(dev->name, "lte%d", &idx); + if (ret != 1) { + dev_kfree_skb(skb); + return -EINVAL; + } ret = nic->phy_dev->send_sdu_func(nic->phy_dev->priv_dev, data_buf, data_len, @@ -485,8 +513,11 @@ static int gdm_lte_event_send(struct net_device *dev, char *buf, int len) struct nic *nic = netdev_priv(dev); struct hci_packet *hci = (struct hci_packet *)buf; int idx; + int ret; - sscanf(dev->name, "lte%d", &idx); + ret = sscanf(dev->name, "lte%d", &idx); + if (ret != 1) + return -EINVAL; return netlink_send(lte_event.sock, idx, 0, buf, gdm_dev16_to_cpu( @@ -495,7 +526,8 @@ static int gdm_lte_event_send(struct net_device *dev, char *buf, int len) + HCI_HEADER_SIZE); } -static void gdm_lte_event_rcv(struct net_device *dev, u16 type, void *msg, int len) +static void gdm_lte_event_rcv(struct net_device *dev, u16 type, + void *msg, int len) { struct nic *nic = netdev_priv(dev); @@ -536,7 +568,8 @@ static u8 find_dev_index(u32 nic_type) return index; } -static void gdm_lte_netif_rx(struct net_device *dev, char *buf, int len, int flagged_nic_type) +static void gdm_lte_netif_rx(struct net_device *dev, char *buf, + int len, int flagged_nic_type) { u32 nic_type; struct nic *nic; @@ -551,28 +584,46 @@ static void gdm_lte_netif_rx(struct net_device *dev, char *buf, int len, int fla nic = netdev_priv(dev); if (flagged_nic_type & NIC_TYPE_F_DHCP) { - /* Change the destination mac address with the one requested the IP */ + /* Change the destination mac address + * with the one requested the IP + */ if (flagged_nic_type & NIC_TYPE_F_IPV4) { struct dhcp_packet { u8 op; /* BOOTREQUEST or BOOTREPLY */ - u8 htype; /* hardware address type. 1 = 10mb ethernet */ + u8 htype; /* hardware address type. + * 1 = 10mb ethernet + */ u8 hlen; /* hardware address length */ u8 hops; /* used by relay agents only */ u32 xid; /* unique id */ - u16 secs; /* elapsed since client began acquisition/renewal */ + u16 secs; /* elapsed since client began + * acquisition/renewal + */ u16 flags; /* only one flag so far: */ - #define BROADCAST_FLAG 0x8000 /* "I need broadcast replies" */ - u32 ciaddr; /* client IP (if client is in BOUND, RENEW or REBINDING state) */ + #define BROADCAST_FLAG 0x8000 + /* "I need broadcast replies" */ + u32 ciaddr; /* client IP (if client is in + * BOUND, RENEW or REBINDING state) + */ u32 yiaddr; /* 'your' (client) IP address */ - /* IP address of next server to use in bootstrap, returned in DHCPOFFER, DHCPACK by server */ + /* IP address of next server to use in + * bootstrap, returned in DHCPOFFER, + * DHCPACK by server + */ u32 siaddr_nip; u32 gateway_nip; /* relay agent IP address */ - u8 chaddr[16]; /* link-layer client hardware address (MAC) */ + u8 chaddr[16]; /* link-layer client hardware + * address (MAC) + */ u8 sname[64]; /* server host name (ASCIZ) */ u8 file[128]; /* boot file name (ASCIZ) */ - u32 cookie; /* fixed first four option bytes (99,130,83,99 dec) */ + u32 cookie; /* fixed first four option + * bytes (99,130,83,99 dec) + */ } __packed; - void *addr = buf + sizeof(struct iphdr) + sizeof(struct udphdr) + offsetof(struct dhcp_packet, chaddr); + void *addr = buf + sizeof(struct iphdr) + + sizeof(struct udphdr) + + offsetof(struct dhcp_packet, chaddr); memcpy(nic->dest_mac_addr, addr, ETH_ALEN); } } @@ -593,7 +644,9 @@ static void gdm_lte_netif_rx(struct net_device *dev, char *buf, int len, int fla vlan_eth.h_vlan_proto = htons(ETH_P_8021Q); if (nic_type == NIC_TYPE_ARP) { - /* Should be response: Only happens because there was a request from the host */ + /* Should be response: Only happens because + * there was a request from the host + */ eth.h_proto = htons(ETH_P_ARP); vlan_eth.h_vlan_encapsulated_proto = htons(ETH_P_ARP); } else { @@ -640,15 +693,20 @@ static void gdm_lte_multi_sdu_pkt(struct phy_dev *phy_dev, char *buf, int len) u32 nic_type; u8 index; - hci_len = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), multi_sdu->len); - num_packet = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), multi_sdu->num_packet); + hci_len = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), + multi_sdu->len); + num_packet = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), + multi_sdu->num_packet); for (i = 0; i < num_packet; i++) { sdu = (struct sdu *)data; - cmd_evt = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), sdu->cmd_evt); - hci_len = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), sdu->len); - nic_type = gdm_dev32_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), sdu->nic_type); + cmd_evt = gdm_dev16_to_cpu(phy_dev-> + get_endian(phy_dev->priv_dev), sdu->cmd_evt); + hci_len = gdm_dev16_to_cpu(phy_dev-> + get_endian(phy_dev->priv_dev), sdu->len); + nic_type = gdm_dev32_to_cpu(phy_dev-> + get_endian(phy_dev->priv_dev), sdu->nic_type); if (cmd_evt != LTE_RX_SDU) { pr_err("rx sdu wrong hci %04x\n", cmd_evt); @@ -662,7 +720,8 @@ static void gdm_lte_multi_sdu_pkt(struct phy_dev *phy_dev, char *buf, int len) index = find_dev_index(nic_type); if (index < MAX_NIC_TYPE) { dev = phy_dev->dev[index]; - gdm_lte_netif_rx(dev, (char *)sdu->data, (int)(hci_len-12), nic_type); + gdm_lte_netif_rx(dev, (char *)sdu->data, + (int)(hci_len-12), nic_type); } else { pr_err("rx sdu invalid nic_type :%x\n", nic_type); } @@ -709,7 +768,8 @@ static int gdm_lte_receive_pkt(struct phy_dev *phy_dev, char *buf, int len) if (!len) return ret; - cmd_evt = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), hci->cmd_evt); + cmd_evt = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), + hci->cmd_evt); dev = phy_dev->dev[0]; if (dev == NULL) @@ -718,7 +778,8 @@ static int gdm_lte_receive_pkt(struct phy_dev *phy_dev, char *buf, int len) switch (cmd_evt) { case LTE_RX_SDU: sdu = (struct sdu *)hci->data; - nic_type = gdm_dev32_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), sdu->nic_type); + nic_type = gdm_dev32_to_cpu(phy_dev-> + get_endian(phy_dev->priv_dev), sdu->nic_type); index = find_dev_index(nic_type); dev = phy_dev->dev[index]; gdm_lte_netif_rx(dev, hci->data, len, nic_type); @@ -733,7 +794,9 @@ static int gdm_lte_receive_pkt(struct phy_dev *phy_dev, char *buf, int len) break; case LTE_PDN_TABLE_IND: pdn_table = (struct hci_pdn_table_ind *)buf; - nic_type = gdm_dev32_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), pdn_table->nic_type); + nic_type = gdm_dev32_to_cpu(phy_dev-> + get_endian(phy_dev->priv_dev), + pdn_table->nic_type); index = find_dev_index(nic_type); dev = phy_dev->dev[index]; gdm_lte_pdn_table(dev, buf, len); @@ -758,7 +821,8 @@ void start_rx_proc(struct phy_dev *phy_dev) int i; for (i = 0; i < MAX_RX_SUBMIT_COUNT; i++) - phy_dev->rcv_func(phy_dev->priv_dev, rx_complete, phy_dev, USB_COMPLETE); + phy_dev->rcv_func(phy_dev->priv_dev, + rx_complete, phy_dev, USB_COMPLETE); } static struct net_device_ops gdm_netdev_ops = { @@ -771,7 +835,8 @@ static struct net_device_ops gdm_netdev_ops = { static u8 gdm_lte_macaddr[ETH_ALEN] = {0x00, 0x0a, 0x3b, 0x00, 0x00, 0x00}; -static void form_mac_address(u8 *dev_addr, u8 *nic_src, u8 *nic_dest, u8 *mac_address, u8 index) +static void form_mac_address(u8 *dev_addr, u8 *nic_src, u8 *nic_dest, + u8 *mac_address, u8 index) { /* Form the dev_addr */ if (!mac_address) @@ -779,10 +844,14 @@ static void form_mac_address(u8 *dev_addr, u8 *nic_src, u8 *nic_dest, u8 *mac_ad else memcpy(dev_addr, mac_address, ETH_ALEN); - /* The last byte of the mac address should be less than or equal to 0xFC */ + /* The last byte of the mac address + * should be less than or equal to 0xFC + */ dev_addr[ETH_ALEN-1] += index; - /* Create random nic src and copy the first 3 bytes to be the same as dev_addr */ + /* Create random nic src and copy the first + * 3 bytes to be the same as dev_addr + */ random_ether_addr(nic_src); memcpy(nic_src, dev_addr, 3); @@ -799,7 +868,8 @@ static void validate_mac_address(u8 *mac_address) } } -int register_lte_device(struct phy_dev *phy_dev, struct device *dev, u8 *mac_address) +int register_lte_device(struct phy_dev *phy_dev, + struct device *dev, u8 *mac_address) { struct nic *nic; struct net_device *net; @@ -814,7 +884,8 @@ int register_lte_device(struct phy_dev *phy_dev, struct device *dev, u8 *mac_add sprintf(pdn_dev_name, "lte%%dpdn%d", index); /* Allocate netdev */ - net = alloc_netdev(sizeof(struct nic), pdn_dev_name, ether_setup); + net = alloc_netdev(sizeof(struct nic), pdn_dev_name, + ether_setup); if (net == NULL) { pr_err("alloc_netdev failed\n"); ret = -ENOMEM; diff --git a/drivers/staging/gdm724x/gdm_lte.h b/drivers/staging/gdm724x/gdm_lte.h index 9287d310d8e2..88414e5a70cc 100644 --- a/drivers/staging/gdm724x/gdm_lte.h +++ b/drivers/staging/gdm724x/gdm_lte.h @@ -56,7 +56,7 @@ struct phy_dev { int (*cb)(void *cb_data, void *data, int len, int context), void *cb_data, int context); - struct gdm_endian *(*get_endian)(void *priv_dev); + struct gdm_endian * (*get_endian)(void *priv_dev); }; struct nic { diff --git a/drivers/staging/gdm724x/gdm_mux.c b/drivers/staging/gdm724x/gdm_mux.c index 2fa3a5a6580f..10ce2c1805bb 100644 --- a/drivers/staging/gdm724x/gdm_mux.c +++ b/drivers/staging/gdm724x/gdm_mux.c @@ -165,7 +165,8 @@ static int up_to_host(struct mux_rx *r) int len = r->len; while (1) { - mux_header = (struct mux_pkt_header *)(r->buf + packet_size_sum); + mux_header = (struct mux_pkt_header *)(r->buf + + packet_size_sum); start_flag = __le32_to_cpu(mux_header->start_flag); payload_size = __le32_to_cpu(mux_header->payload_size); packet_type = __le16_to_cpu(mux_header->packet_type); @@ -231,7 +232,8 @@ static void do_rx(struct work_struct *work) spin_unlock_irqrestore(&rx->to_host_lock, flags); break; } - r = list_entry(rx->to_host_list.next, struct mux_rx, to_host_list); + r = list_entry(rx->to_host_list.next, struct mux_rx, + to_host_list); list_del(&r->to_host_list); spin_unlock_irqrestore(&rx->to_host_lock, flags); @@ -249,7 +251,8 @@ static void remove_rx_submit_list(struct mux_rx *r, struct rx_cxt *rx) struct mux_rx *r_remove, *r_remove_next; spin_lock_irqsave(&rx->submit_list_lock, flags); - list_for_each_entry_safe(r_remove, r_remove_next, &rx->rx_submit_list, rx_submit_list) { + list_for_each_entry_safe(r_remove, r_remove_next, &rx->rx_submit_list, + rx_submit_list) { if (r == r_remove) list_del(&r->rx_submit_list); } @@ -279,9 +282,8 @@ static void gdm_mux_rcv_complete(struct urb *urb) } } -static int gdm_mux_recv(void *priv_dev, - int (*cb)(void *data, int len, int tty_index, struct tty_dev *tty_dev, int complete) - ) +static int gdm_mux_recv(void *priv_dev, int (*cb)(void *data, int len, + int tty_index, struct tty_dev *tty_dev, int complete)) { struct mux_dev *mux_dev = priv_dev; struct usb_device *usbdev = mux_dev->usbdev; @@ -416,7 +418,8 @@ static int gdm_mux_send(void *priv_dev, void *data, int len, int tty_index, return ret; } -static int gdm_mux_send_control(void *priv_dev, int request, int value, void *buf, int len) +static int gdm_mux_send_control(void *priv_dev, int request, int value, + void *buf, int len) { struct mux_dev *mux_dev = priv_dev; struct usb_device *usbdev = mux_dev->usbdev; @@ -448,7 +451,8 @@ static void release_usb(struct mux_dev *mux_dev) cancel_delayed_work(&mux_dev->work_rx); spin_lock_irqsave(&rx->submit_list_lock, flags); - list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, rx_submit_list) { + list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, + rx_submit_list) { spin_unlock_irqrestore(&rx->submit_list_lock, flags); usb_kill_urb(r->urb); spin_lock_irqsave(&rx->submit_list_lock, flags); @@ -503,7 +507,8 @@ static int init_usb(struct mux_dev *mux_dev) return ret; } -static int gdm_mux_probe(struct usb_interface *intf, const struct usb_device_id *id) +static int gdm_mux_probe(struct usb_interface *intf, + const struct usb_device_id *id) { struct mux_dev *mux_dev; struct tty_dev *tty_dev; @@ -610,7 +615,8 @@ static int gdm_mux_suspend(struct usb_interface *intf, pm_message_t pm_msg) spin_lock_irqsave(&rx->submit_list_lock, flags); - list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, rx_submit_list) { + list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, + rx_submit_list) { spin_unlock_irqrestore(&rx->submit_list_lock, flags); usb_kill_urb(r->urb); spin_lock_irqsave(&rx->submit_list_lock, flags); diff --git a/drivers/staging/gdm724x/gdm_usb.c b/drivers/staging/gdm724x/gdm_usb.c index 33458a583142..ee6e40facca7 100644 --- a/drivers/staging/gdm724x/gdm_usb.c +++ b/drivers/staging/gdm724x/gdm_usb.c @@ -30,14 +30,17 @@ #include "gdm_endian.h" #define USB_DEVICE_CDC_DATA(vid, pid) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS,\ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ + USB_DEVICE_ID_MATCH_INT_CLASS | \ + USB_DEVICE_ID_MATCH_INT_SUBCLASS,\ .idVendor = vid,\ .idProduct = pid,\ .bInterfaceClass = USB_CLASS_COMM,\ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET #define USB_DEVICE_MASS_DATA(vid, pid) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,\ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ + USB_DEVICE_ID_MATCH_INT_INFO,\ .idVendor = vid,\ .idProduct = pid,\ .bInterfaceSubClass = USB_SC_SCSI, \ @@ -59,7 +62,8 @@ static void do_tx(struct work_struct *work); static void do_rx(struct work_struct *work); static int gdm_usb_recv(void *priv_dev, - int (*cb)(void *cb_data, void *data, int len, int context), + int (*cb)(void *cb_data, + void *data, int len, int context), void *cb_data, int context); @@ -119,28 +123,15 @@ out: static struct usb_tx_sdu *alloc_tx_sdu_struct(void) { - struct usb_tx_sdu *t_sdu = NULL; - int ret = 0; - + struct usb_tx_sdu *t_sdu; t_sdu = kzalloc(sizeof(struct usb_tx_sdu), GFP_ATOMIC); - if (!t_sdu) { - ret = -ENOMEM; - goto out; - } + if (!t_sdu) + return NULL; t_sdu->buf = kmalloc(SDU_BUF_SIZE, GFP_ATOMIC); if (!t_sdu->buf) { - ret = -ENOMEM; - goto out; - } -out: - - if (ret < 0) { - if (t_sdu) { - kfree(t_sdu->buf); - kfree(t_sdu); - } + kfree(t_sdu); return NULL; } @@ -388,7 +379,8 @@ static int set_mac_address(u8 *data, void *arg) if (tlv->type == MAC_ADDRESS && udev->request_mac_addr) { memcpy(mac_address, tlv->data, tlv->len); - if (register_lte_device(phy_dev, &udev->intf->dev, mac_address) < 0) + if (register_lte_device(phy_dev, + &udev->intf->dev, mac_address) < 0) pr_err("register lte device failed\n"); udev->request_mac_addr = 0; @@ -401,7 +393,8 @@ static int set_mac_address(u8 *data, void *arg) static void do_rx(struct work_struct *work) { - struct lte_udev *udev = container_of(work, struct lte_udev, work_rx.work); + struct lte_udev *udev = + container_of(work, struct lte_udev, work_rx.work); struct rx_cxt *rx = &udev->rx; struct usb_rx *r; struct hci_packet *hci; @@ -416,7 +409,8 @@ static void do_rx(struct work_struct *work) spin_unlock_irqrestore(&rx->to_host_lock, flags); break; } - r = list_entry(rx->to_host_list.next, struct usb_rx, to_host_list); + r = list_entry(rx->to_host_list.next, + struct usb_rx, to_host_list); list_del(&r->to_host_list); spin_unlock_irqrestore(&rx->to_host_lock, flags); @@ -463,7 +457,8 @@ static void remove_rx_submit_list(struct usb_rx *r, struct rx_cxt *rx) struct usb_rx *r_remove, *r_remove_next; spin_lock_irqsave(&rx->submit_lock, flags); - list_for_each_entry_safe(r_remove, r_remove_next, &rx->rx_submit_list, rx_submit_list) + list_for_each_entry_safe(r_remove, + r_remove_next, &rx->rx_submit_list, rx_submit_list) { if (r == r_remove) { list_del(&r->rx_submit_list); @@ -500,7 +495,8 @@ static void gdm_usb_rcv_complete(struct urb *urb) } static int gdm_usb_recv(void *priv_dev, - int (*cb)(void *cb_data, void *data, int len, int context), + int (*cb)(void *cb_data, + void *data, int len, int context), void *cb_data, int context) { @@ -654,7 +650,8 @@ static u32 packet_aggregation(struct lte_udev *udev, u8 *send_buf) static void do_tx(struct work_struct *work) { - struct lte_udev *udev = container_of(work, struct lte_udev, work_tx.work); + struct lte_udev *udev = + container_of(work, struct lte_udev, work_tx.work); struct usb_device *usbdev = udev->usbdev; struct tx_cxt *tx = &udev->tx; struct usb_tx *t = NULL; @@ -813,7 +810,8 @@ static struct gdm_endian *gdm_usb_get_endian(void *priv_dev) return &udev->gdm_ed; } -static int gdm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) +static int gdm_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) { int ret = 0; struct phy_dev *phy_dev = NULL; @@ -861,7 +859,9 @@ static int gdm_usb_probe(struct usb_interface *intf, const struct usb_device_id usb_enable_autosuspend(usbdev); pm_runtime_set_autosuspend_delay(&usbdev->dev, AUTO_SUSPEND_TIMER); - /* List up hosts with big endians, otherwise, defaults to little endian */ + /* List up hosts with big endians, otherwise, + * defaults to little endian + */ if (idProduct == PID_GDM7243) gdm_set_endian(&udev->gdm_ed, ENDIANNESS_BIG); else diff --git a/drivers/staging/gdm724x/netlink_k.c b/drivers/staging/gdm724x/netlink_k.c index 77fc64e28428..5ddd36948a2f 100644 --- a/drivers/staging/gdm724x/netlink_k.c +++ b/drivers/staging/gdm724x/netlink_k.c @@ -32,7 +32,8 @@ static struct semaphore netlink_mutex; #define ND_MAX_GROUP 30 #define ND_IFINDEX_LEN sizeof(int) #define ND_NLMSG_SPACE(len) (NLMSG_SPACE(len) + ND_IFINDEX_LEN) -#define ND_NLMSG_DATA(nlh) ((void *)((char *)NLMSG_DATA(nlh) + ND_IFINDEX_LEN)) +#define ND_NLMSG_DATA(nlh) ((void *)((char *)NLMSG_DATA(nlh) + \ + ND_IFINDEX_LEN)) #define ND_NLMSG_S_LEN(len) (len+ND_IFINDEX_LEN) #define ND_NLMSG_R_LEN(nlh) (nlh->nlmsg_len-ND_IFINDEX_LEN) #define ND_NLMSG_IFIDX(nlh) NLMSG_DATA(nlh) diff --git a/drivers/staging/gdm72xx/TODO b/drivers/staging/gdm72xx/TODO index 30ac01ab972f..5ab27fb29594 100644 --- a/drivers/staging/gdm72xx/TODO +++ b/drivers/staging/gdm72xx/TODO @@ -1,5 +1,3 @@ TODO: - Replace kernel_thread with kthread in gdm_usb.c -- Replace hard-coded firmware paths with request_firmware in - sdio_boot.c and usb_boot.c - Clean up coding style to meet kernel standard. diff --git a/drivers/staging/gdm72xx/gdm_sdio.c b/drivers/staging/gdm72xx/gdm_sdio.c index 047a4d77f5ee..c24653739e13 100644 --- a/drivers/staging/gdm72xx/gdm_sdio.c +++ b/drivers/staging/gdm72xx/gdm_sdio.c @@ -38,26 +38,9 @@ #define TX_HZ 2000 #define TX_INTERVAL (1000000/TX_HZ) -/*#define DEBUG*/ - static int init_sdio(struct sdiowm_dev *sdev); static void release_sdio(struct sdiowm_dev *sdev); -#ifdef DEBUG -static void hexdump(char *title, u8 *data, int len) -{ - int i; - - printk(KERN_DEBUG "%s: length = %d\n", title, len); - for (i = 0; i < len; i++) { - printk(KERN_DEBUG "%02x ", data[i]); - if ((i & 0xf) == 0xf) - printk(KERN_DEBUG "\n"); - } - printk(KERN_DEBUG "\n"); -} -#endif - static struct sdio_tx *alloc_tx_struct(struct tx_cxt *tx) { struct sdio_tx *t = kzalloc(sizeof(*t), GFP_ATOMIC); @@ -297,10 +280,9 @@ static void send_sdu(struct sdio_func *func, struct tx_cxt *tx) spin_unlock_irqrestore(&tx->lock, flags); -#ifdef DEBUG - hexdump("sdio_send", tx->sdu_buf + TYPE_A_HEADER_SIZE, - aggr_len - TYPE_A_HEADER_SIZE); -#endif + print_hex_dump_debug("sdio_send: ", DUMP_PREFIX_NONE, 16, 1, + tx->sdu_buf + TYPE_A_HEADER_SIZE, + aggr_len - TYPE_A_HEADER_SIZE, false); for (pos = TYPE_A_HEADER_SIZE; pos < aggr_len; pos += TX_CHUNK_SIZE) { len = aggr_len - pos; @@ -335,10 +317,9 @@ static void send_hci(struct sdio_func *func, struct tx_cxt *tx, { unsigned long flags; -#ifdef DEBUG - hexdump("sdio_send", t->buf + TYPE_A_HEADER_SIZE, - t->len - TYPE_A_HEADER_SIZE); -#endif + print_hex_dump_debug("sdio_send: ", DUMP_PREFIX_NONE, 16, 1, + t->buf + TYPE_A_HEADER_SIZE, + t->len - TYPE_A_HEADER_SIZE, false); send_sdio_pkt(func, t->buf, t->len); spin_lock_irqsave(&tx->lock, flags); @@ -474,14 +455,10 @@ static int control_sdu_tx_flow(struct sdiowm_dev *sdev, u8 *hci_data, int len) goto out; if (hci_data[4] == 0) { -#ifdef DEBUG - printk(KERN_DEBUG "WIMAX ==> STOP SDU TX\n"); -#endif + dev_dbg(&sdev->func->dev, "WIMAX ==> STOP SDU TX\n"); tx->stop_sdu_tx = 1; } else if (hci_data[4] == 1) { -#ifdef DEBUG - printk(KERN_DEBUG "WIMAX ==> START SDU TX\n"); -#endif + dev_dbg(&sdev->func->dev, "WIMAX ==> START SDU TX\n"); tx->stop_sdu_tx = 0; if (tx->can_send) schedule_work(&sdev->ws); @@ -532,18 +509,14 @@ static void gdm_sdio_irq(struct sdio_func *func) } if (hdr[3] == 1) { /* Ack */ -#ifdef DEBUG u32 *ack_seq = (u32 *)&hdr[4]; -#endif spin_lock_irqsave(&tx->lock, flags); tx->can_send = 1; if (!list_empty(&tx->sdu_list) || !list_empty(&tx->hci_list)) schedule_work(&sdev->ws); spin_unlock_irqrestore(&tx->lock, flags); -#ifdef DEBUG - printk(KERN_DEBUG "Ack... %0x\n", ntohl(*ack_seq)); -#endif + dev_dbg(&func->dev, "Ack... %0x\n", ntohl(*ack_seq)); goto done; } @@ -579,9 +552,8 @@ static void gdm_sdio_irq(struct sdio_func *func) } end_io: -#ifdef DEBUG - hexdump("sdio_receive", rx->rx_buf, len); -#endif + print_hex_dump_debug("sdio_receive: ", DUMP_PREFIX_NONE, 16, 1, + rx->rx_buf, len, false); len = control_sdu_tx_flow(sdev, rx->rx_buf, len); spin_lock_irqsave(&rx->lock, flags); diff --git a/drivers/staging/gdm72xx/gdm_usb.c b/drivers/staging/gdm72xx/gdm_usb.c index cdeffe75496b..20539d809397 100644 --- a/drivers/staging/gdm72xx/gdm_usb.c +++ b/drivers/staging/gdm72xx/gdm_usb.c @@ -55,22 +55,6 @@ static int k_mode_stop; static int init_usb(struct usbwm_dev *udev); static void release_usb(struct usbwm_dev *udev); -/*#define DEBUG */ -#ifdef DEBUG -static void hexdump(char *title, u8 *data, int len) -{ - int i; - - printk(KERN_DEBUG "%s: length = %d\n", title, len); - for (i = 0; i < len; i++) { - printk(KERN_DEBUG "%02x ", data[i]); - if ((i & 0xf) == 0xf) - printk(KERN_DEBUG "\n"); - } - printk(KERN_DEBUG "\n"); -} -#endif - static struct usb_tx *alloc_tx_struct(struct tx_cxt *tx) { struct usb_tx *t = kzalloc(sizeof(*t), GFP_ATOMIC); @@ -368,9 +352,8 @@ static int gdm_usb_send(void *priv_dev, void *data, int len, gdm_usb_send_complete, t); -#ifdef DEBUG - hexdump("usb_send", t->buf, len + padding); -#endif + print_hex_dump_debug("usb_send: ", DUMP_PREFIX_NONE, 16, 1, + t->buf, len + padding, false); #ifdef CONFIG_WIMAX_GDM72XX_USB_PM if (usbdev->state & USB_STATE_SUSPENDED) { list_add_tail(&t->p_list, &tx->pending_list); @@ -438,10 +421,7 @@ static void gdm_usb_rcv_complete(struct urb *urb) struct usb_tx *t; u16 cmd_evt; unsigned long flags, flags2; - -#ifdef CONFIG_WIMAX_GDM72XX_USB_PM struct usb_device *dev = urb->dev; -#endif /* Completion by usb_unlink_urb */ if (urb->status == -ECONNRESET) @@ -451,20 +431,15 @@ static void gdm_usb_rcv_complete(struct urb *urb) if (!urb->status) { cmd_evt = (r->buf[0] << 8) | (r->buf[1]); -#ifdef DEBUG - hexdump("usb_receive", r->buf, urb->actual_length); -#endif + print_hex_dump_debug("usb_receive: ", DUMP_PREFIX_NONE, 16, 1, + r->buf, urb->actual_length, false); if (cmd_evt == WIMAX_SDU_TX_FLOW) { if (r->buf[4] == 0) { -#ifdef DEBUG - printk(KERN_DEBUG "WIMAX ==> STOP SDU TX\n"); -#endif + dev_dbg(&dev->dev, "WIMAX ==> STOP SDU TX\n"); list_for_each_entry(t, &tx->sdu_list, list) usb_unlink_urb(t->urb); } else if (r->buf[4] == 1) { -#ifdef DEBUG - printk(KERN_DEBUG "WIMAX ==> START SDU TX\n"); -#endif + dev_dbg(&dev->dev, "WIMAX ==> START SDU TX\n"); list_for_each_entry(t, &tx->sdu_list, list) { usb_submit_urb(t->urb, GFP_ATOMIC); } diff --git a/drivers/staging/gdm72xx/gdm_wimax.c b/drivers/staging/gdm72xx/gdm_wimax.c index dd854975db7d..05ce2a22c220 100644 --- a/drivers/staging/gdm72xx/gdm_wimax.c +++ b/drivers/staging/gdm72xx/gdm_wimax.c @@ -62,21 +62,6 @@ static u8 gdm_wimax_macaddr[6] = {0x00, 0x0a, 0x3b, 0xf0, 0x01, 0x30}; static void gdm_wimax_ind_fsm_update(struct net_device *dev, struct fsm_s *fsm); static void gdm_wimax_ind_if_updown(struct net_device *dev, int if_up); -#if defined(DEBUG_SDU) -static void printk_hex(u8 *buf, u32 size) -{ - int i; - - for (i = 0; i < size; i++) { - if (i && i % 16 == 0) - printk(KERN_DEBUG "\n%02x ", *buf++); - else - printk(KERN_DEBUG "%02x ", *buf++); - } - - printk(KERN_DEBUG "\n"); -} - static const char *get_protocol_name(u16 protocol) { static char buf[32]; @@ -140,7 +125,8 @@ static const char *get_port_name(u16 port) return buf; } -static void dump_eth_packet(const char *title, u8 *data, int len) +static void dump_eth_packet(struct net_device *dev, const char *title, + u8 *data, int len) { struct iphdr *ih = NULL; struct udphdr *uh = NULL; @@ -162,48 +148,21 @@ static void dump_eth_packet(const char *title, u8 *data, int len) port = ntohs(uh->dest); } - printk(KERN_DEBUG "[%s] len=%d, %s, %s, %s\n", + netdev_dbg(dev, "[%s] len=%d, %s, %s, %s\n", title, len, get_protocol_name(protocol), get_ip_protocol_name(ip_protocol), get_port_name(port)); if (!(data[0] == 0xff && data[1] == 0xff)) { - if (protocol == ETH_P_IP) { - printk(KERN_DEBUG " src=%pI4\n", &ih->saddr); - } else if (protocol == ETH_P_IPV6) { - printk(KERN_DEBUG " src=%pI6\n", &ih->saddr); - } + if (protocol == ETH_P_IP) + netdev_dbg(dev, " src=%pI4\n", &ih->saddr); + else if (protocol == ETH_P_IPV6) + netdev_dbg(dev, " src=%pI6\n", &ih->saddr); } - #if (DUMP_PACKET & DUMP_SDU_ALL) - printk_hex(data, len); - #else - #if (DUMP_PACKET & DUMP_SDU_ARP) - if (protocol == ETH_P_ARP) - printk_hex(data, len); - #endif - #if (DUMP_PACKET & DUMP_SDU_IP) - if (protocol == ETH_P_IP || protocol == ETH_P_IPV6) - printk_hex(data, len); - #else - #if (DUMP_PACKET & DUMP_SDU_IP_TCP) - if (ip_protocol == IPPROTO_TCP) - printk_hex(data, len); - #endif - #if (DUMP_PACKET & DUMP_SDU_IP_UDP) - if (ip_protocol == IPPROTO_UDP) - printk_hex(data, len); - #endif - #if (DUMP_PACKET & DUMP_SDU_IP_ICMP) - if (ip_protocol == IPPROTO_ICMP) - printk_hex(data, len); - #endif - #endif - #endif + print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, data, len, false); } -#endif - static inline int gdm_wimax_header(struct sk_buff **pskb) { @@ -237,12 +196,10 @@ static void gdm_wimax_event_rcv(struct net_device *dev, u16 type, void *msg, { struct nic *nic = netdev_priv(dev); - #if defined(DEBUG_HCI) u8 *buf = (u8 *) msg; u16 hci_cmd = (buf[0]<<8) | buf[1]; u16 hci_len = (buf[2]<<8) | buf[3]; - printk(KERN_DEBUG "H=>D: 0x%04x(%d)\n", hci_cmd, hci_len); - #endif + netdev_dbg(dev, "H=>D: 0x%04x(%d)\n", hci_cmd, hci_len); gdm_wimax_send(nic, msg, len); } @@ -351,11 +308,9 @@ static int gdm_wimax_event_send(struct net_device *dev, char *buf, int size) struct evt_entry *e; unsigned long flags; - #if defined(DEBUG_HCI) u16 hci_cmd = ((u8)buf[0]<<8) | (u8)buf[1]; u16 hci_len = ((u8)buf[2]<<8) | (u8)buf[3]; - printk(KERN_DEBUG "D=>H: 0x%04x(%d)\n", hci_cmd, hci_len); - #endif + netdev_dbg(dev, "D=>H: 0x%04x(%d)\n", hci_cmd, hci_len); spin_lock_irqsave(&wm_event.evt_lock, flags); @@ -415,9 +370,7 @@ static int gdm_wimax_tx(struct sk_buff *skb, struct net_device *dev) struct nic *nic = netdev_priv(dev); struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf; - #if defined(DEBUG_SDU) - dump_eth_packet("TX", skb->data, skb->len); - #endif + dump_eth_packet(dev, "TX", skb->data, skb->len); ret = gdm_wimax_header(&skb); if (ret < 0) { @@ -540,7 +493,7 @@ static int gdm_wimax_ioctl_get_data(struct data_s *dst, struct data_s *src) if (src->size) { if (!dst->buf) return -EINVAL; - if (copy_to_user(dst->buf, src->buf, size)) + if (copy_to_user((void __user *)dst->buf, src->buf, size)) return -EFAULT; } return 0; @@ -563,7 +516,7 @@ static int gdm_wimax_ioctl_set_data(struct data_s *dst, struct data_s *src) return -ENOMEM; } - if (copy_from_user(dst->buf, src->buf, src->size)) { + if (copy_from_user(dst->buf, (void __user *)src->buf, src->size)) { kdelete(&dst->buf); return -EFAULT; } @@ -756,9 +709,7 @@ static void gdm_wimax_netif_rx(struct net_device *dev, char *buf, int len) struct sk_buff *skb; int ret; - #if defined(DEBUG_SDU) - dump_eth_packet("RX", buf, len); - #endif + dump_eth_packet(dev, "RX", buf, len); skb = dev_alloc_skb(len + 2); if (!skb) { diff --git a/drivers/staging/gdm72xx/gdm_wimax.h b/drivers/staging/gdm72xx/gdm_wimax.h index 6ec0ab43e9cc..1fcfc8555417 100644 --- a/drivers/staging/gdm72xx/gdm_wimax.h +++ b/drivers/staging/gdm72xx/gdm_wimax.h @@ -62,26 +62,6 @@ struct nic { }; - -#if 0 -#define dprintk(fmt, args ...) printk(KERN_DEBUG " [GDM] " fmt, ## args) -#else -#define dprintk(...) -#endif - -/*#define DEBUG_SDU */ -#if defined(DEBUG_SDU) -#define DUMP_SDU_ALL (1<<0) -#define DUMP_SDU_ARP (1<<1) -#define DUMP_SDU_IP (1<<2) -#define DUMP_SDU_IP_TCP (1<<8) -#define DUMP_SDU_IP_UDP (1<<9) -#define DUMP_SDU_IP_ICMP (1<<10) -#define DUMP_PACKET (DUMP_SDU_ALL) -#endif - -/*#define DEBUG_HCI */ - /*#define LOOPBACK_TEST */ extern int register_wimax_device(struct phy_dev *phy_dev, struct device *pdev); diff --git a/drivers/staging/gs_fpgaboot/Kconfig b/drivers/staging/gs_fpgaboot/Kconfig new file mode 100644 index 000000000000..550645291fab --- /dev/null +++ b/drivers/staging/gs_fpgaboot/Kconfig @@ -0,0 +1,8 @@ +# +# "xilinx FPGA firmware download, fpgaboot" +# +config GS_FPGABOOT + tristate "Xilinx FPGA firmware download module" + default n + help + Xilinx FPGA firmware download module diff --git a/drivers/staging/gs_fpgaboot/Makefile b/drivers/staging/gs_fpgaboot/Makefile new file mode 100644 index 000000000000..34cb606e0e3d --- /dev/null +++ b/drivers/staging/gs_fpgaboot/Makefile @@ -0,0 +1,4 @@ +gs_fpga-y += gs_fpgaboot.o io.o +obj-$(CONFIG_GS_FPGABOOT) += gs_fpga.o + +ccflags-$(CONFIG_GS_FPGA_DEBUG) := -DDEBUG diff --git a/drivers/staging/gs_fpgaboot/README b/drivers/staging/gs_fpgaboot/README new file mode 100644 index 000000000000..cfa8624304e5 --- /dev/null +++ b/drivers/staging/gs_fpgaboot/README @@ -0,0 +1,71 @@ +============================================================================== +Linux Driver Source for Xilinx FPGA firmware download +============================================================================== + + +TABLE OF CONTENTS. + +1. SUMMARY +2. BACKGROUND +3. DESIGN +4. HOW TO USE +5. REFERENCE + +1. SUMMARY + + - Download Xilinx FPGA firmware + - This module downloads Xilinx FPGA firmware using gpio pins. + +2. BACKGROUND + + An FPGA (Field Programmable Gate Array) is a programmable hardware that is + used in various applications. Hardware design needs to programmed through + a dedicated device or CPU assisted way (serial or parallel). + This driver provides a way to download FPGA firmware. + +3. DESIGN + + - load Xilinx FPGA bitstream format[1] firmware image file using + kernel firmware framework, request_firmware() + - program the Xilinx FPGA using SelectMAP (parallel) mode [2] + - FPGA prgram is done by gpio based bit-banging, as an example + - platform independent file: gs_fpgaboot.c + - platform dependent file: io.c + + +4. HOW TO USE + + $ insmod gs_fpga.ko file="xlinx_fpga_top_bitstream.bit" + $ rmmod gs_fpga + +5. USE CASE (from a mailing list discussion with Greg) + + a. As a FPGA development support tool, + During FPGA firmware development, you need to download a new FPGA + image frequently. + You would do that with a dedicated JTAG, which usually a limited + resource in the lab. + However, if you use my driver, you don't have to have a dedicated JTAG. + This is a real gain :) + + b. For the FPGA that runs without config after the download, which + doesn't talk to any of Linux interfaces (such as PCIE). + + We download FPGA firmware from user triggered or some other way, and that's it. + Since that FPGA runs on its own, it doesn't require a linux driver + after the download. + + c. For the FPGA that requires config after the download, which talk to + any of linux interfaces (such as PCIE) + + Then, this type of FPGA config can be put into device tree and have a + separate driver (pcie or others), then THAT driver calls my driver to + download FPGA firmware during the Linux boot, the take over the device + through the interface. + +6. REFERENCE + + 1. Xilinx APP NOTE XAPP583: + http://www.xilinx.com/support/documentation/application_notes/xapp583-fpga-configuration.pdf + 2. bitstream file info: + http://home.earthlink.net/~davesullins/software/bitinfo.html diff --git a/drivers/staging/gs_fpgaboot/TODO b/drivers/staging/gs_fpgaboot/TODO new file mode 100644 index 000000000000..2d9fb17d606d --- /dev/null +++ b/drivers/staging/gs_fpgaboot/TODO @@ -0,0 +1,7 @@ +TODO: + - get bus width input instead of hardcoded bus width + - get it reviewed + +Please send any patches for this driver to Insop Song +and Greg Kroah-Hartman . +And please CC to "Staging subsystem" mail list too. diff --git a/drivers/staging/gs_fpgaboot/gs_fpgaboot.c b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c new file mode 100644 index 000000000000..89bc84d833e6 --- /dev/null +++ b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c @@ -0,0 +1,422 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gs_fpgaboot.h" +#include "io.h" + +#define DEVICE_NAME "device" +#define CLASS_NAME "fpgaboot" + +static uint8_t bits_magic[] = { + 0x0, 0x9, 0xf, 0xf0, 0xf, 0xf0, + 0xf, 0xf0, 0xf, 0xf0, 0x0, 0x0, 0x1}; + +/* fake device for request_firmware */ +static struct platform_device *firmware_pdev; + +static char *file = "xlinx_fpga_firmware.bit"; +module_param(file, charp, S_IRUGO); +MODULE_PARM_DESC(file, "Xilinx FPGA firmware file."); + +#ifdef DEBUG_FPGA +static void datadump(char *msg, void *m, int n) +{ + int i; + unsigned char *c; + + pr_info("=== %s ===\n", msg); + + c = m; + + for (i = 0; i < n; i++) { + if ((i&0xf) == 0) + pr_info(KERN_INFO "\n 0x%4x: ", i); + + pr_info("%02X ", c[i]); + } + + pr_info("\n"); +} +#endif /* DEBUG_FPGA */ + +static void read_bitstream(char *bitdata, char *buf, int *offset, int rdsize) +{ + memcpy(buf, bitdata + *offset, rdsize); + *offset += rdsize; +} + +static void readinfo_bitstream(char *bitdata, char *buf, int *offset) +{ + char tbuf[64]; + int32_t len; + + /* read section char */ + read_bitstream(bitdata, tbuf, offset, 1); + + /* read length */ + read_bitstream(bitdata, tbuf, offset, 2); + + len = tbuf[0] << 8 | tbuf[1]; + + read_bitstream(bitdata, buf, offset, len); + buf[len] = '\0'; +} + +/* + * read bitdata length + */ +static int readlength_bitstream(char *bitdata, int *lendata, int *offset) +{ + char tbuf[64]; + + /* read section char */ + read_bitstream(bitdata, tbuf, offset, 1); + + /* make sure it is section 'e' */ + if (tbuf[0] != 'e') { + pr_err("error: length section is not 'e', but %c\n", tbuf[0]); + return -1; + } + + /* read 4bytes length */ + read_bitstream(bitdata, tbuf, offset, 4); + + *lendata = tbuf[0] << 24 | tbuf[1] << 16 | + tbuf[2] << 8 | tbuf[3]; + + return 0; +} + + +/* + * read first 13 bytes to check bitstream magic number + */ +static int readmagic_bitstream(char *bitdata, int *offset) +{ + char buf[13]; + int r; + + read_bitstream(bitdata, buf, offset, 13); + r = memcmp(buf, bits_magic, 13); + if (r) { + pr_err("error: corrupted header"); + return -1; + } + pr_info("bitstream file magic number Ok\n"); + + *offset = 13; /* magic length */ + + return 0; +} + +/* + * NOTE: supports only bitstream format + */ +static enum fmt_image get_imageformat(struct fpgaimage *fimage) +{ + return f_bit; +} + +static void gs_print_header(struct fpgaimage *fimage) +{ + pr_info("file: %s\n", fimage->filename); + pr_info("part: %s\n", fimage->part); + pr_info("date: %s\n", fimage->date); + pr_info("time: %s\n", fimage->time); + pr_info("lendata: %d\n", fimage->lendata); +} + +static void gs_read_bitstream(struct fpgaimage *fimage) +{ + char *bitdata; + int size; + int offset; + + offset = 0; + bitdata = (char *)fimage->fw_entry->data; + size = fimage->fw_entry->size; + + readmagic_bitstream(bitdata, &offset); + readinfo_bitstream(bitdata, fimage->filename, &offset); + readinfo_bitstream(bitdata, fimage->part, &offset); + readinfo_bitstream(bitdata, fimage->date, &offset); + readinfo_bitstream(bitdata, fimage->time, &offset); + readlength_bitstream(bitdata, &fimage->lendata, &offset); + + fimage->fpgadata = bitdata + offset; +} + +static int gs_read_image(struct fpgaimage *fimage) +{ + int img_fmt; + + img_fmt = get_imageformat(fimage); + + switch (img_fmt) { + case f_bit: + pr_info("image is bitstream format\n"); + gs_read_bitstream(fimage); + break; + default: + pr_err("unsupported fpga image format\n"); + return -1; + } + + gs_print_header(fimage); + + return 0; +} + +static int gs_load_image(struct fpgaimage *fimage, char *file) +{ + int err; + + pr_info("load fpgaimage %s\n", file); + + err = request_firmware(&fimage->fw_entry, file, &firmware_pdev->dev); + if (err != 0) { + pr_err("firmware %s is missing, cannot continue.\n", file); + return err; + } + + return 0; +} + +static int gs_download_image(struct fpgaimage *fimage, enum wbus bus_bytes) +{ + char *bitdata; + int size, i, cnt; + cnt = 0; + + bitdata = (char *)fimage->fpgadata; + size = fimage->lendata; + +#ifdef DEBUG_FPGA + datadump("bitfile sample", bitdata, 0x100); +#endif /* DEBUG_FPGA */ + + if (!xl_supported_prog_bus_width(bus_bytes)) { + pr_err("unsupported program bus width %d\n", + bus_bytes); + return -1; + } + + /* Bring csi_b, rdwr_b Low and program_b High */ + xl_program_b(1); + xl_rdwr_b(0); + xl_csi_b(0); + + /* Configuration reset */ + xl_program_b(0); + msleep(20); + xl_program_b(1); + + /* Wait for Device Initialization */ + while (xl_get_init_b() == 0) + ; + + pr_info("device init done\n"); + + for (i = 0; i < size; i += bus_bytes) + xl_shift_bytes_out(bus_bytes, bitdata+i); + + pr_info("program done\n"); + + /* Check INIT_B */ + if (xl_get_init_b() == 0) { + pr_err("init_b 0\n"); + return -1; + } + + while (xl_get_done_b() == 0) { + if (cnt++ > MAX_WAIT_DONE) { + pr_err("init_B %d\n", xl_get_init_b()); + break; + } + } + + if (cnt > MAX_WAIT_DONE) { + pr_err("fpga download fail\n"); + return -1; + } + + pr_info("download fpgaimage\n"); + + /* Compensate for Special Startup Conditions */ + xl_shift_cclk(8); + + return 0; +} + +static int gs_release_image(struct fpgaimage *fimage) +{ + release_firmware(fimage->fw_entry); + pr_info("release fpgaimage\n"); + + return 0; +} + +/* + * NOTE: supports systemmap parallel programming + */ +static int gs_set_download_method(struct fpgaimage *fimage) +{ + pr_info("set program method\n"); + + fimage->dmethod = m_systemmap; + + pr_info("systemmap program method\n"); + + return 0; +} + +static int init_driver(void) +{ + firmware_pdev = platform_device_register_simple("fpgaboot", -1, + NULL, 0); + return PTR_ERR_OR_ZERO(firmware_pdev); +} + +static void finish_driver(void) +{ + platform_device_unregister(firmware_pdev); +} + +static int gs_fpgaboot(void) +{ + int err; + struct fpgaimage *fimage; + + fimage = kmalloc(sizeof(struct fpgaimage), GFP_KERNEL); + if (fimage == NULL) { + pr_err("No memory is available\n"); + goto err_out; + } + + err = gs_load_image(fimage, file); + if (err) { + pr_err("gs_load_image error\n"); + goto err_out1; + } + + err = gs_read_image(fimage); + if (err) { + pr_err("gs_read_image error\n"); + goto err_out2; + } + + err = gs_set_download_method(fimage); + if (err) { + pr_err("gs_set_download_method error\n"); + goto err_out2; + } + + err = gs_download_image(fimage, bus_2byte); + if (err) { + pr_err("gs_download_image error\n"); + goto err_out2; + } + + err = gs_release_image(fimage); + if (err) { + pr_err("gs_release_image error\n"); + goto err_out1; + } + + kfree(fimage); + return 0; + +err_out2: + err = gs_release_image(fimage); + if (err) + pr_err("gs_release_image error\n"); +err_out1: + kfree(fimage); + +err_out: + return -1; + +} + +static int __init gs_fpgaboot_init(void) +{ + int err, r; + + r = -1; + + pr_info("FPGA DOWNLOAD --->\n"); + pr_info("built at %s UTC\n", __TIMESTAMP__); + + pr_info("FPGA image file name: %s\n", file); + + err = init_driver(); + if (err != 0) { + pr_err("FPGA DRIVER INIT FAIL!!\n"); + return r; + } + + err = xl_init_io(); + if (err) { + pr_err("GPIO INIT FAIL!!\n"); + r = -1; + goto errout; + } + + err = gs_fpgaboot(); + if (err) { + pr_err("FPGA DOWNLOAD FAIL!!\n"); + r = -1; + goto errout; + } + + pr_info("FPGA DOWNLOAD DONE <---\n"); + + r = 0; + return r; + +errout: + finish_driver(); + + return r; +} + +static void __exit gs_fpgaboot_exit(void) +{ + finish_driver(); + pr_info("FPGA image download module removed\n"); +} + +module_init(gs_fpgaboot_init); +module_exit(gs_fpgaboot_exit); + +MODULE_AUTHOR("Insop Song"); +MODULE_DESCRIPTION("Xlinix FPGA firmware download"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/gs_fpgaboot/gs_fpgaboot.h b/drivers/staging/gs_fpgaboot/gs_fpgaboot.h new file mode 100644 index 000000000000..f41f4cc798cc --- /dev/null +++ b/drivers/staging/gs_fpgaboot/gs_fpgaboot.h @@ -0,0 +1,56 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#define MAX_STR 256 + +enum fmt_image { + f_bit, /* only bitstream is supported */ + f_rbt, + f_bin, + f_mcs, + f_hex, +}; + +enum mdownload { + m_systemmap, /* only system map is supported */ + m_serial, + m_jtag, +}; + +/* + * xilinx fpgaimage information + * NOTE: use MAX_STR instead of dynamic alloc for simplicity + */ +struct fpgaimage { + enum fmt_image fmt_img; + enum mdownload dmethod; + + const struct firmware *fw_entry; + + /* + * the followings can be read from bitstream, + * but other image format should have as well + */ + char filename[MAX_STR]; + char part[MAX_STR]; + char date[MAX_STR]; + char time[MAX_STR]; + int32_t lendata; + char *fpgadata; +}; diff --git a/drivers/staging/gs_fpgaboot/io.c b/drivers/staging/gs_fpgaboot/io.c new file mode 100644 index 000000000000..b7be8e37b8d1 --- /dev/null +++ b/drivers/staging/gs_fpgaboot/io.c @@ -0,0 +1,294 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "io.h" + +#ifdef CONFIG_B4860G100 +static struct gpiobus gbus; +#endif /* CONFIG_B4860G100 */ + +static inline void byte0_out(unsigned char data); +static inline void byte1_out(unsigned char data); +static inline void xl_cclk_b(int32_t i); + + +/* Assert and Deassert CCLK */ +void xl_shift_cclk(int count) +{ + int i; + for (i = 0; i < count; i++) { + xl_cclk_b(1); + xl_cclk_b(0); + } +} + +int xl_supported_prog_bus_width(enum wbus bus_bytes) +{ + switch (bus_bytes) { + case bus_1byte: + break; + case bus_2byte: + break; + default: + pr_err("unsupported program bus width %d\n", + bus_bytes); + return 0; + } + + return 1; +} + +/* Serialize byte and clock each bit on target's DIN and CCLK pins */ +void xl_shift_bytes_out(enum wbus bus_byte, unsigned char *pdata) +{ + /* + * supports 1 and 2 bytes programming mode + */ + if (likely(bus_byte == bus_2byte)) + byte0_out(pdata[0]); + + byte1_out(pdata[1]); + xl_shift_cclk(1); +} + +/* + * generic bit swap for xilinx SYSTEMMAP FPGA programming + */ +static inline unsigned char bitswap(unsigned char s) +{ + unsigned char d; + d = (((s&0x80)>>7) | ((s&0x40)>>5) | ((s&0x20)>>3) | ((s&0x10)>>1) | + ((s&0x08)<<1) | ((s&0x04)<<3) | ((s&0x02)<<5) | ((s&0x01)<<7)); + return d; +} + +#ifdef CONFIG_B4860G100 +/* + * ====================================================================== + * board specific configuration + */ + +static inline void mpc85xx_gpio_set_dir( + int32_t port, + uint32_t mask, + uint32_t dir) +{ + dir |= (in_be32(gbus.r[port]+GPDIR) & ~mask); + out_be32(gbus.r[port]+GPDIR, dir); +} + +static inline void mpc85xx_gpio_set(int32_t port, uint32_t mask, uint32_t val) +{ + /* First mask off the unwanted parts of "dir" and "val" */ + val &= mask; + + /* Now read in the values we're supposed to preserve */ + val |= (in_be32(gbus.r[port]+GPDAT) & ~mask); + + out_be32(gbus.r[port]+GPDAT, val); +} + +static inline uint32_t mpc85xx_gpio_get(int32_t port, uint32_t mask) +{ + /* Read the requested values */ + return in_be32(gbus.r[port]+GPDAT) & mask; +} + +static inline void mpc85xx_gpio_set_low(int32_t port, uint32_t gpios) +{ + mpc85xx_gpio_set(port, gpios, 0x00000000); +} + +static inline void mpc85xx_gpio_set_high(int32_t port, uint32_t gpios) +{ + mpc85xx_gpio_set(port, gpios, 0xFFFFFFFF); +} + +static inline void gpio_set_value(int32_t port, uint32_t gpio, uint32_t value) +{ + int32_t g; + g = 31 - gpio; + if (value) + mpc85xx_gpio_set_high(port, 1U << g); + else + mpc85xx_gpio_set_low(port, 1U << g); +} + +static inline int gpio_get_value(int32_t port, uint32_t gpio) +{ + int32_t g; + g = 31 - gpio; + return !!mpc85xx_gpio_get(port, 1U << g); +} + +static inline void xl_cclk_b(int32_t i) +{ + gpio_set_value(XL_CCLK_PORT, XL_CCLK_PIN, i); +} + +void xl_program_b(int32_t i) +{ + gpio_set_value(XL_PROGN_PORT, XL_PROGN_PIN, i); +} + +void xl_rdwr_b(int32_t i) +{ + gpio_set_value(XL_RDWRN_PORT, XL_RDWRN_PIN, i); +} + +void xl_csi_b(int32_t i) +{ + gpio_set_value(XL_CSIN_PORT, XL_CSIN_PIN, i); +} + +int xl_get_init_b(void) +{ + return gpio_get_value(XL_INITN_PORT, XL_INITN_PIN); +} + +int xl_get_done_b(void) +{ + return gpio_get_value(XL_DONE_PORT, XL_DONE_PIN); +} + + +/* G100 specific bit swap and remmap (to gpio pins) for byte 0 */ +static inline uint32_t bit_remap_byte0(uint32_t s) +{ + uint32_t d; + d = (((s&0x80)>>7) | ((s&0x40)>>5) | ((s&0x20)>>3) | ((s&0x10)>>1) | + ((s&0x08)<<1) | ((s&0x04)<<3) | ((s&0x02)<<6) | ((s&0x01)<<9)); + return d; +} + +/* + * G100 specific MSB, in this order [byte0 | byte1], out + */ +static inline void byte0_out(unsigned char data) +{ + uint32_t swap32; + swap32 = bit_remap_byte0((uint32_t) data) << 8; + + mpc85xx_gpio_set(0, 0x0002BF00, (uint32_t) swap32); +} + +/* + * G100 specific LSB, in this order [byte0 | byte1], out + */ +static inline void byte1_out(unsigned char data) +{ + mpc85xx_gpio_set(0, 0x000000FF, (uint32_t) bitswap(data)); +} + +/* + * configurable per device type for different I/O config + */ +int xl_init_io(void) +{ + struct device_node *np; + const u32 *p_reg; + int reg, cnt; + + cnt = 0; + memset(&gbus, 0, sizeof(struct gpiobus)); + for_each_compatible_node(np, NULL, "fsl,qoriq-gpio") { + p_reg = of_get_property(np, "reg", NULL); + if (p_reg == NULL) + break; + reg = (int) *p_reg; + gbus.r[cnt] = of_iomap(np, 0); + + if (!gbus.r[cnt]) { + pr_err("not findding gpio cell-index %d\n", cnt); + return -ENODEV; + } + cnt++; + } + mpc85xx_gpio_set_dir(0, 0x0002BFFF, 0x0002BFFF); + mpc85xx_gpio_set_dir(1, 0x00240060, 0x00240060); + + gbus.ngpio = cnt; + + return 0; +} + + +#else /* placeholder for boards with different config */ + +void xl_program_b(int32_t i) +{ + return; +} + +void xl_rdwr_b(int32_t i) +{ + return; +} + +void xl_csi_b(int32_t i) +{ + return; +} + +int xl_get_init_b(void) +{ + return -1; +} + +int xl_get_done_b(void) +{ + return -1; +} + +static inline void byte0_out(unsigned char data) +{ + return; +} + +static inline void byte1_out(unsigned char data) +{ + return; +} + +static inline void xl_cclk_b(int32_t i) +{ + return; +} + +/* + * configurable per device type for different I/O config + */ +int xl_init_io(void) +{ + return -1; +} + +#endif /* CONFIG_B4860G100 */ diff --git a/drivers/staging/gs_fpgaboot/io.h b/drivers/staging/gs_fpgaboot/io.h new file mode 100644 index 000000000000..7b46ac24b74e --- /dev/null +++ b/drivers/staging/gs_fpgaboot/io.h @@ -0,0 +1,90 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define GPDIR 0 +#define GPCFG 4 /* open drain or not */ +#define GPDAT 8 + +/* + * gpio port and pin definitions + * NOTE: port number starts from 0 + */ +#define XL_INITN_PORT 1 +#define XL_INITN_PIN 14 +#define XL_RDWRN_PORT 1 +#define XL_RDWRN_PIN 13 +#define XL_CCLK_PORT 1 +#define XL_CCLK_PIN 10 +#define XL_PROGN_PORT 1 +#define XL_PROGN_PIN 25 +#define XL_CSIN_PORT 1 +#define XL_CSIN_PIN 26 +#define XL_DONE_PORT 1 +#define XL_DONE_PIN 27 + +/* + * gpio mapping + * + XL_config_D0 – gpio1_31 + Xl_config_d1 – gpio1_30 + Xl_config_d2 – gpio1_29 + Xl_config_d3 – gpio1_28 + Xl_config_d4 – gpio1_27 + Xl_config_d5 – gpio1_26 + Xl_config_d6 – gpio1_25 + Xl_config_d7 – gpio1_24 + Xl_config_d8 – gpio1_23 + Xl_config_d9 – gpio1_22 + Xl_config_d10 – gpio1_21 + Xl_config_d11 – gpio1_20 + Xl_config_d12 – gpio1_19 + Xl_config_d13 – gpio1_18 + Xl_config_d14 – gpio1_16 + Xl_config_d15 – gpio1_14 +* +*/ + +/* + * program bus width in bytes + */ +enum wbus { + bus_1byte = 1, + bus_2byte = 2, +}; + + +#define MAX_WAIT_DONE 10000 + + +struct gpiobus { + int ngpio; + void __iomem *r[4]; +}; + +int xl_supported_prog_bus_width(enum wbus bus_bytes); + +void xl_program_b(int32_t i); +void xl_rdwr_b(int32_t i); +void xl_csi_b(int32_t i); + +int xl_get_init_b(void); +int xl_get_done_b(void); + +void xl_shift_cclk(int count); +void xl_shift_bytes_out(enum wbus bus_byte, unsigned char *pdata); + +int xl_init_io(void); diff --git a/drivers/staging/iio/Documentation/iio_utils.h b/drivers/staging/iio/Documentation/iio_utils.h index c9fedb79e3a2..2064839ef2cd 100644 --- a/drivers/staging/iio/Documentation/iio_utils.h +++ b/drivers/staging/iio/Documentation/iio_utils.h @@ -652,3 +652,25 @@ error_free: free(temp); return ret; } + +read_sysfs_string(const char *filename, const char *basedir, char *str) +{ + float ret = 0; + FILE *sysfsfp; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + if (temp == NULL) { + printf("Memory allocation failed"); + return -ENOMEM; + } + sprintf(temp, "%s/%s", basedir, filename); + sysfsfp = fopen(temp, "r"); + if (sysfsfp == NULL) { + ret = -errno; + goto error_free; + } + fscanf(sysfsfp, "%s\n", str); + fclose(sysfsfp); +error_free: + free(temp); + return ret; +} diff --git a/drivers/staging/iio/Documentation/lsiio.c b/drivers/staging/iio/Documentation/lsiio.c new file mode 100644 index 000000000000..24ae9694eb41 --- /dev/null +++ b/drivers/staging/iio/Documentation/lsiio.c @@ -0,0 +1,157 @@ +/* + * Industrial I/O utilities - lsiio.c + * + * Copyright (c) 2010 Manuel Stahl + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iio_utils.h" + + +static enum verbosity { + VERBLEVEL_DEFAULT, /* 0 gives lspci behaviour */ + VERBLEVEL_SENSORS, /* 1 lists sensors */ +} verblevel = VERBLEVEL_DEFAULT; + +const char *type_device = "iio:device"; +const char *type_trigger = "trigger"; + + +static inline int check_prefix(const char *str, const char *prefix) +{ + return strlen(str) > strlen(prefix) && + strncmp(str, prefix, strlen(prefix)) == 0; +} + +static inline int check_postfix(const char *str, const char *postfix) +{ + return strlen(str) > strlen(postfix) && + strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; +} + +static int dump_channels(const char *dev_dir_name) +{ + DIR *dp; + const struct dirent *ent; + dp = opendir(dev_dir_name); + if (dp == NULL) + return -errno; + while (ent = readdir(dp), ent != NULL) + if (check_prefix(ent->d_name, "in_") && + check_postfix(ent->d_name, "_raw")) { + printf(" %-10s\n", ent->d_name); + } + + return 0; +} + +static int dump_one_device(const char *dev_dir_name) +{ + char name[IIO_MAX_NAME_LENGTH]; + int dev_idx; + + sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_device), + "%i", &dev_idx); + read_sysfs_string("name", dev_dir_name, name); + printf("Device %03d: %s\n", dev_idx, name); + + if (verblevel >= VERBLEVEL_SENSORS) { + int ret = dump_channels(dev_dir_name); + if (ret) + return ret; + } + return 0; +} + +static int dump_one_trigger(const char *dev_dir_name) +{ + char name[IIO_MAX_NAME_LENGTH]; + int dev_idx; + + sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_trigger), + "%i", &dev_idx); + read_sysfs_string("name", dev_dir_name, name); + printf("Trigger %03d: %s\n", dev_idx, name); + return 0; +} + +static void dump_devices(void) +{ + const struct dirent *ent; + int number, numstrlen; + + FILE *nameFile; + DIR *dp; + char thisname[IIO_MAX_NAME_LENGTH]; + char *filename; + + dp = opendir(iio_dir); + if (dp == NULL) { + printf("No industrial I/O devices available\n"); + return; + } + + while (ent = readdir(dp), ent != NULL) { + if (check_prefix(ent->d_name, type_device)) { + char *dev_dir_name; + asprintf(&dev_dir_name, "%s%s", iio_dir, ent->d_name); + dump_one_device(dev_dir_name); + free(dev_dir_name); + if (verblevel >= VERBLEVEL_SENSORS) + printf("\n"); + } + } + rewinddir(dp); + while (ent = readdir(dp), ent != NULL) { + if (check_prefix(ent->d_name, type_trigger)) { + char *dev_dir_name; + asprintf(&dev_dir_name, "%s%s", iio_dir, ent->d_name); + dump_one_trigger(dev_dir_name); + free(dev_dir_name); + } + } + closedir(dp); +} + +int main(int argc, char **argv) +{ + int c, err = 0; + + while ((c = getopt(argc, argv, "d:D:v")) != EOF) { + switch (c) { + case 'v': + verblevel++; + break; + + case '?': + default: + err++; + break; + } + } + if (err || argc > optind) { + fprintf(stderr, "Usage: lsiio [options]...\n" + "List industrial I/O devices\n" + " -v, --verbose\n" + " Increase verbosity (may be given multiple times)\n" + ); + exit(1); + } + + dump_devices(); + + return 0; +} diff --git a/drivers/staging/iio/accel/sca3000.h b/drivers/staging/iio/accel/sca3000.h index c1016c510dae..b284e5a6cac1 100644 --- a/drivers/staging/iio/accel/sca3000.h +++ b/drivers/staging/iio/accel/sca3000.h @@ -65,7 +65,8 @@ #define SCA3000_RING_BUF_ENABLE 0x80 #define SCA3000_RING_BUF_8BIT 0x40 -/* Free fall detection triggers an interrupt if the acceleration +/* + * Free fall detection triggers an interrupt if the acceleration * is below a threshold for equivalent of 25cm drop */ #define SCA3000_FREE_FALL_DETECT 0x10 @@ -73,8 +74,9 @@ #define SCA3000_MEAS_MODE_OP_1 0x01 #define SCA3000_MEAS_MODE_OP_2 0x02 -/* In motion detection mode the accelerations are band pass filtered - * (aprox 1 - 25Hz) and then a programmable threshold used to trigger +/* + * In motion detection mode the accelerations are band pass filtered + * (approx 1 - 25Hz) and then a programmable threshold used to trigger * and interrupt. */ #define SCA3000_MEAS_MODE_MOT_DET 0x03 @@ -99,8 +101,10 @@ #define SCA3000_REG_CTRL_SEL_MD_Y_TH 0x03 #define SCA3000_REG_CTRL_SEL_MD_X_TH 0x04 #define SCA3000_REG_CTRL_SEL_MD_Z_TH 0x05 -/* BE VERY CAREFUL WITH THIS, IF 3 BITS ARE NOT SET the device - will not function */ +/* + * BE VERY CAREFUL WITH THIS, IF 3 BITS ARE NOT SET the device + * will not function + */ #define SCA3000_REG_CTRL_SEL_OUT_CTRL 0x0B #define SCA3000_OUT_CTRL_PROT_MASK 0xE0 #define SCA3000_OUT_CTRL_BUF_X_EN 0x10 @@ -109,8 +113,9 @@ #define SCA3000_OUT_CTRL_BUF_DIV_4 0x02 #define SCA3000_OUT_CTRL_BUF_DIV_2 0x01 -/* Control which motion detector interrupts are on. - * For now only OR combinations are supported.x +/* + * Control which motion detector interrupts are on. + * For now only OR combinations are supported. */ #define SCA3000_MD_CTRL_PROT_MASK 0xC0 #define SCA3000_MD_CTRL_OR_Y 0x01 @@ -121,7 +126,8 @@ #define SCA3000_MD_CTRL_AND_X 0x10 #define SAC3000_MD_CTRL_AND_Z 0x20 -/* Some control registers of complex access methods requiring this register to +/* + * Some control registers of complex access methods requiring this register to * be used to remove a lock. */ #define SCA3000_REG_ADDR_UNLOCK 0x1e @@ -139,7 +145,8 @@ /* Values of multiplexed registers (write to ctrl_data after select) */ #define SCA3000_REG_ADDR_CTRL_DATA 0x22 -/* Measurement modes available on some sca3000 series chips. Code assumes others +/* + * Measurement modes available on some sca3000 series chips. Code assumes others * may become available in the future. * * Bypass - Bypass the low-pass filter in the signal channel so as to increase @@ -160,7 +167,6 @@ * struct sca3000_state - device instance state information * @us: the associated spi device * @info: chip variant information - * @indio_dev: device information used by the IIO core * @interrupt_handler_ws: event interrupt handler for all events * @last_timestamp: the timestamp of the last event * @mo_det_use_count: reference counter for the motion detection unit diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index 7f6ccdfaf168..ed30e32e60de 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -32,7 +32,8 @@ enum sca3000_variant { e05, }; -/* Note where option modes are not defined, the chip simply does not +/* + * Note where option modes are not defined, the chip simply does not * support any. * Other chips in the sca3000 series use i2c and are not included here. * @@ -191,7 +192,6 @@ error_ret: return ret; } -/* Crucial that lock is called before calling this */ /** * sca3000_read_ctrl_reg() read from lock protected control register. * @@ -250,9 +250,8 @@ error_ret: } #endif /* SCA3000_DEBUG */ - /** - * sca3000_show_reg() - sysfs interface to read the chip revision number + * sca3000_show_rev() - sysfs interface to read the chip revision number **/ static ssize_t sca3000_show_rev(struct device *dev, struct device_attribute *attr, @@ -312,7 +311,7 @@ sca3000_show_available_measurement_modes(struct device *dev, } /** - * sca3000_show_measurmenet_mode() sysfs read of current mode + * sca3000_show_measurement_mode() sysfs read of current mode **/ static ssize_t sca3000_show_measurement_mode(struct device *dev, @@ -403,7 +402,8 @@ error_ret: } -/* Not even vaguely standard attributes so defined here rather than +/* + * Not even vaguely standard attributes so defined here rather than * in the relevant IIO core headers */ static IIO_DEVICE_ATTR(measurement_mode_available, S_IRUGO, @@ -450,6 +450,18 @@ static const struct iio_chan_spec sca3000_channels[] = { SCA3000_CHAN(2, IIO_MOD_Z), }; +static const struct iio_chan_spec sca3000_channels_with_temp[] = { + SCA3000_CHAN(0, IIO_MOD_X), + SCA3000_CHAN(1, IIO_MOD_Y), + SCA3000_CHAN(2, IIO_MOD_Z), + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + }, +}; + static u8 sca3000_addresses[3][3] = { [0] = {SCA3000_REG_ADDR_X_MSB, SCA3000_REG_CTRL_SEL_MD_X_TH, SCA3000_MD_CTRL_OR_X}, @@ -472,19 +484,30 @@ static int sca3000_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: mutex_lock(&st->lock); - if (st->mo_det_use_count) { - mutex_unlock(&st->lock); - return -EBUSY; + if (chan->type == IIO_ACCEL) { + if (st->mo_det_use_count) { + mutex_unlock(&st->lock); + return -EBUSY; + } + address = sca3000_addresses[chan->address][0]; + ret = sca3000_read_data_short(st, address, 2); + if (ret < 0) { + mutex_unlock(&st->lock); + return ret; + } + *val = (be16_to_cpup((__be16 *)st->rx) >> 3) & 0x1FFF; + *val = ((*val) << (sizeof(*val)*8 - 13)) >> + (sizeof(*val)*8 - 13); + } else { + /* get the temperature when available */ + ret = sca3000_read_data_short(st, + SCA3000_REG_ADDR_TEMP_MSB, 2); + if (ret < 0) { + mutex_unlock(&st->lock); + return ret; + } + *val = ((st->rx[0] & 0x3F) << 3) | ((st->rx[1] & 0xE0) >> 5); } - address = sca3000_addresses[chan->address][0]; - ret = sca3000_read_data_short(st, address, 2); - if (ret < 0) { - mutex_unlock(&st->lock); - return ret; - } - *val = (be16_to_cpup((__be16 *)st->rx) >> 3) & 0x1FFF; - *val = ((*val) << (sizeof(*val)*8 - 13)) >> - (sizeof(*val)*8 - 13); mutex_unlock(&st->lock); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: @@ -494,6 +517,10 @@ static int sca3000_read_raw(struct iio_dev *indio_dev, else /* temperature */ *val2 = 555556; return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + *val = -214; + *val2 = 600000; + return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL; } @@ -547,7 +574,7 @@ error_ret: return ret; } /** - * __sca3000_get_base_frequency() obtain mode specific base frequency + * __sca3000_get_base_freq() obtain mode specific base frequency * * lock must be held **/ @@ -663,7 +690,8 @@ error_free_lock: return ret ? ret : len; } -/* Should only really be registered if ring buffer support is compiled in. +/* + * Should only really be registered if ring buffer support is compiled in. * Does no harm however and doing it right would add a fair bit of complexity */ static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(sca3000_read_av_freq); @@ -672,37 +700,6 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, sca3000_read_frequency, sca3000_set_frequency); - -/** - * sca3000_read_temp() sysfs interface to get the temperature when available - * -* The alignment of data in here is downright odd. See data sheet. -* Converting this into a meaningful value is left to inline functions in -* userspace part of header. -**/ -static ssize_t sca3000_read_temp(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - int val; - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_TEMP_MSB, 2); - if (ret < 0) - goto error_ret; - val = ((st->rx[0] & 0x3F) << 3) | ((st->rx[1] & 0xE0) >> 5); - - return sprintf(buf, "%d\n", val); - -error_ret: - return ret; -} -static IIO_DEV_ATTR_TEMP_RAW(sca3000_read_temp); - -static IIO_CONST_ATTR_TEMP_SCALE("0.555556"); -static IIO_CONST_ATTR_TEMP_OFFSET("-214.6"); - /** * sca3000_read_thresh() - query of a threshold **/ @@ -782,33 +779,16 @@ static struct attribute *sca3000_attributes[] = { NULL, }; -static struct attribute *sca3000_attributes_with_temp[] = { - &iio_dev_attr_revision.dev_attr.attr, - &iio_dev_attr_measurement_mode_available.dev_attr.attr, - &iio_dev_attr_measurement_mode.dev_attr.attr, - &iio_dev_attr_sampling_frequency_available.dev_attr.attr, - &iio_dev_attr_sampling_frequency.dev_attr.attr, - /* Only present if temp sensor is */ - &iio_dev_attr_in_temp_raw.dev_attr.attr, - &iio_const_attr_in_temp_offset.dev_attr.attr, - &iio_const_attr_in_temp_scale.dev_attr.attr, - NULL, -}; - static const struct attribute_group sca3000_attribute_group = { .attrs = sca3000_attributes, }; -static const struct attribute_group sca3000_attribute_group_with_temp = { - .attrs = sca3000_attributes_with_temp, -}; - -/* RING RELATED interrupt handler */ -/* depending on event, push to the ring buffer event chrdev or the event one */ - /** * sca3000_event_handler() - handling ring and non ring events * + * Ring related interrupt handler. Depending on event, push to + * the ring buffer event chrdev or the event one. + * * This function is complicated by the fact that the devices can signify ring * and non ring events via the same interrupt line and they can only * be distinguished via a read of the relevant status register. @@ -820,7 +800,8 @@ static irqreturn_t sca3000_event_handler(int irq, void *private) int ret, val; s64 last_timestamp = iio_get_time_ns(); - /* Could lead if badly timed to an extra read of status reg, + /* + * Could lead if badly timed to an extra read of status reg, * but ensures no interrupt is missed. */ mutex_lock(&st->lock); @@ -935,7 +916,6 @@ static ssize_t sca3000_query_free_fall_mode(struct device *dev, * the device falls more than 25cm. This has not been tested due * to fragile wiring. **/ - static ssize_t sca3000_set_free_fall_mode(struct device *dev, struct device_attribute *attr, const char *buf, @@ -957,7 +937,7 @@ static ssize_t sca3000_set_free_fall_mode(struct device *dev, if (ret) goto error_ret; - /*if off and should be on*/ + /* if off and should be on */ if (val && !(st->rx[0] & protect_mask)) ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, (st->rx[0] | SCA3000_FREE_FALL_DETECT)); @@ -972,7 +952,7 @@ error_ret: } /** - * sca3000_set_mo_det() simple on off control for motion detector + * sca3000_write_event_config() simple on off control for motion detector * * This is a per axis control, but enabling any will result in the * motion detector unit being enabled. @@ -992,13 +972,15 @@ static int sca3000_write_event_config(struct iio_dev *indio_dev, int num = chan->channel2; mutex_lock(&st->lock); - /* First read the motion detector config to find out if - * this axis is on*/ + /* + * First read the motion detector config to find out if + * this axis is on + */ ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); if (ret < 0) goto exit_point; ctrlval = ret; - /* Off and should be on */ + /* if off and should be on */ if (state && !(ctrlval & sca3000_addresses[num][2])) { ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL, @@ -1021,7 +1003,7 @@ static int sca3000_write_event_config(struct iio_dev *indio_dev, ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); if (ret) goto exit_point; - /*if off and should be on*/ + /* if off and should be on */ if ((st->mo_det_use_count) && ((st->rx[0] & protect_mask) != SCA3000_MEAS_MODE_MOT_DET)) ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, @@ -1067,7 +1049,7 @@ static struct attribute_group sca3000_event_attribute_group = { * Devices use flash memory to store many of the register values * and hence can come up in somewhat unpredictable states. * Hence reset everything on driver load. - **/ + **/ static int sca3000_clean_setup(struct sca3000_state *st) { int ret; @@ -1107,9 +1089,11 @@ static int sca3000_clean_setup(struct sca3000_state *st) | SCA3000_INT_MASK_ACTIVE_LOW); if (ret) goto error_ret; - /* Select normal measurement mode, free fall off, ring off */ - /* Ring in 12 bit mode - it is fine to overwrite reserved bits 3,5 - * as that occurs in one of the example on the datasheet */ + /* + * Select normal measurement mode, free fall off, ring off + * Ring in 12 bit mode - it is fine to overwrite reserved bits 3,5 + * as that occurs in one of the example on the datasheet + */ ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); if (ret) goto error_ret; @@ -1133,16 +1117,6 @@ static const struct iio_info sca3000_info = { .driver_module = THIS_MODULE, }; -static const struct iio_info sca3000_info_with_temp = { - .attrs = &sca3000_attribute_group_with_temp, - .read_raw = &sca3000_read_raw, - .read_event_value = &sca3000_read_thresh, - .write_event_value = &sca3000_write_thresh, - .read_event_config = &sca3000_read_event_config, - .write_event_config = &sca3000_write_event_config, - .driver_module = THIS_MODULE, -}; - static int sca3000_probe(struct spi_device *spi) { int ret; @@ -1162,10 +1136,12 @@ static int sca3000_probe(struct spi_device *spi) indio_dev->dev.parent = &spi->dev; indio_dev->name = spi_get_device_id(spi)->name; - if (st->info->temp_output) - indio_dev->info = &sca3000_info_with_temp; - else { - indio_dev->info = &sca3000_info; + indio_dev->info = &sca3000_info; + if (st->info->temp_output) { + indio_dev->channels = sca3000_channels_with_temp; + indio_dev->num_channels = + ARRAY_SIZE(sca3000_channels_with_temp); + } else { indio_dev->channels = sca3000_channels; indio_dev->num_channels = ARRAY_SIZE(sca3000_channels); } @@ -1236,7 +1212,7 @@ static int sca3000_remove(struct spi_device *spi) struct iio_dev *indio_dev = spi_get_drvdata(spi); struct sca3000_state *st = iio_priv(indio_dev); - /* Must ensure no interrupts can be generated after this!*/ + /* Must ensure no interrupts can be generated after this! */ sca3000_stop_all_interrupts(st); if (spi->irq) free_irq(spi->irq, indio_dev); diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c index ea0af6d81d2b..198710651e0e 100644 --- a/drivers/staging/iio/accel/sca3000_ring.c +++ b/drivers/staging/iio/accel/sca3000_ring.c @@ -309,7 +309,7 @@ int __sca3000_hw_ring_state_set(struct iio_dev *indio_dev, bool state) if (ret) goto error_ret; if (state) { - printk(KERN_INFO "supposedly enabling ring buffer\n"); + dev_info(&indio_dev->dev, "supposedly enabling ring buffer\n"); ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, (st->rx[0] | SCA3000_RING_BUF_ENABLE)); diff --git a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h index a591aa6feae1..fc8c85298feb 100644 --- a/drivers/staging/iio/adc/ad799x.h +++ b/drivers/staging/iio/adc/ad799x.h @@ -95,7 +95,7 @@ struct ad799x_state { struct i2c_client *client; const struct ad799x_chip_info *chip_info; struct regulator *reg; - u16 int_vref_mv; + struct regulator *vref; unsigned id; u16 config; @@ -103,14 +103,6 @@ struct ad799x_state { unsigned int transfer_size; }; -/* - * TODO: struct ad799x_platform_data needs to go into include/linux/iio - */ - -struct ad799x_platform_data { - u16 vref_mv; -}; - #ifdef CONFIG_AD799X_RING_BUFFER int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev); void ad799x_ring_cleanup(struct iio_dev *indio_dev); diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c index 5708ffc62aec..979ec77d6c2d 100644 --- a/drivers/staging/iio/adc/ad799x_core.c +++ b/drivers/staging/iio/adc/ad799x_core.c @@ -1,6 +1,6 @@ /* * iio/adc/ad799x.c - * Copyright (C) 2010-1011 Michael Hennerich, Analog Devices Inc. + * Copyright (C) 2010-2011 Michael Hennerich, Analog Devices Inc. * * based on iio/adc/max1363 * Copyright (C) 2008-2010 Jonathan Cameron @@ -179,7 +179,10 @@ static int ad799x_read_raw(struct iio_dev *indio_dev, RES_MASK(chan->scan_type.realbits); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = st->int_vref_mv; + ret = regulator_get_voltage(st->vref); + if (ret < 0) + return ret; + *val = ret / 1000; *val2 = chan->scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2; } @@ -533,7 +536,6 @@ static int ad799x_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret; - struct ad799x_platform_data *pdata = client->dev.platform_data; struct ad799x_state *st; struct iio_dev *indio_dev; @@ -551,17 +553,21 @@ static int ad799x_probe(struct i2c_client *client, /* TODO: Add pdata options for filtering and bit delay */ - if (!pdata) - return -EINVAL; - - st->int_vref_mv = pdata->vref_mv; - st->reg = devm_regulator_get(&client->dev, "vcc"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) - return ret; + if (IS_ERR(st->reg)) + return PTR_ERR(st->reg); + ret = regulator_enable(st->reg); + if (ret) + return ret; + st->vref = devm_regulator_get(&client->dev, "vref"); + if (IS_ERR(st->vref)) { + ret = PTR_ERR(st->vref); + goto error_disable_reg; } + ret = regulator_enable(st->vref); + if (ret) + goto error_disable_reg; + st->client = client; indio_dev->dev.parent = &client->dev; @@ -577,28 +583,28 @@ static int ad799x_probe(struct i2c_client *client, goto error_disable_reg; if (client->irq > 0) { - ret = request_threaded_irq(client->irq, - NULL, - ad799x_event_handler, - IRQF_TRIGGER_FALLING | - IRQF_ONESHOT, - client->name, - indio_dev); + ret = devm_request_threaded_irq(&client->dev, + client->irq, + NULL, + ad799x_event_handler, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + client->name, + indio_dev); if (ret) goto error_cleanup_ring; } ret = iio_device_register(indio_dev); if (ret) - goto error_free_irq; + goto error_cleanup_ring; return 0; -error_free_irq: - if (client->irq > 0) - free_irq(client->irq, indio_dev); error_cleanup_ring: ad799x_ring_cleanup(indio_dev); error_disable_reg: + if (!IS_ERR(st->vref)) + regulator_disable(st->vref); if (!IS_ERR(st->reg)) regulator_disable(st->reg); @@ -611,10 +617,10 @@ static int ad799x_remove(struct i2c_client *client) struct ad799x_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (client->irq > 0) - free_irq(client->irq, indio_dev); ad799x_ring_cleanup(indio_dev); + if (!IS_ERR(st->vref)) + regulator_disable(st->vref); if (!IS_ERR(st->reg)) regulator_disable(st->reg); kfree(st->rx_buf); diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 514844efac75..11fb95201545 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -847,7 +847,8 @@ static int mxs_lradc_read_single(struct iio_dev *iio_dev, int chan, int *val) mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0); /* Clean the slot's previous content, then set new one. */ - mxs_lradc_reg_clear(lradc, LRADC_CTRL4_LRADCSELECT_MASK(0), LRADC_CTRL4); + mxs_lradc_reg_clear(lradc, LRADC_CTRL4_LRADCSELECT_MASK(0), + LRADC_CTRL4); mxs_lradc_reg_set(lradc, chan, LRADC_CTRL4); mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(0)); @@ -898,10 +899,6 @@ static int mxs_lradc_read_raw(struct iio_dev *iio_dev, { struct mxs_lradc *lradc = iio_priv(iio_dev); - /* Check for invalid channel */ - if (chan->channel > LRADC_MAX_TOTAL_CHANS) - return -EINVAL; - switch (m) { case IIO_CHAN_INFO_RAW: if (chan->type == IIO_TEMP) @@ -1173,7 +1170,8 @@ static irqreturn_t mxs_lradc_handle_irq(int irq, void *data) else if (reg & LRADC_CTRL1_LRADC_IRQ(0)) complete(&lradc->completion); - mxs_lradc_reg_clear(lradc, reg & mxs_lradc_irq_mask(lradc), LRADC_CTRL1); + mxs_lradc_reg_clear(lradc, reg & mxs_lradc_irq_mask(lradc), + LRADC_CTRL1); return IRQ_HANDLED; } @@ -1264,7 +1262,8 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio) uint32_t ctrl1_irq = 0; const uint32_t chan_value = LRADC_CH_ACCUMULATE | ((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET); - const int len = bitmap_weight(iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS); + const int len = bitmap_weight(iio->active_scan_mask, + LRADC_MAX_TOTAL_CHANS); if (!len) return -EINVAL; @@ -1563,7 +1562,7 @@ static int mxs_lradc_probe(struct platform_device *pdev) for (i = 0; i < of_cfg->irq_count; i++) { lradc->irq[i] = platform_get_irq(pdev, i); if (lradc->irq[i] < 0) - return -EINVAL; + return lradc->irq[i]; ret = devm_request_irq(dev, lradc->irq[i], mxs_lradc_handle_irq, 0, diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 16a8201228ff..9f0ebb329008 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -859,11 +859,14 @@ static ssize_t adt7316_show_DAC_update_mode(struct device *dev, else { switch (chip->dac_config & ADT7316_DA_EN_MODE_MASK) { case ADT7316_DA_EN_MODE_SINGLE: - return sprintf(buf, "0 - auto at any MSB DAC writing\n"); + return sprintf(buf, + "0 - auto at any MSB DAC writing\n"); case ADT7316_DA_EN_MODE_AB_CD: - return sprintf(buf, "1 - auto at MSB DAC AB and CD writing\n"); + return sprintf(buf, + "1 - auto at MSB DAC AB and CD writing\n"); case ADT7316_DA_EN_MODE_ABCD: - return sprintf(buf, "2 - auto at MSB DAC ABCD writing\n"); + return sprintf(buf, + "2 - auto at MSB DAC ABCD writing\n"); default: /* ADT7316_DA_EN_MODE_LDAC */ return sprintf(buf, "3 - manual\n"); } @@ -1102,7 +1105,8 @@ static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev, ldac_config = chip->ldac_config | ADT7316_DAC_IN_VREF; } - ret = chip->bus.write(chip->bus.client, ADT7316_LDAC_CONFIG, ldac_config); + ret = chip->bus.write(chip->bus.client, ADT7316_LDAC_CONFIG, + ldac_config); if (ret) return -EIO; @@ -1224,7 +1228,8 @@ static ssize_t adt7316_show_ex_temp_AIN1(struct device *dev, return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_EX, buf); } -static IIO_DEVICE_ATTR(ex_temp_AIN1, S_IRUGO, adt7316_show_ex_temp_AIN1, NULL, 0); +static IIO_DEVICE_ATTR(ex_temp_AIN1, S_IRUGO, adt7316_show_ex_temp_AIN1, + NULL, 0); static IIO_DEVICE_ATTR(ex_temp, S_IRUGO, adt7316_show_ex_temp_AIN1, NULL, 0); static ssize_t adt7316_show_AIN2(struct device *dev, @@ -1319,7 +1324,8 @@ static ssize_t adt7316_store_in_temp_offset(struct device *dev, struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); - return adt7316_store_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf, len); + return adt7316_store_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf, + len); } static IIO_DEVICE_ATTR(in_temp_offset, S_IRUGO | S_IWUSR, @@ -1344,7 +1350,8 @@ static ssize_t adt7316_store_ex_temp_offset(struct device *dev, struct iio_dev *dev_info = dev_to_iio_dev(dev); struct adt7316_chip_info *chip = iio_priv(dev_info); - return adt7316_store_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf, len); + return adt7316_store_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf, + len); } static IIO_DEVICE_ATTR(ex_temp_offset, S_IRUGO | S_IWUSR, diff --git a/drivers/staging/iio/addac/adt7316.h b/drivers/staging/iio/addac/adt7316.h index 2dbfb499528d..ec50bf34628d 100644 --- a/drivers/staging/iio/addac/adt7316.h +++ b/drivers/staging/iio/addac/adt7316.h @@ -18,10 +18,10 @@ struct adt7316_bus { void *client; int irq; int irq_flags; - int (*read) (void *client, u8 reg, u8 *data); - int (*write) (void *client, u8 reg, u8 val); - int (*multi_read) (void *client, u8 first_reg, u8 count, u8 *data); - int (*multi_write) (void *client, u8 first_reg, u8 count, u8 *data); + int (*read)(void *client, u8 reg, u8 *data); + int (*write)(void *client, u8 reg, u8 val); + int (*multi_read)(void *client, u8 first_reg, u8 count, u8 *data); + int (*multi_write)(void *client, u8 first_reg, u8 count, u8 *data); }; #ifdef CONFIG_PM_SLEEP diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c index f8c659568c38..0a60def92735 100644 --- a/drivers/staging/iio/light/tsl2583.c +++ b/drivers/staging/iio/light/tsl2583.c @@ -433,7 +433,7 @@ static int taos_chip_on(struct iio_dev *indio_dev) TSL258X_CMD_REG | TSL258X_CNTRL, utmp); if (ret < 0) { dev_err(&chip->client->dev, "taos_chip_on failed on CNTRL reg.\n"); - return -1; + return ret; } /* Use the following shadow copy for our delay before enabling ADC. @@ -445,7 +445,7 @@ static int taos_chip_on(struct iio_dev *indio_dev) if (ret < 0) { dev_err(&chip->client->dev, "taos_chip_on failed on reg %d.\n", i); - return -1; + return ret; } } @@ -458,7 +458,7 @@ static int taos_chip_on(struct iio_dev *indio_dev) utmp); if (ret < 0) { dev_err(&chip->client->dev, "taos_chip_on failed on 2nd CTRL reg.\n"); - return -1; + return ret; } chip->taos_chip_status = TSL258X_CHIP_WORKING; diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c index 1e538086d48b..9e0f2a9c73ae 100644 --- a/drivers/staging/iio/light/tsl2x7x_core.c +++ b/drivers/staging/iio/light/tsl2x7x_core.c @@ -352,7 +352,7 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev) /* device is not enabled */ dev_err(&chip->client->dev, "%s: device is not enabled\n", __func__); - ret = -EBUSY ; + ret = -EBUSY; goto out_unlock; } @@ -1507,16 +1507,16 @@ static int tsl2x7x_device_id(unsigned char *id, int target) case tsl2571: case tsl2671: case tsl2771: - return ((*id & 0xf0) == TRITON_ID); + return (*id & 0xf0) == TRITON_ID; case tmd2671: case tmd2771: - return ((*id & 0xf0) == HALIBUT_ID); + return (*id & 0xf0) == HALIBUT_ID; case tsl2572: case tsl2672: case tmd2672: case tsl2772: case tmd2772: - return ((*id & 0xf0) == SWORDFISH_ID); + return (*id & 0xf0) == SWORDFISH_ID; } return -EINVAL; diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 6966d5f76648..7fbaba41c872 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -312,7 +312,7 @@ static ssize_t ad2s1210_store_control(struct device *dev, if (st->pdata->gpioin) { data = ad2s1210_read_resolution_pin(st); if (data != st->resolution) - pr_warning("ad2s1210: resolution settings not match\n"); + pr_warn("ad2s1210: resolution settings not match\n"); } else ad2s1210_set_resolution_pin(st); @@ -372,7 +372,7 @@ static ssize_t ad2s1210_store_resolution(struct device *dev, if (st->pdata->gpioin) { data = ad2s1210_read_resolution_pin(st); if (data != st->resolution) - pr_warning("ad2s1210: resolution settings not match\n"); + pr_warn("ad2s1210: resolution settings not match\n"); } else ad2s1210_set_resolution_pin(st); ret = len; diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig index 78319ad176cd..c6e8ba7b3e4e 100644 --- a/drivers/staging/imx-drm/Kconfig +++ b/drivers/staging/imx-drm/Kconfig @@ -20,6 +20,7 @@ config DRM_IMX_FB_HELPER config DRM_IMX_PARALLEL_DISPLAY tristate "Support for parallel displays" + select DRM_PANEL depends on DRM_IMX select VIDEOMODE_HELPERS diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile index 4677585b5ad5..129e3a3f59f1 100644 --- a/drivers/staging/imx-drm/Makefile +++ b/drivers/staging/imx-drm/Makefile @@ -1,12 +1,11 @@ -imxdrm-objs := imx-drm-core.o imx-fb.o +imxdrm-objs := imx-drm-core.o obj-$(CONFIG_DRM_IMX) += imxdrm.o obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o -obj-$(CONFIG_DRM_IMX_FB_HELPER) += imx-fbdev.o obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/ imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o diff --git a/drivers/staging/imx-drm/TODO b/drivers/staging/imx-drm/TODO index 6a9da94c9573..29636fb13959 100644 --- a/drivers/staging/imx-drm/TODO +++ b/drivers/staging/imx-drm/TODO @@ -1,15 +1,10 @@ TODO: - get DRM Maintainer review for this code -- Wait for common display framework to hit mainline and update the IPU - driver to use it. This will most probably make changes to the devicetree - bindings necessary. -- Factor out more code to common helper functions - decide where to put the base driver. It is not specific to a subsystem and would be used by DRM/KMS and media/V4L2 Missing features (not necessarily for moving out of staging): -- Add i.MX6 HDMI support - Add support for IC (Image converter) - Add support for CSI (CMOS Sensor interface) - Add support for VDIC (Video Deinterlacer) diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c index 236ed66f116a..4144a75e5f71 100644 --- a/drivers/staging/imx-drm/imx-drm-core.c +++ b/drivers/staging/imx-drm/imx-drm-core.c @@ -13,14 +13,15 @@ * GNU General Public License for more details. * */ - +#include #include +#include +#include +#include #include #include #include #include -#include -#include #include #include @@ -28,45 +29,29 @@ #define MAX_CRTC 4 -struct crtc_cookie { - void *cookie; - int id; +struct imx_drm_crtc; + +struct imx_drm_component { + struct device_node *of_node; struct list_head list; }; struct imx_drm_device { struct drm_device *drm; - struct device *dev; - struct list_head crtc_list; - struct list_head encoder_list; - struct list_head connector_list; - struct mutex mutex; + struct imx_drm_crtc *crtc[MAX_CRTC]; int pipes; struct drm_fbdev_cma *fbhelper; }; struct imx_drm_crtc { struct drm_crtc *crtc; - struct list_head list; - struct imx_drm_device *imxdrm; int pipe; struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs; - struct module *owner; - struct crtc_cookie cookie; + struct device_node *port; }; -struct imx_drm_encoder { - struct drm_encoder *encoder; - struct list_head list; - struct module *owner; - struct list_head possible_crtcs; -}; - -struct imx_drm_connector { - struct drm_connector *connector; - struct list_head list; - struct module *owner; -}; +static int legacyfb_depth = 16; +module_param(legacyfb_depth, int, 0444); int imx_drm_crtc_id(struct imx_drm_crtc *crtc) { @@ -76,69 +61,71 @@ EXPORT_SYMBOL_GPL(imx_drm_crtc_id); static void imx_drm_driver_lastclose(struct drm_device *drm) { +#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) struct imx_drm_device *imxdrm = drm->dev_private; if (imxdrm->fbhelper) drm_fbdev_cma_restore_mode(imxdrm->fbhelper); +#endif } static int imx_drm_driver_unload(struct drm_device *drm) { +#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) struct imx_drm_device *imxdrm = drm->dev_private; +#endif - imx_drm_device_put(); + drm_kms_helper_poll_fini(drm); + +#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) + if (imxdrm->fbhelper) + drm_fbdev_cma_fini(imxdrm->fbhelper); +#endif + + component_unbind_all(drm->dev, drm); drm_vblank_cleanup(drm); - drm_kms_helper_poll_fini(drm); drm_mode_config_cleanup(drm); return 0; } -/* - * We don't care at all for crtc numbers, but the core expects the - * crtcs to be numbered - */ -static struct imx_drm_crtc *imx_drm_crtc_by_num(struct imx_drm_device *imxdrm, - int num) +static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc) { - struct imx_drm_crtc *imx_drm_crtc; + struct imx_drm_device *imxdrm = crtc->dev->dev_private; + unsigned i; + + for (i = 0; i < MAX_CRTC; i++) + if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc) + return imxdrm->crtc[i]; - list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list) - if (imx_drm_crtc->pipe == num) - return imx_drm_crtc; return NULL; } -int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type, +int imx_drm_panel_format_pins(struct drm_encoder *encoder, u32 interface_pix_fmt, int hsync_pin, int vsync_pin) { - struct imx_drm_device *imxdrm = crtc->dev->dev_private; - struct imx_drm_crtc *imx_crtc; struct imx_drm_crtc_helper_funcs *helper; + struct imx_drm_crtc *imx_crtc; - list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list) - if (imx_crtc->crtc == crtc) - goto found; + imx_crtc = imx_drm_find_crtc(encoder->crtc); + if (!imx_crtc) + return -EINVAL; - return -EINVAL; -found: helper = &imx_crtc->imx_drm_helper_funcs; if (helper->set_interface_pix_fmt) - return helper->set_interface_pix_fmt(crtc, - encoder_type, interface_pix_fmt, + return helper->set_interface_pix_fmt(encoder->crtc, + encoder->encoder_type, interface_pix_fmt, hsync_pin, vsync_pin); return 0; } -EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format_pins); +EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins); -int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type, - u32 interface_pix_fmt) +int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt) { - return imx_drm_crtc_panel_format_pins(crtc, encoder_type, - interface_pix_fmt, 2, 3); + return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3); } -EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format); +EXPORT_SYMBOL_GPL(imx_drm_panel_format); int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc) { @@ -161,10 +148,9 @@ EXPORT_SYMBOL_GPL(imx_drm_handle_vblank); static int imx_drm_enable_vblank(struct drm_device *drm, int crtc) { struct imx_drm_device *imxdrm = drm->dev_private; - struct imx_drm_crtc *imx_drm_crtc; + struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc]; int ret; - imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc); if (!imx_drm_crtc) return -EINVAL; @@ -180,9 +166,8 @@ static int imx_drm_enable_vblank(struct drm_device *drm, int crtc) static void imx_drm_disable_vblank(struct drm_device *drm, int crtc) { struct imx_drm_device *imxdrm = drm->dev_private; - struct imx_drm_crtc *imx_drm_crtc; + struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc]; - imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc); if (!imx_drm_crtc) return; @@ -215,172 +200,54 @@ static const struct file_operations imx_drm_driver_fops = { .llseek = noop_llseek, }; -static struct imx_drm_device *imx_drm_device; - -static struct imx_drm_device *__imx_drm_device(void) +int imx_drm_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { - return imx_drm_device; + return MODE_OK; +} +EXPORT_SYMBOL(imx_drm_connector_mode_valid); + +void imx_drm_connector_destroy(struct drm_connector *connector) +{ + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); +} +EXPORT_SYMBOL_GPL(imx_drm_connector_destroy); + +void imx_drm_encoder_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); +} +EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy); + +static void imx_drm_output_poll_changed(struct drm_device *drm) +{ +#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) + struct imx_drm_device *imxdrm = drm->dev_private; + + drm_fbdev_cma_hotplug_event(imxdrm->fbhelper); +#endif } -struct drm_device *imx_drm_device_get(void) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - struct imx_drm_encoder *enc; - struct imx_drm_connector *con; - struct imx_drm_crtc *crtc; - - list_for_each_entry(enc, &imxdrm->encoder_list, list) { - if (!try_module_get(enc->owner)) { - dev_err(imxdrm->dev, "could not get module %s\n", - module_name(enc->owner)); - goto unwind_enc; - } - } - - list_for_each_entry(con, &imxdrm->connector_list, list) { - if (!try_module_get(con->owner)) { - dev_err(imxdrm->dev, "could not get module %s\n", - module_name(con->owner)); - goto unwind_con; - } - } - - list_for_each_entry(crtc, &imxdrm->crtc_list, list) { - if (!try_module_get(crtc->owner)) { - dev_err(imxdrm->dev, "could not get module %s\n", - module_name(crtc->owner)); - goto unwind_crtc; - } - } - - return imxdrm->drm; - -unwind_crtc: - list_for_each_entry_continue_reverse(crtc, &imxdrm->crtc_list, list) - module_put(crtc->owner); -unwind_con: - list_for_each_entry_continue_reverse(con, &imxdrm->connector_list, list) - module_put(con->owner); -unwind_enc: - list_for_each_entry_continue_reverse(enc, &imxdrm->encoder_list, list) - module_put(enc->owner); - - mutex_unlock(&imxdrm->mutex); - - return NULL; - -} -EXPORT_SYMBOL_GPL(imx_drm_device_get); - -void imx_drm_device_put(void) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - struct imx_drm_encoder *enc; - struct imx_drm_connector *con; - struct imx_drm_crtc *crtc; - - mutex_lock(&imxdrm->mutex); - - list_for_each_entry(crtc, &imxdrm->crtc_list, list) - module_put(crtc->owner); - - list_for_each_entry(con, &imxdrm->connector_list, list) - module_put(con->owner); - - list_for_each_entry(enc, &imxdrm->encoder_list, list) - module_put(enc->owner); - - mutex_unlock(&imxdrm->mutex); -} -EXPORT_SYMBOL_GPL(imx_drm_device_put); - -static int drm_mode_group_reinit(struct drm_device *dev) -{ - struct drm_mode_group *group = &dev->primary->mode_group; - uint32_t *id_list = group->id_list; - int ret; - - ret = drm_mode_group_init_legacy_group(dev, group); - if (ret < 0) - return ret; - - kfree(id_list); - return 0; -} +static struct drm_mode_config_funcs imx_drm_mode_config_funcs = { + .fb_create = drm_fb_cma_create, + .output_poll_changed = imx_drm_output_poll_changed, +}; /* - * register an encoder to the drm core - */ -static int imx_drm_encoder_register(struct imx_drm_encoder *imx_drm_encoder) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - - INIT_LIST_HEAD(&imx_drm_encoder->possible_crtcs); - - drm_encoder_init(imxdrm->drm, imx_drm_encoder->encoder, - imx_drm_encoder->encoder->funcs, - imx_drm_encoder->encoder->encoder_type); - - drm_mode_group_reinit(imxdrm->drm); - - return 0; -} - -/* - * unregister an encoder from the drm core - */ -static void imx_drm_encoder_unregister(struct imx_drm_encoder - *imx_drm_encoder) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - - drm_encoder_cleanup(imx_drm_encoder->encoder); - - drm_mode_group_reinit(imxdrm->drm); -} - -/* - * register a connector to the drm core - */ -static int imx_drm_connector_register( - struct imx_drm_connector *imx_drm_connector) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - - drm_connector_init(imxdrm->drm, imx_drm_connector->connector, - imx_drm_connector->connector->funcs, - imx_drm_connector->connector->connector_type); - drm_mode_group_reinit(imxdrm->drm); - - return drm_sysfs_connector_add(imx_drm_connector->connector); -} - -/* - * unregister a connector from the drm core - */ -static void imx_drm_connector_unregister( - struct imx_drm_connector *imx_drm_connector) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - - drm_sysfs_connector_remove(imx_drm_connector->connector); - drm_connector_cleanup(imx_drm_connector->connector); - - drm_mode_group_reinit(imxdrm->drm); -} - -/* - * Called by the CRTC driver when all CRTCs are registered. This - * puts all the pieces together and initializes the driver. - * Once this is called no more CRTCs can be registered since - * the drm core has hardcoded the number of crtcs in several - * places. + * Main DRM initialisation. This binds, initialises and registers + * with DRM the subcomponents of the driver. */ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) { - struct imx_drm_device *imxdrm = __imx_drm_device(); + struct imx_drm_device *imxdrm; + struct drm_connector *connector; int ret; + imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL); + if (!imxdrm) + return -ENOMEM; + imxdrm->drm = drm; drm->dev_private = imxdrm; @@ -396,120 +263,118 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) */ drm->irq_enabled = true; + /* + * set max width and height as default value(4096x4096). + * this value would be used to check framebuffer size limitation + * at drm_mode_addfb(). + */ + drm->mode_config.min_width = 64; + drm->mode_config.min_height = 64; + drm->mode_config.max_width = 4096; + drm->mode_config.max_height = 4096; + drm->mode_config.funcs = &imx_drm_mode_config_funcs; + drm_mode_config_init(drm); - imx_drm_mode_config_init(drm); - - mutex_lock(&imxdrm->mutex); - - drm_kms_helper_poll_init(drm); - - /* setup the grouping for the legacy output */ - ret = drm_mode_group_init_legacy_group(drm, - &drm->primary->mode_group); - if (ret) - goto err_kms; ret = drm_vblank_init(drm, MAX_CRTC); if (ret) goto err_kms; /* - * with vblank_disable_allowed = true, vblank interrupt will be disabled - * by drm timer once a current process gives up ownership of - * vblank event.(after drm_vblank_put function is called) + * with vblank_disable_allowed = true, vblank interrupt will be + * disabled by drm timer once a current process gives up ownership + * of vblank event. (after drm_vblank_put function is called) */ drm->vblank_disable_allowed = true; - if (!imx_drm_device_get()) { - ret = -EINVAL; + platform_set_drvdata(drm->platformdev, drm); + + /* Now try and bind all our sub-components */ + ret = component_bind_all(drm->dev, drm); + if (ret) goto err_vblank; + + /* + * All components are now added, we can publish the connector sysfs + * entries to userspace. This will generate hotplug events and so + * userspace will expect to be able to access DRM at this point. + */ + list_for_each_entry(connector, &drm->mode_config.connector_list, head) { + ret = drm_sysfs_connector_add(connector); + if (ret) { + dev_err(drm->dev, + "[CONNECTOR:%d:%s] drm_sysfs_connector_add failed: %d\n", + connector->base.id, + drm_get_connector_name(connector), ret); + goto err_unbind; + } } - platform_set_drvdata(drm->platformdev, drm); - mutex_unlock(&imxdrm->mutex); + /* + * All components are now initialised, so setup the fb helper. + * The fb helper takes copies of key hardware information, so the + * crtcs/connectors/encoders must not change after this point. + */ +#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) + if (legacyfb_depth != 16 && legacyfb_depth != 32) { + dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n"); + legacyfb_depth = 16; + } + imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth, + drm->mode_config.num_crtc, MAX_CRTC); + if (IS_ERR(imxdrm->fbhelper)) { + ret = PTR_ERR(imxdrm->fbhelper); + imxdrm->fbhelper = NULL; + goto err_unbind; + } +#endif + + drm_kms_helper_poll_init(drm); + return 0; +err_unbind: + component_unbind_all(drm->dev, drm); err_vblank: drm_vblank_cleanup(drm); err_kms: - drm_kms_helper_poll_fini(drm); drm_mode_config_cleanup(drm); - mutex_unlock(&imxdrm->mutex); return ret; } -static void imx_drm_update_possible_crtcs(void) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - struct imx_drm_crtc *imx_drm_crtc; - struct imx_drm_encoder *enc; - struct crtc_cookie *cookie; - - list_for_each_entry(enc, &imxdrm->encoder_list, list) { - u32 possible_crtcs = 0; - - list_for_each_entry(cookie, &enc->possible_crtcs, list) { - list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list) { - if (imx_drm_crtc->cookie.cookie == cookie->cookie && - imx_drm_crtc->cookie.id == cookie->id) { - possible_crtcs |= 1 << imx_drm_crtc->pipe; - } - } - } - enc->encoder->possible_crtcs = possible_crtcs; - enc->encoder->possible_clones = possible_crtcs; - } -} - /* * imx_drm_add_crtc - add a new crtc - * - * The return value if !NULL is a cookie for the caller to pass to - * imx_drm_remove_crtc later. */ -int imx_drm_add_crtc(struct drm_crtc *crtc, +int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, struct imx_drm_crtc **new_crtc, const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs, - struct module *owner, void *cookie, int id) + struct device_node *port) { - struct imx_drm_device *imxdrm = __imx_drm_device(); + struct imx_drm_device *imxdrm = drm->dev_private; struct imx_drm_crtc *imx_drm_crtc; int ret; - mutex_lock(&imxdrm->mutex); - /* * The vblank arrays are dimensioned by MAX_CRTC - we can't * pass IDs greater than this to those functions. */ - if (imxdrm->pipes >= MAX_CRTC) { - ret = -EINVAL; - goto err_busy; - } + if (imxdrm->pipes >= MAX_CRTC) + return -EINVAL; - if (imxdrm->drm->open_count) { - ret = -EBUSY; - goto err_busy; - } + if (imxdrm->drm->open_count) + return -EBUSY; imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL); - if (!imx_drm_crtc) { - ret = -ENOMEM; - goto err_alloc; - } + if (!imx_drm_crtc) + return -ENOMEM; imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs; imx_drm_crtc->pipe = imxdrm->pipes++; - imx_drm_crtc->cookie.cookie = cookie; - imx_drm_crtc->cookie.id = id; - + imx_drm_crtc->port = port; imx_drm_crtc->crtc = crtc; - imx_drm_crtc->imxdrm = imxdrm; - imx_drm_crtc->owner = owner; - - list_add_tail(&imx_drm_crtc->list, &imxdrm->crtc_list); + imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc; *new_crtc = imx_drm_crtc; @@ -520,23 +385,14 @@ int imx_drm_add_crtc(struct drm_crtc *crtc, drm_crtc_helper_add(crtc, imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs); - drm_crtc_init(imxdrm->drm, crtc, + drm_crtc_init(drm, crtc, imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs); - drm_mode_group_reinit(imxdrm->drm); - - imx_drm_update_possible_crtcs(); - - mutex_unlock(&imxdrm->mutex); - return 0; err_register: - list_del(&imx_drm_crtc->list); + imxdrm->crtc[imx_drm_crtc->pipe] = NULL; kfree(imx_drm_crtc); -err_alloc: -err_busy: - mutex_unlock(&imxdrm->mutex); return ret; } EXPORT_SYMBOL_GPL(imx_drm_add_crtc); @@ -546,17 +402,11 @@ EXPORT_SYMBOL_GPL(imx_drm_add_crtc); */ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc) { - struct imx_drm_device *imxdrm = imx_drm_crtc->imxdrm; - - mutex_lock(&imxdrm->mutex); + struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private; drm_crtc_cleanup(imx_drm_crtc->crtc); - list_del(&imx_drm_crtc->list); - - drm_mode_group_reinit(imxdrm->drm); - - mutex_unlock(&imxdrm->mutex); + imxdrm->crtc[imx_drm_crtc->pipe] = NULL; kfree(imx_drm_crtc); @@ -565,220 +415,115 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc) EXPORT_SYMBOL_GPL(imx_drm_remove_crtc); /* - * imx_drm_add_encoder - add a new encoder + * Find the DRM CRTC possible mask for the connected endpoint. + * + * The encoder possible masks are defined by their position in the + * mode_config crtc_list. This means that CRTCs must not be added + * or removed once the DRM device has been fully initialised. */ -int imx_drm_add_encoder(struct drm_encoder *encoder, - struct imx_drm_encoder **newenc, struct module *owner) +static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm, + struct device_node *endpoint) { - struct imx_drm_device *imxdrm = __imx_drm_device(); - struct imx_drm_encoder *imx_drm_encoder; - int ret; + struct device_node *port; + unsigned i; - mutex_lock(&imxdrm->mutex); + port = of_graph_get_remote_port(endpoint); + if (!port) + return 0; + of_node_put(port); - if (imxdrm->drm->open_count) { - ret = -EBUSY; - goto err_busy; + for (i = 0; i < MAX_CRTC; i++) { + struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i]; + if (imx_drm_crtc && imx_drm_crtc->port == port) + return drm_crtc_mask(imx_drm_crtc->crtc); } - imx_drm_encoder = kzalloc(sizeof(*imx_drm_encoder), GFP_KERNEL); - if (!imx_drm_encoder) { - ret = -ENOMEM; - goto err_alloc; - } - - imx_drm_encoder->encoder = encoder; - imx_drm_encoder->owner = owner; - - ret = imx_drm_encoder_register(imx_drm_encoder); - if (ret) { - ret = -ENOMEM; - goto err_register; - } - - list_add_tail(&imx_drm_encoder->list, &imxdrm->encoder_list); - - *newenc = imx_drm_encoder; - - mutex_unlock(&imxdrm->mutex); - return 0; - -err_register: - kfree(imx_drm_encoder); -err_alloc: -err_busy: - mutex_unlock(&imxdrm->mutex); - - return ret; } -EXPORT_SYMBOL_GPL(imx_drm_add_encoder); -int imx_drm_encoder_add_possible_crtcs( - struct imx_drm_encoder *imx_drm_encoder, - struct device_node *np) +static struct device_node *imx_drm_of_get_next_endpoint( + const struct device_node *parent, struct device_node *prev) { - struct imx_drm_device *imxdrm = __imx_drm_device(); - struct of_phandle_args args; - struct crtc_cookie *c; - int ret = 0; + struct device_node *node = of_graph_get_next_endpoint(parent, prev); + of_node_put(prev); + return node; +} + +int imx_drm_encoder_parse_of(struct drm_device *drm, + struct drm_encoder *encoder, struct device_node *np) +{ + struct imx_drm_device *imxdrm = drm->dev_private; + struct device_node *ep = NULL; + uint32_t crtc_mask = 0; int i; - if (!list_empty(&imx_drm_encoder->possible_crtcs)) - return -EBUSY; + for (i = 0; ; i++) { + u32 mask; - for (i = 0; !ret; i++) { - ret = of_parse_phandle_with_args(np, "crtcs", - "#crtc-cells", i, &args); - if (ret < 0) + ep = imx_drm_of_get_next_endpoint(np, ep); + if (!ep) break; - c = kzalloc(sizeof(*c), GFP_KERNEL); - if (!c) { - of_node_put(args.np); - return -ENOMEM; - } + mask = imx_drm_find_crtc_mask(imxdrm, ep); - c->cookie = args.np; - c->id = args.args_count > 0 ? args.args[0] : 0; + /* + * If we failed to find the CRTC(s) which this encoder is + * supposed to be connected to, it's because the CRTC has + * not been registered yet. Defer probing, and hope that + * the required CRTC is added later. + */ + if (mask == 0) + return -EPROBE_DEFER; - of_node_put(args.np); - - mutex_lock(&imxdrm->mutex); - - list_add_tail(&c->list, &imx_drm_encoder->possible_crtcs); - - mutex_unlock(&imxdrm->mutex); + crtc_mask |= mask; } - imx_drm_update_possible_crtcs(); + if (ep) + of_node_put(ep); + if (i == 0) + return -ENOENT; + + encoder->possible_crtcs = crtc_mask; + + /* FIXME: this is the mask of outputs which can clone this output. */ + encoder->possible_clones = ~0; return 0; } -EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs); - -int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder, - struct drm_crtc *crtc) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - struct imx_drm_crtc *imx_crtc; - int i = 0; - - list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list) { - if (imx_crtc->crtc == crtc) - goto found; - i++; - } - - return -EINVAL; -found: - return i; -} -EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id); +EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of); /* - * imx_drm_remove_encoder - remove an encoder + * @node: device tree node containing encoder input ports + * @encoder: drm_encoder */ -int imx_drm_remove_encoder(struct imx_drm_encoder *imx_drm_encoder) +int imx_drm_encoder_get_mux_id(struct device_node *node, + struct drm_encoder *encoder) { - struct imx_drm_device *imxdrm = __imx_drm_device(); - struct crtc_cookie *c, *tmp; - - mutex_lock(&imxdrm->mutex); - - imx_drm_encoder_unregister(imx_drm_encoder); - - list_del(&imx_drm_encoder->list); - - list_for_each_entry_safe(c, tmp, &imx_drm_encoder->possible_crtcs, - list) - kfree(c); - - mutex_unlock(&imxdrm->mutex); - - kfree(imx_drm_encoder); - - return 0; -} -EXPORT_SYMBOL_GPL(imx_drm_remove_encoder); - -/* - * imx_drm_add_connector - add a connector - */ -int imx_drm_add_connector(struct drm_connector *connector, - struct imx_drm_connector **new_con, - struct module *owner) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - struct imx_drm_connector *imx_drm_connector; + struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc); + struct device_node *ep = NULL; + struct of_endpoint endpoint; + struct device_node *port; int ret; - mutex_lock(&imxdrm->mutex); + if (!node || !imx_crtc) + return -EINVAL; - if (imxdrm->drm->open_count) { - ret = -EBUSY; - goto err_busy; - } + do { + ep = imx_drm_of_get_next_endpoint(node, ep); + if (!ep) + break; - imx_drm_connector = kzalloc(sizeof(*imx_drm_connector), GFP_KERNEL); - if (!imx_drm_connector) { - ret = -ENOMEM; - goto err_alloc; - } + port = of_graph_get_remote_port(ep); + of_node_put(port); + if (port == imx_crtc->port) { + ret = of_graph_parse_endpoint(ep, &endpoint); + return ret ? ret : endpoint.id; + } + } while (ep); - imx_drm_connector->connector = connector; - imx_drm_connector->owner = owner; - - ret = imx_drm_connector_register(imx_drm_connector); - if (ret) - goto err_register; - - list_add_tail(&imx_drm_connector->list, &imxdrm->connector_list); - - *new_con = imx_drm_connector; - - mutex_unlock(&imxdrm->mutex); - - return 0; - -err_register: - kfree(imx_drm_connector); -err_alloc: -err_busy: - mutex_unlock(&imxdrm->mutex); - - return ret; + return -EINVAL; } -EXPORT_SYMBOL_GPL(imx_drm_add_connector); - -void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - - imxdrm->fbhelper = fbdev_helper; -} -EXPORT_SYMBOL_GPL(imx_drm_fb_helper_set); - -/* - * imx_drm_remove_connector - remove a connector - */ -int imx_drm_remove_connector(struct imx_drm_connector *imx_drm_connector) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - - mutex_lock(&imxdrm->mutex); - - imx_drm_connector_unregister(imx_drm_connector); - - list_del(&imx_drm_connector->list); - - mutex_unlock(&imxdrm->mutex); - - kfree(imx_drm_connector); - - return 0; -} -EXPORT_SYMBOL_GPL(imx_drm_remove_connector); +EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id); static const struct drm_ioctl_desc imx_drm_ioctls[] = { /* none so far */ @@ -819,80 +564,156 @@ static struct drm_driver imx_drm_driver = { .patchlevel = 0, }; +static int compare_of(struct device *dev, void *data) +{ + struct device_node *np = data; + + /* Special case for LDB, one device for two channels */ + if (of_node_cmp(np->name, "lvds-channel") == 0) { + np = of_get_parent(np); + of_node_put(np); + } + + return dev->of_node == np; +} + +static LIST_HEAD(imx_drm_components); + +static int imx_drm_add_components(struct device *master, struct master *m) +{ + struct imx_drm_component *component; + int ret; + + list_for_each_entry(component, &imx_drm_components, list) { + ret = component_master_add_child(m, compare_of, + component->of_node); + if (ret) + return ret; + } + return 0; +} + +static int imx_drm_bind(struct device *dev) +{ + return drm_platform_init(&imx_drm_driver, to_platform_device(dev)); +} + +static void imx_drm_unbind(struct device *dev) +{ + drm_put_dev(dev_get_drvdata(dev)); +} + +static const struct component_master_ops imx_drm_ops = { + .add_components = imx_drm_add_components, + .bind = imx_drm_bind, + .unbind = imx_drm_unbind, +}; + +static struct imx_drm_component *imx_drm_find_component(struct device *dev, + struct device_node *node) +{ + struct imx_drm_component *component; + + list_for_each_entry(component, &imx_drm_components, list) + if (component->of_node == node) + return component; + + return NULL; +} + +static int imx_drm_add_component(struct device *dev, struct device_node *node) +{ + struct imx_drm_component *component; + + if (imx_drm_find_component(dev, node)) + return 0; + + component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL); + if (!component) + return -ENOMEM; + + component->of_node = node; + list_add_tail(&component->list, &imx_drm_components); + + return 0; +} + static int imx_drm_platform_probe(struct platform_device *pdev) { + struct device_node *ep, *port, *remote; int ret; + int i; + + /* + * Bind the IPU display interface ports first, so that + * imx_drm_encoder_parse_of called from encoder .bind callbacks + * works as expected. + */ + for (i = 0; ; i++) { + port = of_parse_phandle(pdev->dev.of_node, "ports", i); + if (!port) + break; + + ret = imx_drm_add_component(&pdev->dev, port); + if (ret < 0) + return ret; + } + + if (i == 0) { + dev_err(&pdev->dev, "missing 'ports' property\n"); + return -ENODEV; + } + + /* Then bind all encoders */ + for (i = 0; ; i++) { + port = of_parse_phandle(pdev->dev.of_node, "ports", i); + if (!port) + break; + + for_each_child_of_node(port, ep) { + remote = of_graph_get_remote_port_parent(ep); + if (!remote || !of_device_is_available(remote)) { + of_node_put(remote); + continue; + } + + ret = imx_drm_add_component(&pdev->dev, remote); + of_node_put(remote); + if (ret < 0) + return ret; + } + of_node_put(port); + } ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) return ret; - imx_drm_device->dev = &pdev->dev; - - return drm_platform_init(&imx_drm_driver, pdev); + return component_master_add(&pdev->dev, &imx_drm_ops); } static int imx_drm_platform_remove(struct platform_device *pdev) { - drm_put_dev(platform_get_drvdata(pdev)); - + component_master_del(&pdev->dev, &imx_drm_ops); return 0; } +static const struct of_device_id imx_drm_dt_ids[] = { + { .compatible = "fsl,imx-display-subsystem", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, imx_drm_dt_ids); + static struct platform_driver imx_drm_pdrv = { .probe = imx_drm_platform_probe, .remove = imx_drm_platform_remove, .driver = { .owner = THIS_MODULE, .name = "imx-drm", + .of_match_table = imx_drm_dt_ids, }, }; - -static struct platform_device *imx_drm_pdev; - -static int __init imx_drm_init(void) -{ - int ret; - - imx_drm_device = kzalloc(sizeof(*imx_drm_device), GFP_KERNEL); - if (!imx_drm_device) - return -ENOMEM; - - mutex_init(&imx_drm_device->mutex); - INIT_LIST_HEAD(&imx_drm_device->crtc_list); - INIT_LIST_HEAD(&imx_drm_device->connector_list); - INIT_LIST_HEAD(&imx_drm_device->encoder_list); - - imx_drm_pdev = platform_device_register_simple("imx-drm", -1, NULL, 0); - if (IS_ERR(imx_drm_pdev)) { - ret = PTR_ERR(imx_drm_pdev); - goto err_pdev; - } - - ret = platform_driver_register(&imx_drm_pdrv); - if (ret) - goto err_pdrv; - - return 0; - -err_pdrv: - platform_device_unregister(imx_drm_pdev); -err_pdev: - kfree(imx_drm_device); - - return ret; -} - -static void __exit imx_drm_exit(void) -{ - platform_device_unregister(imx_drm_pdev); - platform_driver_unregister(&imx_drm_pdrv); - - kfree(imx_drm_device); -} - -module_init(imx_drm_init); -module_exit(imx_drm_exit); +module_platform_driver(imx_drm_pdrv); MODULE_AUTHOR("Sascha Hauer "); MODULE_DESCRIPTION("i.MX drm driver core"); diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h index ae90c9c15312..a322bac55414 100644 --- a/drivers/staging/imx-drm/imx-drm.h +++ b/drivers/staging/imx-drm/imx-drm.h @@ -1,17 +1,15 @@ #ifndef _IMX_DRM_H_ #define _IMX_DRM_H_ -#include - -#define IPU_PIX_FMT_GBR24 v4l2_fourcc('G', 'B', 'R', '3') - +struct device_node; struct drm_crtc; struct drm_connector; struct drm_device; +struct drm_display_mode; struct drm_encoder; -struct imx_drm_crtc; struct drm_fbdev_cma; struct drm_framebuffer; +struct imx_drm_crtc; struct platform_device; int imx_drm_crtc_id(struct imx_drm_crtc *crtc); @@ -25,10 +23,10 @@ struct imx_drm_crtc_helper_funcs { const struct drm_crtc_funcs *crtc_funcs; }; -int imx_drm_add_crtc(struct drm_crtc *crtc, +int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, struct imx_drm_crtc **new_crtc, const struct imx_drm_crtc_helper_funcs *imx_helper_funcs, - struct module *owner, void *cookie, int id); + struct device_node *port); int imx_drm_remove_crtc(struct imx_drm_crtc *); int imx_drm_init_drm(struct platform_device *pdev, int preferred_bpp); @@ -38,35 +36,23 @@ int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc); void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc); void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc); -struct imx_drm_encoder; -int imx_drm_add_encoder(struct drm_encoder *encoder, - struct imx_drm_encoder **new_enc, - struct module *owner); -int imx_drm_remove_encoder(struct imx_drm_encoder *); - -struct imx_drm_connector; -int imx_drm_add_connector(struct drm_connector *connector, - struct imx_drm_connector **new_con, - struct module *owner); -int imx_drm_remove_connector(struct imx_drm_connector *); - void imx_drm_mode_config_init(struct drm_device *drm); struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb); -struct drm_device *imx_drm_device_get(void); -void imx_drm_device_put(void); -int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type, +int imx_drm_panel_format_pins(struct drm_encoder *encoder, u32 interface_pix_fmt, int hsync_pin, int vsync_pin); -int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type, +int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt); -void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper); -struct device_node; +int imx_drm_encoder_get_mux_id(struct device_node *node, + struct drm_encoder *encoder); +int imx_drm_encoder_parse_of(struct drm_device *drm, + struct drm_encoder *encoder, struct device_node *np); -int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder, - struct drm_crtc *crtc); -int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder, - struct device_node *np); +int imx_drm_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode); +void imx_drm_connector_destroy(struct drm_connector *connector); +void imx_drm_encoder_destroy(struct drm_encoder *encoder); #endif /* _IMX_DRM_H_ */ diff --git a/drivers/staging/imx-drm/imx-fb.c b/drivers/staging/imx-drm/imx-fb.c deleted file mode 100644 index 03a7b4e14f67..000000000000 --- a/drivers/staging/imx-drm/imx-fb.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * i.MX drm driver - * - * Copyright (C) 2012 Sascha Hauer, Pengutronix - * - * Based on Samsung Exynos code - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include -#include -#include -#include -#include -#include - -#include "imx-drm.h" - -static struct drm_mode_config_funcs imx_drm_mode_config_funcs = { - .fb_create = drm_fb_cma_create, -}; - -void imx_drm_mode_config_init(struct drm_device *dev) -{ - dev->mode_config.min_width = 64; - dev->mode_config.min_height = 64; - - /* - * set max width and height as default value(4096x4096). - * this value would be used to check framebuffer size limitation - * at drm_mode_addfb(). - */ - dev->mode_config.max_width = 4096; - dev->mode_config.max_height = 4096; - - dev->mode_config.funcs = &imx_drm_mode_config_funcs; -} diff --git a/drivers/staging/imx-drm/imx-fbdev.c b/drivers/staging/imx-drm/imx-fbdev.c deleted file mode 100644 index 8331739c3d08..000000000000 --- a/drivers/staging/imx-drm/imx-fbdev.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * i.MX drm driver - * - * Copyright (C) 2012 Sascha Hauer, Pengutronix - * - * Based on Samsung Exynos code - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include -#include -#include -#include -#include - -#include "imx-drm.h" - -#define MAX_CONNECTOR 4 -#define PREFERRED_BPP 16 - -static struct drm_fbdev_cma *fbdev_cma; - -static int legacyfb_depth = 16; - -module_param(legacyfb_depth, int, 0444); - -static int __init imx_fb_helper_init(void) -{ - struct drm_device *drm = imx_drm_device_get(); - - if (!drm) - return -EINVAL; - - if (legacyfb_depth != 16 && legacyfb_depth != 32) { - pr_warn("i.MX legacyfb: invalid legacyfb_depth setting. defaulting to 16bpp\n"); - legacyfb_depth = 16; - } - - fbdev_cma = drm_fbdev_cma_init(drm, legacyfb_depth, - drm->mode_config.num_crtc, MAX_CONNECTOR); - - if (IS_ERR(fbdev_cma)) { - imx_drm_device_put(); - return PTR_ERR(fbdev_cma); - } - - imx_drm_fb_helper_set(fbdev_cma); - - return 0; -} - -static void __exit imx_fb_helper_exit(void) -{ - imx_drm_fb_helper_set(NULL); - drm_fbdev_cma_fini(fbdev_cma); - imx_drm_device_put(); -} - -late_initcall(imx_fb_helper_init); -module_exit(imx_fb_helper_exit); - -MODULE_DESCRIPTION("Freescale i.MX legacy fb driver"); -MODULE_AUTHOR("Sascha Hauer, Pengutronix"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c index 62ce0e86f14b..d47dedd2cdb4 100644 --- a/drivers/staging/imx-drm/imx-hdmi.c +++ b/drivers/staging/imx-drm/imx-hdmi.c @@ -12,6 +12,7 @@ * Copyright (C) 2010, Guennadi Liakhovetski */ +#include #include #include #include @@ -112,15 +113,15 @@ struct hdmi_data_info { struct imx_hdmi { struct drm_connector connector; - struct imx_drm_connector *imx_drm_connector; struct drm_encoder encoder; - struct imx_drm_encoder *imx_drm_encoder; enum imx_hdmi_devtype dev_type; struct device *dev; struct clk *isfr_clk; struct clk *iahb_clk; + enum drm_connector_status connector_status; + struct hdmi_data_info hdmi_data; int vic; @@ -134,7 +135,6 @@ struct imx_hdmi { struct i2c_adapter *ddc; void __iomem *regs; - unsigned long pixel_clk_rate; unsigned int sample_rate; int ratio; }; @@ -156,37 +156,34 @@ static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset) return readb(hdmi->regs + offset); } +static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg) +{ + u8 val = hdmi_readb(hdmi, reg) & ~mask; + val |= data & mask; + hdmi_writeb(hdmi, val, reg); +} + static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg, u8 shift, u8 mask) { - u8 value = hdmi_readb(hdmi, reg) & ~mask; - value |= (data << shift) & mask; - hdmi_writeb(hdmi, value, reg); + hdmi_modb(hdmi, data << shift, mask, reg); } static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi, unsigned int value) { - u8 val; - hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1); hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2); hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3); /* nshift factor = 0 */ - val = hdmi_readb(hdmi, HDMI_AUD_CTS3); - val &= ~HDMI_AUD_CTS3_N_SHIFT_MASK; - hdmi_writeb(hdmi, val, HDMI_AUD_CTS3); + hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); } static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts) { - u8 val; - /* Must be set/cleared first */ - val = hdmi_readb(hdmi, HDMI_AUD_CTS3); - val &= ~HDMI_AUD_CTS3_CTS_MANUAL; - hdmi_writeb(hdmi, val, HDMI_AUD_CTS3); + hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1); hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2); @@ -331,34 +328,25 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk, return (cts * ratio) / 100; } -static void hdmi_get_pixel_clk(struct imx_hdmi *hdmi) -{ - unsigned long rate; - - rate = 65000000; /* FIXME */ - - if (rate) - hdmi->pixel_clk_rate = rate; -} - -static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi) +static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi, + unsigned long pixel_clk) { unsigned int clk_n, clk_cts; - clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate, + clk_n = hdmi_compute_n(hdmi->sample_rate, pixel_clk, hdmi->ratio); - clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate, + clk_cts = hdmi_compute_cts(hdmi->sample_rate, pixel_clk, hdmi->ratio); if (!clk_cts) { dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n", - __func__, hdmi->pixel_clk_rate); + __func__, pixel_clk); return; } dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d cts=%d\n", __func__, hdmi->sample_rate, hdmi->ratio, - hdmi->pixel_clk_rate, clk_n, clk_cts); + pixel_clk, clk_n, clk_cts); hdmi_set_clock_regenerator_n(hdmi, clk_n); hdmi_regenerate_cts(hdmi, clk_cts); @@ -366,32 +354,12 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi) static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi) { - unsigned int clk_n, clk_cts; - - clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate, - hdmi->ratio); - clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate, - hdmi->ratio); - - if (!clk_cts) { - dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n", - __func__, hdmi->pixel_clk_rate); - return; - } - - dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d cts=%d\n", - __func__, hdmi->sample_rate, hdmi->ratio, - hdmi->pixel_clk_rate, clk_n, clk_cts); - - hdmi_set_clock_regenerator_n(hdmi, clk_n); - hdmi_regenerate_cts(hdmi, clk_cts); + hdmi_set_clk_regenerator(hdmi, 74250000); } static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi) { - /* Get pixel clock from ipu */ - hdmi_get_pixel_clk(hdmi); - hdmi_set_clk_regenerator(hdmi); + hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock); } /* @@ -459,38 +427,45 @@ static void hdmi_video_sample(struct imx_hdmi *hdmi) static int is_color_space_conversion(struct imx_hdmi *hdmi) { - return (hdmi->hdmi_data.enc_in_format != - hdmi->hdmi_data.enc_out_format); + return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format; } static int is_color_space_decimation(struct imx_hdmi *hdmi) { - return ((hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS) && - (hdmi->hdmi_data.enc_in_format == RGB || - hdmi->hdmi_data.enc_in_format == YCBCR444)); + if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS) + return 0; + if (hdmi->hdmi_data.enc_in_format == RGB || + hdmi->hdmi_data.enc_in_format == YCBCR444) + return 1; + return 0; } static int is_color_space_interpolation(struct imx_hdmi *hdmi) { - return ((hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) && - (hdmi->hdmi_data.enc_out_format == RGB || - hdmi->hdmi_data.enc_out_format == YCBCR444)); + if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS) + return 0; + if (hdmi->hdmi_data.enc_out_format == RGB || + hdmi->hdmi_data.enc_out_format == YCBCR444) + return 1; + return 0; } static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi) { const u16 (*csc_coeff)[3][4] = &csc_coeff_default; + unsigned i; u32 csc_scale = 1; - u8 val; if (is_color_space_conversion(hdmi)) { if (hdmi->hdmi_data.enc_out_format == RGB) { - if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601) + if (hdmi->hdmi_data.colorimetry == + HDMI_COLORIMETRY_ITU_601) csc_coeff = &csc_coeff_rgb_out_eitu601; else csc_coeff = &csc_coeff_rgb_out_eitu709; } else if (hdmi->hdmi_data.enc_in_format == RGB) { - if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601) + if (hdmi->hdmi_data.colorimetry == + HDMI_COLORIMETRY_ITU_601) csc_coeff = &csc_coeff_rgb_in_eitu601; else csc_coeff = &csc_coeff_rgb_in_eitu709; @@ -498,37 +473,24 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi) } } - hdmi_writeb(hdmi, ((*csc_coeff)[0][0] & 0xff), HDMI_CSC_COEF_A1_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[0][0] >> 8), HDMI_CSC_COEF_A1_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[0][1] & 0xff), HDMI_CSC_COEF_A2_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[0][1] >> 8), HDMI_CSC_COEF_A2_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[0][2] & 0xff), HDMI_CSC_COEF_A3_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[0][2] >> 8), HDMI_CSC_COEF_A3_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[0][3] & 0xff), HDMI_CSC_COEF_A4_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[0][3] >> 8), HDMI_CSC_COEF_A4_MSB); + /* The CSC registers are sequential, alternating MSB then LSB */ + for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) { + u16 coeff_a = (*csc_coeff)[0][i]; + u16 coeff_b = (*csc_coeff)[1][i]; + u16 coeff_c = (*csc_coeff)[2][i]; - hdmi_writeb(hdmi, ((*csc_coeff)[1][0] & 0xff), HDMI_CSC_COEF_B1_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[1][0] >> 8), HDMI_CSC_COEF_B1_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[1][1] & 0xff), HDMI_CSC_COEF_B2_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[1][1] >> 8), HDMI_CSC_COEF_B2_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[1][2] & 0xff), HDMI_CSC_COEF_B3_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[1][2] >> 8), HDMI_CSC_COEF_B3_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[1][3] & 0xff), HDMI_CSC_COEF_B4_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[1][3] >> 8), HDMI_CSC_COEF_B4_MSB); + hdmi_writeb(hdmi, coeff_a & 0xff, + HDMI_CSC_COEF_A1_LSB + i * 2); + hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2); + hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2); + hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2); + hdmi_writeb(hdmi, coeff_c & 0xff, + HDMI_CSC_COEF_C1_LSB + i * 2); + hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2); + } - hdmi_writeb(hdmi, ((*csc_coeff)[2][0] & 0xff), HDMI_CSC_COEF_C1_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[2][0] >> 8), HDMI_CSC_COEF_C1_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[2][1] & 0xff), HDMI_CSC_COEF_C2_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[2][1] >> 8), HDMI_CSC_COEF_C2_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[2][2] & 0xff), HDMI_CSC_COEF_C3_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[2][2] >> 8), HDMI_CSC_COEF_C3_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[2][3] & 0xff), HDMI_CSC_COEF_C4_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[2][3] >> 8), HDMI_CSC_COEF_C4_MSB); - - val = hdmi_readb(hdmi, HDMI_CSC_SCALE); - val &= ~HDMI_CSC_SCALE_CSCSCALE_MASK; - val |= csc_scale & HDMI_CSC_SCALE_CSCSCALE_MASK; - hdmi_writeb(hdmi, val, HDMI_CSC_SCALE); + hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK, + HDMI_CSC_SCALE); } static void hdmi_video_csc(struct imx_hdmi *hdmi) @@ -536,7 +498,6 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi) int color_depth = 0; int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE; int decimation = 0; - u8 val; /* YCC422 interpolation to 444 mode */ if (is_color_space_interpolation(hdmi)) @@ -557,10 +518,8 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi) /* Configure the CSC registers */ hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG); - val = hdmi_readb(hdmi, HDMI_CSC_SCALE); - val &= ~HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK; - val |= color_depth; - hdmi_writeb(hdmi, val, HDMI_CSC_SCALE); + hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK, + HDMI_CSC_SCALE); imx_hdmi_update_csc_coeffs(hdmi); } @@ -576,7 +535,7 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi) unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit; unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP; struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data; - u8 val; + u8 val, vp_conf; if (hdmi_data->enc_out_format == RGB || hdmi_data->enc_out_format == YCBCR444) { @@ -615,107 +574,75 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi) HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK); hdmi_writeb(hdmi, val, HDMI_VP_PR_CD); - val = hdmi_readb(hdmi, HDMI_VP_STUFF); - val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK; - val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE; - hdmi_writeb(hdmi, val, HDMI_VP_STUFF); + hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE, + HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF); /* Data from pixel repeater block */ if (hdmi_data->pix_repet_factor > 1) { - val = hdmi_readb(hdmi, HDMI_VP_CONF); - val &= ~(HDMI_VP_CONF_PR_EN_MASK | - HDMI_VP_CONF_BYPASS_SELECT_MASK); - val |= HDMI_VP_CONF_PR_EN_ENABLE | - HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER; - hdmi_writeb(hdmi, val, HDMI_VP_CONF); + vp_conf = HDMI_VP_CONF_PR_EN_ENABLE | + HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER; } else { /* data from packetizer block */ - val = hdmi_readb(hdmi, HDMI_VP_CONF); - val &= ~(HDMI_VP_CONF_PR_EN_MASK | - HDMI_VP_CONF_BYPASS_SELECT_MASK); - val |= HDMI_VP_CONF_PR_EN_DISABLE | - HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER; - hdmi_writeb(hdmi, val, HDMI_VP_CONF); + vp_conf = HDMI_VP_CONF_PR_EN_DISABLE | + HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER; } - val = hdmi_readb(hdmi, HDMI_VP_STUFF); - val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK; - val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET; - hdmi_writeb(hdmi, val, HDMI_VP_STUFF); + hdmi_modb(hdmi, vp_conf, + HDMI_VP_CONF_PR_EN_MASK | + HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF); + + hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET, + HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF); hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP); if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) { - val = hdmi_readb(hdmi, HDMI_VP_CONF); - val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK | - HDMI_VP_CONF_PP_EN_ENMASK | - HDMI_VP_CONF_YCC422_EN_MASK); - val |= HDMI_VP_CONF_BYPASS_EN_DISABLE | - HDMI_VP_CONF_PP_EN_ENABLE | - HDMI_VP_CONF_YCC422_EN_DISABLE; - hdmi_writeb(hdmi, val, HDMI_VP_CONF); + vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE | + HDMI_VP_CONF_PP_EN_ENABLE | + HDMI_VP_CONF_YCC422_EN_DISABLE; } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) { - val = hdmi_readb(hdmi, HDMI_VP_CONF); - val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK | - HDMI_VP_CONF_PP_EN_ENMASK | - HDMI_VP_CONF_YCC422_EN_MASK); - val |= HDMI_VP_CONF_BYPASS_EN_DISABLE | - HDMI_VP_CONF_PP_EN_DISABLE | - HDMI_VP_CONF_YCC422_EN_ENABLE; - hdmi_writeb(hdmi, val, HDMI_VP_CONF); + vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE | + HDMI_VP_CONF_PP_EN_DISABLE | + HDMI_VP_CONF_YCC422_EN_ENABLE; } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) { - val = hdmi_readb(hdmi, HDMI_VP_CONF); - val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK | - HDMI_VP_CONF_PP_EN_ENMASK | - HDMI_VP_CONF_YCC422_EN_MASK); - val |= HDMI_VP_CONF_BYPASS_EN_ENABLE | - HDMI_VP_CONF_PP_EN_DISABLE | - HDMI_VP_CONF_YCC422_EN_DISABLE; - hdmi_writeb(hdmi, val, HDMI_VP_CONF); + vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE | + HDMI_VP_CONF_PP_EN_DISABLE | + HDMI_VP_CONF_YCC422_EN_DISABLE; } else { return; } - val = hdmi_readb(hdmi, HDMI_VP_STUFF); - val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK | - HDMI_VP_STUFF_YCC422_STUFFING_MASK); - val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE | - HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE; - hdmi_writeb(hdmi, val, HDMI_VP_STUFF); + hdmi_modb(hdmi, vp_conf, + HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK | + HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF); - val = hdmi_readb(hdmi, HDMI_VP_CONF); - val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK; - val |= output_select; - hdmi_writeb(hdmi, val, HDMI_VP_CONF); + hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE | + HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE, + HDMI_VP_STUFF_PP_STUFFING_MASK | + HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF); + + hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK, + HDMI_VP_CONF); } static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi, unsigned char bit) { - u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0); - val &= ~HDMI_PHY_TST0_TSTCLR_MASK; - val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) & - HDMI_PHY_TST0_TSTCLR_MASK; - hdmi_writeb(hdmi, val, HDMI_PHY_TST0); + hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET, + HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0); } static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi, unsigned char bit) { - u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0); - val &= ~HDMI_PHY_TST0_TSTEN_MASK; - val |= (bit << HDMI_PHY_TST0_TSTEN_OFFSET) & - HDMI_PHY_TST0_TSTEN_MASK; - hdmi_writeb(hdmi, val, HDMI_PHY_TST0); + hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET, + HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0); } static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi, unsigned char bit) { - u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0); - val &= ~HDMI_PHY_TST0_TSTCLK_MASK; - val |= (bit << HDMI_PHY_TST0_TSTCLK_OFFSET) & - HDMI_PHY_TST0_TSTCLK_MASK; - hdmi_writeb(hdmi, val, HDMI_PHY_TST0); + hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET, + HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0); } static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi, @@ -806,19 +733,94 @@ static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable) HDMI_PHY_CONF0_SELDIPIF_MASK); } +enum { + RES_8, + RES_10, + RES_12, + RES_MAX, +}; + +struct mpll_config { + unsigned long mpixelclock; + struct { + u16 cpce; + u16 gmp; + } res[RES_MAX]; +}; + +static const struct mpll_config mpll_config[] = { + { + 45250000, { + { 0x01e0, 0x0000 }, + { 0x21e1, 0x0000 }, + { 0x41e2, 0x0000 } + }, + }, { + 92500000, { + { 0x0140, 0x0005 }, + { 0x2141, 0x0005 }, + { 0x4142, 0x0005 }, + }, + }, { + 148500000, { + { 0x00a0, 0x000a }, + { 0x20a1, 0x000a }, + { 0x40a2, 0x000a }, + }, + }, { + ~0UL, { + { 0x00a0, 0x000a }, + { 0x2001, 0x000f }, + { 0x4002, 0x000f }, + }, + } +}; + +struct curr_ctrl { + unsigned long mpixelclock; + u16 curr[RES_MAX]; +}; + +static const struct curr_ctrl curr_ctrl[] = { + /* pixelclk bpp8 bpp10 bpp12 */ + { + 54000000, { 0x091c, 0x091c, 0x06dc }, + }, { + 58400000, { 0x091c, 0x06dc, 0x06dc }, + }, { + 72000000, { 0x06dc, 0x06dc, 0x091c }, + }, { + 74250000, { 0x06dc, 0x0b5c, 0x091c }, + }, { + 118800000, { 0x091c, 0x091c, 0x06dc }, + }, { + 216000000, { 0x06dc, 0x0b5c, 0x091c }, + } +}; + static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, unsigned char res, int cscon) { + unsigned res_idx, i; u8 val, msec; - /* color resolution 0 is 8 bit colour depth */ - if (!res) - res = 8; - if (prep) return -EINVAL; - else if (res != 8 && res != 12) + + switch (res) { + case 0: /* color resolution 0 is 8 bit colour depth */ + case 8: + res_idx = RES_8; + break; + case 10: + res_idx = RES_10; + break; + case 12: + res_idx = RES_12; + break; + default: return -EINVAL; + } /* Enable csc path */ if (cscon) @@ -845,165 +847,30 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, HDMI_PHY_I2CM_SLAVE_ADDR); hdmi_phy_test_clear(hdmi, 0); - if (hdmi->hdmi_data.video_mode.mpixelclock <= 45250000) { - switch (res) { - case 8: - /* PLL/MPLL Cfg */ - hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06); - hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); /* GMPCTRL */ + /* PLL/MPLL Cfg - always match on final entry */ + for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++) + if (hdmi->hdmi_data.video_mode.mpixelclock <= + mpll_config[i].mpixelclock) break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x21e1, 0x06); - hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x41e2, 0x06); - hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); - break; - default: - return -EINVAL; - } - } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 92500000) { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x0140, 0x06); - hdmi_phy_i2c_write(hdmi, 0x0005, 0x15); - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x2141, 0x06); - hdmi_phy_i2c_write(hdmi, 0x0005, 0x15); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x4142, 0x06); - hdmi_phy_i2c_write(hdmi, 0x0005, 0x15); - default: - return -EINVAL; - } - } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 148500000) { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06); - hdmi_phy_i2c_write(hdmi, 0x000a, 0x15); - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x20a1, 0x06); - hdmi_phy_i2c_write(hdmi, 0x000a, 0x15); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x40a2, 0x06); - hdmi_phy_i2c_write(hdmi, 0x000a, 0x15); - default: - return -EINVAL; - } - } else { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06); - hdmi_phy_i2c_write(hdmi, 0x000a, 0x15); - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x2001, 0x06); - hdmi_phy_i2c_write(hdmi, 0x000f, 0x15); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x4002, 0x06); - hdmi_phy_i2c_write(hdmi, 0x000f, 0x15); - default: - return -EINVAL; - } - } - if (hdmi->hdmi_data.video_mode.mpixelclock <= 54000000) { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); /* CURRCTRL */ + hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06); + hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15); + + for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++) + if (hdmi->hdmi_data.video_mode.mpixelclock <= + curr_ctrl[i].mpixelclock) break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); - break; - default: - return -EINVAL; - } - } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 58400000) { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); - break; - default: - return -EINVAL; - } - } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 72000000) { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); - break; - default: - return -EINVAL; - } - } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 74250000) { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); - break; - default: - return -EINVAL; - } - } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 118800000) { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); - break; - default: - return -EINVAL; - } - } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 216000000) { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); - break; - default: - return -EINVAL; - } - } else { + + if (i >= ARRAY_SIZE(curr_ctrl)) { dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n", hdmi->hdmi_data.video_mode.mpixelclock); return -EINVAL; } + /* CURRCTRL */ + hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10); + hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17); /* RESISTANCE TERM 133Ohm Cfg */ @@ -1072,7 +939,7 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi) static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi) { - u8 de, val; + u8 de; if (hdmi->hdmi_data.video_mode.mdataenablepolarity) de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH; @@ -1080,20 +947,13 @@ static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi) de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW; /* disable rx detect */ - val = hdmi_readb(hdmi, HDMI_A_HDCPCFG0); - val &= HDMI_A_HDCPCFG0_RXDETECT_MASK; - val |= HDMI_A_HDCPCFG0_RXDETECT_DISABLE; - hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG0); + hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE, + HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0); - val = hdmi_readb(hdmi, HDMI_A_VIDPOLCFG); - val &= HDMI_A_VIDPOLCFG_DATAENPOL_MASK; - val |= de; - hdmi_writeb(hdmi, val, HDMI_A_VIDPOLCFG); + hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG); - val = hdmi_readb(hdmi, HDMI_A_HDCPCFG1); - val &= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK; - val |= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE; - hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG1); + hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE, + HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1); } static void hdmi_config_AVI(struct imx_hdmi *hdmi) @@ -1317,11 +1177,7 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi) static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi) { - u8 clkdis; - - clkdis = hdmi_readb(hdmi, HDMI_MC_CLKDIS); - clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE; - hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); + hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS); } /* Workaround to clear the overflow condition */ @@ -1456,9 +1312,6 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi) /* Clear Hotplug interrupts */ hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0); - /* Unmute interrupts */ - hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); - return 0; } @@ -1527,12 +1380,9 @@ static void imx_hdmi_poweroff(struct imx_hdmi *hdmi) static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector *connector, bool force) { - /* FIXME */ - return connector_status_connected; -} - -static void imx_hdmi_connector_destroy(struct drm_connector *connector) -{ + struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi, + connector); + return hdmi->connector_status; } static int imx_hdmi_connector_get_modes(struct drm_connector *connector) @@ -1560,13 +1410,6 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector) return 0; } -static int imx_hdmi_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - - return MODE_OK; -} - static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector *connector) { @@ -1614,28 +1457,21 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder) struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); imx_hdmi_poweroff(hdmi); - imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE, - V4L2_PIX_FMT_RGB24); + imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24); } static void imx_hdmi_encoder_commit(struct drm_encoder *encoder) { struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); - int mux = imx_drm_encoder_get_mux_id(hdmi->imx_drm_encoder, - encoder->crtc); + int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder); imx_hdmi_set_ipu_di_mux(hdmi, mux); imx_hdmi_poweron(hdmi); } -static void imx_hdmi_encoder_destroy(struct drm_encoder *encoder) -{ - return; -} - static struct drm_encoder_funcs imx_hdmi_encoder_funcs = { - .destroy = imx_hdmi_encoder_destroy, + .destroy = imx_drm_encoder_destroy, }; static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = { @@ -1651,21 +1487,32 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = { .dpms = drm_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = imx_hdmi_connector_detect, - .destroy = imx_hdmi_connector_destroy, + .destroy = imx_drm_connector_destroy, }; static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = { .get_modes = imx_hdmi_connector_get_modes, - .mode_valid = imx_hdmi_connector_mode_valid, + .mode_valid = imx_drm_connector_mode_valid, .best_encoder = imx_hdmi_connector_best_encoder, }; +static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id) +{ + struct imx_hdmi *hdmi = dev_id; + u8 intr_stat; + + intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0); + if (intr_stat) + hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); + + return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE; +} + static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) { struct imx_hdmi *hdmi = dev_id; u8 intr_stat; u8 phy_int_pol; - u8 val; intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0); @@ -1675,55 +1522,47 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) if (phy_int_pol & HDMI_PHY_HPD) { dev_dbg(hdmi->dev, "EVENT=plugin\n"); - val = hdmi_readb(hdmi, HDMI_PHY_POL0); - val &= ~HDMI_PHY_HPD; - hdmi_writeb(hdmi, val, HDMI_PHY_POL0); + hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0); + hdmi->connector_status = connector_status_connected; imx_hdmi_poweron(hdmi); } else { dev_dbg(hdmi->dev, "EVENT=plugout\n"); - val = hdmi_readb(hdmi, HDMI_PHY_POL0); - val |= HDMI_PHY_HPD; - hdmi_writeb(hdmi, val, HDMI_PHY_POL0); + hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, + HDMI_PHY_POL0); + hdmi->connector_status = connector_status_disconnected; imx_hdmi_poweroff(hdmi); } + drm_helper_hpd_irq_event(hdmi->connector.dev); } hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0); + hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); return IRQ_HANDLED; } -static int imx_hdmi_register(struct imx_hdmi *hdmi) +static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi) { int ret; - hdmi->connector.funcs = &imx_hdmi_connector_funcs; - hdmi->encoder.funcs = &imx_hdmi_encoder_funcs; + ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder, + hdmi->dev->of_node); + if (ret) + return ret; - hdmi->encoder.encoder_type = DRM_MODE_ENCODER_TMDS; - hdmi->connector.connector_type = DRM_MODE_CONNECTOR_HDMIA; + hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs); - ret = imx_drm_add_encoder(&hdmi->encoder, &hdmi->imx_drm_encoder, - THIS_MODULE); - if (ret) { - dev_err(hdmi->dev, "adding encoder failed: %d\n", ret); - return ret; - } + drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs, + DRM_MODE_ENCODER_TMDS); drm_connector_helper_add(&hdmi->connector, &imx_hdmi_connector_helper_funcs); - - ret = imx_drm_add_connector(&hdmi->connector, - &hdmi->imx_drm_connector, THIS_MODULE); - if (ret) { - imx_drm_remove_encoder(hdmi->imx_drm_encoder); - dev_err(hdmi->dev, "adding connector failed: %d\n", ret); - return ret; - } + drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA); hdmi->connector.encoder = &hdmi->encoder; @@ -1750,28 +1589,33 @@ static const struct of_device_id imx_hdmi_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids); -static int imx_hdmi_platform_probe(struct platform_device *pdev) +static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); const struct of_device_id *of_id = - of_match_device(imx_hdmi_dt_ids, &pdev->dev); - struct device_node *np = pdev->dev.of_node; + of_match_device(imx_hdmi_dt_ids, dev); + struct drm_device *drm = data; + struct device_node *np = dev->of_node; struct device_node *ddc_node; struct imx_hdmi *hdmi; struct resource *iores; int ret, irq; - hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); + hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); if (!hdmi) return -ENOMEM; - hdmi->dev = &pdev->dev; + hdmi->dev = dev; + hdmi->connector_status = connector_status_disconnected; + hdmi->sample_rate = 48000; + hdmi->ratio = 100; if (of_id) { const struct platform_device_id *device_id = of_id->data; hdmi->dev_type = device_id->driver_data; } - ddc_node = of_parse_phandle(np, "ddc", 0); + ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); if (ddc_node) { hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); if (!hdmi->ddc) @@ -1786,13 +1630,14 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev) if (irq < 0) return -EINVAL; - ret = devm_request_irq(&pdev->dev, irq, imx_hdmi_irq, 0, - dev_name(&pdev->dev), hdmi); + ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq, + imx_hdmi_irq, IRQF_SHARED, + dev_name(dev), hdmi); if (ret) return ret; iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hdmi->regs = devm_ioremap_resource(&pdev->dev, iores); + hdmi->regs = devm_ioremap_resource(dev, iores); if (IS_ERR(hdmi->regs)) return PTR_ERR(hdmi->regs); @@ -1831,7 +1676,7 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev) } /* Product and revision IDs */ - dev_info(&pdev->dev, + dev_info(dev, "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n", hdmi_readb(hdmi, HDMI_DESIGN_ID), hdmi_readb(hdmi, HDMI_REVISION_ID), @@ -1859,13 +1704,14 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev) if (ret) goto err_iahb; - ret = imx_hdmi_register(hdmi); + ret = imx_hdmi_register(drm, hdmi); if (ret) goto err_iahb; - imx_drm_encoder_add_possible_crtcs(hdmi->imx_drm_encoder, np); + /* Unmute interrupts */ + hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); - platform_set_drvdata(pdev, hdmi); + dev_set_drvdata(dev, hdmi); return 0; @@ -1877,20 +1723,35 @@ err_isfr: return ret; } -static int imx_hdmi_platform_remove(struct platform_device *pdev) +static void imx_hdmi_unbind(struct device *dev, struct device *master, + void *data) { - struct imx_hdmi *hdmi = platform_get_drvdata(pdev); - struct drm_connector *connector = &hdmi->connector; - struct drm_encoder *encoder = &hdmi->encoder; + struct imx_hdmi *hdmi = dev_get_drvdata(dev); - drm_mode_connector_detach_encoder(connector, encoder); - imx_drm_remove_connector(hdmi->imx_drm_connector); - imx_drm_remove_encoder(hdmi->imx_drm_encoder); + /* Disable all interrupts */ + hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); + + hdmi->connector.funcs->destroy(&hdmi->connector); + hdmi->encoder.funcs->destroy(&hdmi->encoder); clk_disable_unprepare(hdmi->iahb_clk); clk_disable_unprepare(hdmi->isfr_clk); i2c_put_adapter(hdmi->ddc); +} +static const struct component_ops hdmi_ops = { + .bind = imx_hdmi_bind, + .unbind = imx_hdmi_unbind, +}; + +static int imx_hdmi_platform_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &hdmi_ops); +} + +static int imx_hdmi_platform_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &hdmi_ops); return 0; } diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c index 7e593296ac47..fe4c1ef4e7a5 100644 --- a/drivers/staging/imx-drm/imx-ldb.c +++ b/drivers/staging/imx-drm/imx-ldb.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -58,9 +59,8 @@ struct imx_ldb; struct imx_ldb_channel { struct imx_ldb *ldb; struct drm_connector connector; - struct imx_drm_connector *imx_drm_connector; struct drm_encoder encoder; - struct imx_drm_encoder *imx_drm_encoder; + struct device_node *child; int chno; void *edid; int edid_len; @@ -91,11 +91,6 @@ static enum drm_connector_status imx_ldb_connector_detect( return connector_status_connected; } -static void imx_ldb_connector_destroy(struct drm_connector *connector) -{ - /* do not free here */ -} - static int imx_ldb_connector_get_modes(struct drm_connector *connector) { struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector); @@ -111,6 +106,8 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector) struct drm_display_mode *mode; mode = drm_mode_create(connector->dev); + if (!mode) + return -EINVAL; drm_mode_copy(mode, &imx_ldb_ch->mode); mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; drm_mode_probed_add(connector, mode); @@ -120,12 +117,6 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector) return num_modes; } -static int imx_ldb_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - return 0; -} - static struct drm_encoder *imx_ldb_connector_best_encoder( struct drm_connector *connector) { @@ -168,7 +159,9 @@ static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno, /* set display clock mux to LDB input clock */ ret = clk_set_parent(ldb->clk_sel[mux], ldb->clk[chno]); if (ret) - dev_err(ldb->dev, "unable to set di%d parent clock to ldb_di%d\n", mux, chno); + dev_err(ldb->dev, + "unable to set di%d parent clock to ldb_di%d\n", mux, + chno); } static void imx_ldb_encoder_prepare(struct drm_encoder *encoder) @@ -179,8 +172,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder) u32 pixel_fmt; unsigned long serial_clk; unsigned long di_clk = mode->clock * 1000; - int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->imx_drm_encoder, - encoder->crtc); + int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder); if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) { /* dual channel LVDS mode */ @@ -189,7 +181,8 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder) imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk); } else { serial_clk = 7000UL * mode->clock; - imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk, di_clk); + imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk, + di_clk); } switch (imx_ldb_ch->chno) { @@ -207,8 +200,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder) pixel_fmt = V4L2_PIX_FMT_RGB24; } - imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_LVDS, - pixel_fmt); + imx_drm_panel_format(encoder, pixel_fmt); } static void imx_ldb_encoder_commit(struct drm_encoder *encoder) @@ -216,8 +208,7 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder) struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); struct imx_ldb *ldb = imx_ldb_ch->ldb; int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; - int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->imx_drm_encoder, - encoder->crtc); + int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder); if (dual) { clk_prepare_enable(ldb->clk[0]); @@ -316,26 +307,21 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder) } } -static void imx_ldb_encoder_destroy(struct drm_encoder *encoder) -{ - /* do not free here */ -} - static struct drm_connector_funcs imx_ldb_connector_funcs = { .dpms = drm_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = imx_ldb_connector_detect, - .destroy = imx_ldb_connector_destroy, + .destroy = imx_drm_connector_destroy, }; static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = { .get_modes = imx_ldb_connector_get_modes, .best_encoder = imx_ldb_connector_best_encoder, - .mode_valid = imx_ldb_connector_mode_valid, + .mode_valid = imx_drm_connector_mode_valid, }; static struct drm_encoder_funcs imx_ldb_encoder_funcs = { - .destroy = imx_ldb_encoder_destroy, + .destroy = imx_drm_encoder_destroy, }; static struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = { @@ -351,56 +337,47 @@ static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno) { char clkname[16]; - sprintf(clkname, "di%d", chno); + snprintf(clkname, sizeof(clkname), "di%d", chno); ldb->clk[chno] = devm_clk_get(ldb->dev, clkname); if (IS_ERR(ldb->clk[chno])) return PTR_ERR(ldb->clk[chno]); - sprintf(clkname, "di%d_pll", chno); + snprintf(clkname, sizeof(clkname), "di%d_pll", chno); ldb->clk_pll[chno] = devm_clk_get(ldb->dev, clkname); return PTR_ERR_OR_ZERO(ldb->clk_pll[chno]); } -static int imx_ldb_register(struct imx_ldb_channel *imx_ldb_ch) +static int imx_ldb_register(struct drm_device *drm, + struct imx_ldb_channel *imx_ldb_ch) { - int ret; struct imx_ldb *ldb = imx_ldb_ch->ldb; + int ret; + + ret = imx_drm_encoder_parse_of(drm, &imx_ldb_ch->encoder, + imx_ldb_ch->child); + if (ret) + return ret; ret = imx_ldb_get_clk(ldb, imx_ldb_ch->chno); if (ret) return ret; + if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) { - ret |= imx_ldb_get_clk(ldb, 1); + ret = imx_ldb_get_clk(ldb, 1); if (ret) return ret; } - imx_ldb_ch->connector.funcs = &imx_ldb_connector_funcs; - imx_ldb_ch->encoder.funcs = &imx_ldb_encoder_funcs; - - imx_ldb_ch->encoder.encoder_type = DRM_MODE_ENCODER_LVDS; - imx_ldb_ch->connector.connector_type = DRM_MODE_CONNECTOR_LVDS; - drm_encoder_helper_add(&imx_ldb_ch->encoder, &imx_ldb_encoder_helper_funcs); - ret = imx_drm_add_encoder(&imx_ldb_ch->encoder, - &imx_ldb_ch->imx_drm_encoder, THIS_MODULE); - if (ret) { - dev_err(ldb->dev, "adding encoder failed with %d\n", ret); - return ret; - } + drm_encoder_init(drm, &imx_ldb_ch->encoder, &imx_ldb_encoder_funcs, + DRM_MODE_ENCODER_LVDS); drm_connector_helper_add(&imx_ldb_ch->connector, &imx_ldb_connector_helper_funcs); - - ret = imx_drm_add_connector(&imx_ldb_ch->connector, - &imx_ldb_ch->imx_drm_connector, THIS_MODULE); - if (ret) { - imx_drm_remove_encoder(imx_ldb_ch->imx_drm_encoder); - dev_err(ldb->dev, "adding connector failed with %d\n", ret); - return ret; - } + drm_connector_init(drm, &imx_ldb_ch->connector, + &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS); drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, &imx_ldb_ch->encoder); @@ -459,11 +436,12 @@ static const struct of_device_id imx_ldb_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids); -static int imx_ldb_probe(struct platform_device *pdev) +static int imx_ldb_bind(struct device *dev, struct device *master, void *data) { - struct device_node *np = pdev->dev.of_node; + struct drm_device *drm = data; + struct device_node *np = dev->of_node; const struct of_device_id *of_id = - of_match_device(imx_ldb_dt_ids, &pdev->dev); + of_match_device(imx_ldb_dt_ids, dev); struct device_node *child; const u8 *edidp; struct imx_ldb *imx_ldb; @@ -473,17 +451,17 @@ static int imx_ldb_probe(struct platform_device *pdev) int ret; int i; - imx_ldb = devm_kzalloc(&pdev->dev, sizeof(*imx_ldb), GFP_KERNEL); + imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL); if (!imx_ldb) return -ENOMEM; imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr"); if (IS_ERR(imx_ldb->regmap)) { - dev_err(&pdev->dev, "failed to get parent regmap\n"); + dev_err(dev, "failed to get parent regmap\n"); return PTR_ERR(imx_ldb->regmap); } - imx_ldb->dev = &pdev->dev; + imx_ldb->dev = dev; if (of_id) imx_ldb->lvds_mux = of_id->data; @@ -521,7 +499,7 @@ static int imx_ldb_probe(struct platform_device *pdev) return -EINVAL; if (dual && i > 0) { - dev_warn(&pdev->dev, "dual-channel mode, ignoring second output\n"); + dev_warn(dev, "dual-channel mode, ignoring second output\n"); continue; } @@ -531,6 +509,7 @@ static int imx_ldb_probe(struct platform_device *pdev) channel = &imx_ldb->channel[i]; channel->ldb = imx_ldb; channel->chno = i; + channel->child = child; edidp = of_get_property(child, "edid", &channel->edid_len); if (edidp) { @@ -553,54 +532,67 @@ static int imx_ldb_probe(struct platform_device *pdev) case LVDS_BIT_MAP_SPWG: if (datawidth == 24) { if (i == 0 || dual) - imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24; + imx_ldb->ldb_ctrl |= + LDB_DATA_WIDTH_CH0_24; if (i == 1 || dual) - imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24; + imx_ldb->ldb_ctrl |= + LDB_DATA_WIDTH_CH1_24; } break; case LVDS_BIT_MAP_JEIDA: if (datawidth == 18) { - dev_err(&pdev->dev, "JEIDA standard only supported in 24 bit\n"); + dev_err(dev, "JEIDA standard only supported in 24 bit\n"); return -EINVAL; } if (i == 0 || dual) - imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 | LDB_BIT_MAP_CH0_JEIDA; + imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 | + LDB_BIT_MAP_CH0_JEIDA; if (i == 1 || dual) - imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | LDB_BIT_MAP_CH1_JEIDA; + imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | + LDB_BIT_MAP_CH1_JEIDA; break; default: - dev_err(&pdev->dev, "data mapping not specified or invalid\n"); + dev_err(dev, "data mapping not specified or invalid\n"); return -EINVAL; } - ret = imx_ldb_register(channel); + ret = imx_ldb_register(drm, channel); if (ret) return ret; - - imx_drm_encoder_add_possible_crtcs(channel->imx_drm_encoder, child); } - platform_set_drvdata(pdev, imx_ldb); + dev_set_drvdata(dev, imx_ldb); return 0; } -static int imx_ldb_remove(struct platform_device *pdev) +static void imx_ldb_unbind(struct device *dev, struct device *master, + void *data) { - struct imx_ldb *imx_ldb = platform_get_drvdata(pdev); + struct imx_ldb *imx_ldb = dev_get_drvdata(dev); int i; for (i = 0; i < 2; i++) { struct imx_ldb_channel *channel = &imx_ldb->channel[i]; - struct drm_connector *connector = &channel->connector; - struct drm_encoder *encoder = &channel->encoder; - drm_mode_connector_detach_encoder(connector, encoder); - - imx_drm_remove_connector(channel->imx_drm_connector); - imx_drm_remove_encoder(channel->imx_drm_encoder); + channel->connector.funcs->destroy(&channel->connector); + channel->encoder.funcs->destroy(&channel->encoder); } +} +static const struct component_ops imx_ldb_ops = { + .bind = imx_ldb_bind, + .unbind = imx_ldb_unbind, +}; + +static int imx_ldb_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &imx_ldb_ops); +} + +static int imx_ldb_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &imx_ldb_ops); return 0; } diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c index 9abc7ca8b6cf..575533f4fd64 100644 --- a/drivers/staging/imx-drm/imx-tve.c +++ b/drivers/staging/imx-drm/imx-tve.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -30,6 +31,7 @@ #include #include +#include "ipu-v3/imx-ipu-v3.h" #include "imx-drm.h" #define TVE_COM_CONF_REG 0x00 @@ -110,9 +112,7 @@ enum { struct imx_tve { struct drm_connector connector; - struct imx_drm_connector *imx_drm_connector; struct drm_encoder encoder; - struct imx_drm_encoder *imx_drm_encoder; struct device *dev; spinlock_t lock; /* register lock */ bool enabled; @@ -225,11 +225,6 @@ static enum drm_connector_status imx_tve_connector_detect( return connector_status_connected; } -static void imx_tve_connector_destroy(struct drm_connector *connector) -{ - /* do not free here */ -} - static int imx_tve_connector_get_modes(struct drm_connector *connector) { struct imx_tve *tve = con_to_tve(connector); @@ -254,6 +249,11 @@ static int imx_tve_connector_mode_valid(struct drm_connector *connector, { struct imx_tve *tve = con_to_tve(connector); unsigned long rate; + int ret; + + ret = imx_drm_connector_mode_valid(connector, mode); + if (ret != MODE_OK) + return ret; /* pixel clock with 2x oversampling */ rate = clk_round_rate(tve->clk, 2000UL * mode->clock) / 2000; @@ -305,13 +305,11 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder) switch (tve->mode) { case TVE_MODE_VGA: - imx_drm_crtc_panel_format_pins(encoder->crtc, - DRM_MODE_ENCODER_DAC, IPU_PIX_FMT_GBR24, + imx_drm_panel_format_pins(encoder, IPU_PIX_FMT_GBR24, tve->hsync_pin, tve->vsync_pin); break; case TVE_MODE_TVOUT: - imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_TVDAC, - V4L2_PIX_FMT_YUV444); + imx_drm_panel_format(encoder, V4L2_PIX_FMT_YUV444); break; } } @@ -364,16 +362,11 @@ static void imx_tve_encoder_disable(struct drm_encoder *encoder) tve_disable(tve); } -static void imx_tve_encoder_destroy(struct drm_encoder *encoder) -{ - /* do not free here */ -} - static struct drm_connector_funcs imx_tve_connector_funcs = { .dpms = drm_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = imx_tve_connector_detect, - .destroy = imx_tve_connector_destroy, + .destroy = imx_drm_connector_destroy, }; static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = { @@ -383,7 +376,7 @@ static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = { }; static struct drm_encoder_funcs imx_tve_encoder_funcs = { - .destroy = imx_tve_encoder_destroy, + .destroy = imx_drm_encoder_destroy, }; static struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = { @@ -503,34 +496,27 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base) return 0; } -static int imx_tve_register(struct imx_tve *tve) +static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve) { + int encoder_type; int ret; - tve->connector.funcs = &imx_tve_connector_funcs; - tve->encoder.funcs = &imx_tve_encoder_funcs; + encoder_type = tve->mode == TVE_MODE_VGA ? + DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC; - tve->encoder.encoder_type = DRM_MODE_ENCODER_NONE; - tve->connector.connector_type = DRM_MODE_CONNECTOR_VGA; + ret = imx_drm_encoder_parse_of(drm, &tve->encoder, + tve->dev->of_node); + if (ret) + return ret; drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs); - ret = imx_drm_add_encoder(&tve->encoder, &tve->imx_drm_encoder, - THIS_MODULE); - if (ret) { - dev_err(tve->dev, "adding encoder failed with %d\n", ret); - return ret; - } + drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs, + encoder_type); drm_connector_helper_add(&tve->connector, &imx_tve_connector_helper_funcs); - - ret = imx_drm_add_connector(&tve->connector, - &tve->imx_drm_connector, THIS_MODULE); - if (ret) { - imx_drm_remove_encoder(tve->imx_drm_encoder); - dev_err(tve->dev, "adding connector failed with %d\n", ret); - return ret; - } + drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs, + DRM_MODE_CONNECTOR_VGA); drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder); @@ -576,9 +562,11 @@ static const int of_get_tve_mode(struct device_node *np) return -EINVAL; } -static int imx_tve_probe(struct platform_device *pdev) +static int imx_tve_bind(struct device *dev, struct device *master, void *data) { - struct device_node *np = pdev->dev.of_node; + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = data; + struct device_node *np = dev->of_node; struct device_node *ddc_node; struct imx_tve *tve; struct resource *res; @@ -587,14 +575,14 @@ static int imx_tve_probe(struct platform_device *pdev) int irq; int ret; - tve = devm_kzalloc(&pdev->dev, sizeof(*tve), GFP_KERNEL); + tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL); if (!tve) return -ENOMEM; - tve->dev = &pdev->dev; + tve->dev = dev; spin_lock_init(&tve->lock); - ddc_node = of_parse_phandle(np, "ddc", 0); + ddc_node = of_parse_phandle(np, "i2c-ddc-bus", 0); if (ddc_node) { tve->ddc = of_find_i2c_adapter_by_node(ddc_node); of_node_put(ddc_node); @@ -602,7 +590,7 @@ static int imx_tve_probe(struct platform_device *pdev) tve->mode = of_get_tve_mode(np); if (tve->mode != TVE_MODE_VGA) { - dev_err(&pdev->dev, "only VGA mode supported, currently\n"); + dev_err(dev, "only VGA mode supported, currently\n"); return -EINVAL; } @@ -611,7 +599,7 @@ static int imx_tve_probe(struct platform_device *pdev) &tve->hsync_pin); if (ret < 0) { - dev_err(&pdev->dev, "failed to get vsync pin\n"); + dev_err(dev, "failed to get vsync pin\n"); return ret; } @@ -619,40 +607,40 @@ static int imx_tve_probe(struct platform_device *pdev) &tve->vsync_pin); if (ret < 0) { - dev_err(&pdev->dev, "failed to get vsync pin\n"); + dev_err(dev, "failed to get vsync pin\n"); return ret; } } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_ioremap_resource(dev, res); if (IS_ERR(base)) return PTR_ERR(base); tve_regmap_config.lock_arg = tve; - tve->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "tve", base, + tve->regmap = devm_regmap_init_mmio_clk(dev, "tve", base, &tve_regmap_config); if (IS_ERR(tve->regmap)) { - dev_err(&pdev->dev, "failed to init regmap: %ld\n", + dev_err(dev, "failed to init regmap: %ld\n", PTR_ERR(tve->regmap)); return PTR_ERR(tve->regmap); } irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "failed to get irq\n"); + dev_err(dev, "failed to get irq\n"); return irq; } - ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + ret = devm_request_threaded_irq(dev, irq, NULL, imx_tve_irq_handler, IRQF_ONESHOT, "imx-tve", tve); if (ret < 0) { - dev_err(&pdev->dev, "failed to request irq: %d\n", ret); + dev_err(dev, "failed to request irq: %d\n", ret); return ret; } - tve->dac_reg = devm_regulator_get(&pdev->dev, "dac"); + tve->dac_reg = devm_regulator_get(dev, "dac"); if (!IS_ERR(tve->dac_reg)) { regulator_set_voltage(tve->dac_reg, 2750000, 2750000); ret = regulator_enable(tve->dac_reg); @@ -660,17 +648,17 @@ static int imx_tve_probe(struct platform_device *pdev) return ret; } - tve->clk = devm_clk_get(&pdev->dev, "tve"); + tve->clk = devm_clk_get(dev, "tve"); if (IS_ERR(tve->clk)) { - dev_err(&pdev->dev, "failed to get high speed tve clock: %ld\n", + dev_err(dev, "failed to get high speed tve clock: %ld\n", PTR_ERR(tve->clk)); return PTR_ERR(tve->clk); } /* this is the IPU DI clock input selector, can be parented to tve_di */ - tve->di_sel_clk = devm_clk_get(&pdev->dev, "di_sel"); + tve->di_sel_clk = devm_clk_get(dev, "di_sel"); if (IS_ERR(tve->di_sel_clk)) { - dev_err(&pdev->dev, "failed to get ipu di mux clock: %ld\n", + dev_err(dev, "failed to get ipu di mux clock: %ld\n", PTR_ERR(tve->di_sel_clk)); return PTR_ERR(tve->di_sel_clk); } @@ -681,42 +669,51 @@ static int imx_tve_probe(struct platform_device *pdev) ret = regmap_read(tve->regmap, TVE_COM_CONF_REG, &val); if (ret < 0) { - dev_err(&pdev->dev, "failed to read configuration register: %d\n", ret); + dev_err(dev, "failed to read configuration register: %d\n", ret); return ret; } if (val != 0x00100000) { - dev_err(&pdev->dev, "configuration register default value indicates this is not a TVEv2\n"); + dev_err(dev, "configuration register default value indicates this is not a TVEv2\n"); return -ENODEV; } /* disable cable detection for VGA mode */ ret = regmap_write(tve->regmap, TVE_CD_CONT_REG, 0); - ret = imx_tve_register(tve); + ret = imx_tve_register(drm, tve); if (ret) return ret; - ret = imx_drm_encoder_add_possible_crtcs(tve->imx_drm_encoder, np); - - platform_set_drvdata(pdev, tve); + dev_set_drvdata(dev, tve); return 0; } -static int imx_tve_remove(struct platform_device *pdev) +static void imx_tve_unbind(struct device *dev, struct device *master, + void *data) { - struct imx_tve *tve = platform_get_drvdata(pdev); - struct drm_connector *connector = &tve->connector; - struct drm_encoder *encoder = &tve->encoder; + struct imx_tve *tve = dev_get_drvdata(dev); - drm_mode_connector_detach_encoder(connector, encoder); - - imx_drm_remove_connector(tve->imx_drm_connector); - imx_drm_remove_encoder(tve->imx_drm_encoder); + tve->connector.funcs->destroy(&tve->connector); + tve->encoder.funcs->destroy(&tve->encoder); if (!IS_ERR(tve->dac_reg)) regulator_disable(tve->dac_reg); +} +static const struct component_ops imx_tve_ops = { + .bind = imx_tve_bind, + .unbind = imx_tve_unbind, +}; + +static int imx_tve_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &imx_tve_ops); +} + +static int imx_tve_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &imx_tve_ops); return 0; } diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h index 4826b5c0249d..c4d14ead5837 100644 --- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h +++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h @@ -25,6 +25,8 @@ enum ipuv3_type { IPUV3H, }; +#define IPU_PIX_FMT_GBR24 v4l2_fourcc('G', 'B', 'R', '3') + /* * Bitfield of Display Interface signal polarities. */ diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c index d0e3bc3c53e7..d5de8bb5c803 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c @@ -262,7 +262,7 @@ void ipu_dc_disable_channel(struct ipu_dc *dc) /* Wait for DC triple buffer to empty */ while ((readl(priv->dc_reg + DC_STAT) & val) != val) { - msleep(2); + usleep_range(2000, 20000); timeout -= 2; if (timeout <= 0) break; diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c index 948a49b289ef..82a9ebad697c 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c @@ -19,9 +19,6 @@ #include #include #include -#include -#include -#include #include "imx-ipu-v3.h" #include "ipu-prv.h" @@ -33,10 +30,7 @@ struct ipu_di { struct clk *clk_di; /* display input clock */ struct clk *clk_ipu; /* IPU bus clock */ struct clk *clk_di_pixel; /* resulting pixel clock */ - struct clk_hw clk_hw_out; - char *clk_name; bool inuse; - unsigned long clkflags; struct ipu_soc *ipu; }; @@ -141,130 +135,6 @@ static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset) writel(value, di->base + offset); } -static int ipu_di_clk_calc_div(unsigned long inrate, unsigned long outrate) -{ - u64 tmp = inrate; - int div; - - tmp *= 16; - - do_div(tmp, outrate); - - div = tmp; - - if (div < 0x10) - div = 0x10; - -#ifdef WTF_IS_THIS - /* - * Freescale has this in their Kernel. It is neither clear what - * it does nor why it does it - */ - if (div & 0x10) - div &= ~0x7; - else { - /* Round up divider if it gets us closer to desired pix clk */ - if ((div & 0xC) == 0xC) { - div += 0x10; - div &= ~0xF; - } - } -#endif - return div; -} - -static unsigned long clk_di_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out); - unsigned long outrate; - u32 div = ipu_di_read(di, DI_BS_CLKGEN0); - - if (div < 0x10) - div = 0x10; - - outrate = (parent_rate / div) * 16; - - return outrate; -} - -static long clk_di_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out); - unsigned long outrate; - int div; - u32 val; - - div = ipu_di_clk_calc_div(*prate, rate); - - outrate = (*prate / div) * 16; - - val = ipu_di_read(di, DI_GENERAL); - - if (!(val & DI_GEN_DI_CLK_EXT) && outrate > *prate / 2) - outrate = *prate / 2; - - dev_dbg(di->ipu->dev, - "%s: inrate: %ld div: 0x%08x outrate: %ld wanted: %ld\n", - __func__, *prate, div, outrate, rate); - - return outrate; -} - -static int clk_di_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out); - int div; - u32 clkgen0; - - clkgen0 = ipu_di_read(di, DI_BS_CLKGEN0) & ~0xfff; - - div = ipu_di_clk_calc_div(parent_rate, rate); - - ipu_di_write(di, clkgen0 | div, DI_BS_CLKGEN0); - - dev_dbg(di->ipu->dev, "%s: inrate: %ld desired: %ld div: 0x%08x\n", - __func__, parent_rate, rate, div); - return 0; -} - -static u8 clk_di_get_parent(struct clk_hw *hw) -{ - struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out); - u32 val; - - val = ipu_di_read(di, DI_GENERAL); - - return val & DI_GEN_DI_CLK_EXT ? 1 : 0; -} - -static int clk_di_set_parent(struct clk_hw *hw, u8 index) -{ - struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out); - u32 val; - - val = ipu_di_read(di, DI_GENERAL); - - if (index) - val |= DI_GEN_DI_CLK_EXT; - else - val &= ~DI_GEN_DI_CLK_EXT; - - ipu_di_write(di, val, DI_GENERAL); - - return 0; -} - -static struct clk_ops clk_di_ops = { - .round_rate = clk_di_round_rate, - .set_rate = clk_di_set_rate, - .recalc_rate = clk_di_recalc_rate, - .set_parent = clk_di_set_parent, - .get_parent = clk_di_get_parent, -}; - static void ipu_di_data_wave_config(struct ipu_di *di, int wave_gen, int access_size, int component_size) @@ -528,15 +398,125 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di, ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga)); } +static void ipu_di_config_clock(struct ipu_di *di, + const struct ipu_di_signal_cfg *sig) +{ + struct clk *clk; + unsigned clkgen0; + uint32_t val; + + if (sig->clkflags & IPU_DI_CLKMODE_EXT) { + /* + * CLKMODE_EXT means we must use the DI clock: this is + * needed for things like LVDS which needs to feed the + * DI and LDB with the same pixel clock. + */ + clk = di->clk_di; + + if (sig->clkflags & IPU_DI_CLKMODE_SYNC) { + /* + * CLKMODE_SYNC means that we want the DI to be + * clocked at the same rate as the parent clock. + * This is needed (eg) for LDB which needs to be + * fed with the same pixel clock. We assume that + * the LDB clock has already been set correctly. + */ + clkgen0 = 1 << 4; + } else { + /* + * We can use the divider. We should really have + * a flag here indicating whether the bridge can + * cope with a fractional divider or not. For the + * time being, let's go for simplicitly and + * reliability. + */ + unsigned long in_rate; + unsigned div; + + clk_set_rate(clk, sig->pixelclock); + + in_rate = clk_get_rate(clk); + div = (in_rate + sig->pixelclock / 2) / sig->pixelclock; + if (div == 0) + div = 1; + + clkgen0 = div << 4; + } + } else { + /* + * For other interfaces, we can arbitarily select between + * the DI specific clock and the internal IPU clock. See + * DI_GENERAL bit 20. We select the IPU clock if it can + * give us a clock rate within 1% of the requested frequency, + * otherwise we use the DI clock. + */ + unsigned long rate, clkrate; + unsigned div, error; + + clkrate = clk_get_rate(di->clk_ipu); + div = (clkrate + sig->pixelclock / 2) / sig->pixelclock; + rate = clkrate / div; + + error = rate / (sig->pixelclock / 1000); + + dev_dbg(di->ipu->dev, " IPU clock can give %lu with divider %u, error %d.%u%%\n", + rate, div, (signed)(error - 1000) / 10, error % 10); + + /* Allow a 1% error */ + if (error < 1010 && error >= 990) { + clk = di->clk_ipu; + + clkgen0 = div << 4; + } else { + unsigned long in_rate; + unsigned div; + + clk = di->clk_di; + + clk_set_rate(clk, sig->pixelclock); + + in_rate = clk_get_rate(clk); + div = (in_rate + sig->pixelclock / 2) / sig->pixelclock; + if (div == 0) + div = 1; + + clkgen0 = div << 4; + } + } + + di->clk_di_pixel = clk; + + /* Set the divider */ + ipu_di_write(di, clkgen0, DI_BS_CLKGEN0); + + /* + * Set the high/low periods. Bits 24:16 give us the falling edge, + * and bits 8:0 give the rising edge. LSB is fraction, and is + * based on the divider above. We want a 50% duty cycle, so set + * the falling edge to be half the divider. + */ + ipu_di_write(di, (clkgen0 >> 4) << 16, DI_BS_CLKGEN1); + + /* Finally select the input clock */ + val = ipu_di_read(di, DI_GENERAL) & ~DI_GEN_DI_CLK_EXT; + if (clk == di->clk_di) + val |= DI_GEN_DI_CLK_EXT; + ipu_di_write(di, val, DI_GENERAL); + + dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n", + sig->pixelclock, + clk_get_rate(di->clk_ipu), + clk_get_rate(di->clk_di), + clk == di->clk_di ? "DI" : "IPU", + clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4)); +} + int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) { u32 reg; u32 di_gen, vsync_cnt; u32 div; u32 h_total, v_total; - int ret; - unsigned long round; - struct clk *parent; dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n", di->id, sig->width, sig->height); @@ -544,33 +524,20 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0)) return -EINVAL; - if (sig->clkflags & IPU_DI_CLKMODE_EXT) - parent = di->clk_di; - else - parent = di->clk_ipu; - - ret = clk_set_parent(di->clk_di_pixel, parent); - if (ret) { - dev_err(di->ipu->dev, - "setting pixel clock to parent %s failed with %d\n", - __clk_get_name(parent), ret); - return ret; - } - - if (sig->clkflags & IPU_DI_CLKMODE_SYNC) - round = clk_get_rate(parent); - else - round = clk_round_rate(di->clk_di_pixel, sig->pixelclock); - - ret = clk_set_rate(di->clk_di_pixel, round); - h_total = sig->width + sig->h_sync_width + sig->h_start_width + sig->h_end_width; v_total = sig->height + sig->v_sync_width + sig->v_start_width + sig->v_end_width; + dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n", + clk_get_rate(di->clk_ipu), + clk_get_rate(di->clk_di), + sig->pixelclock); + mutex_lock(&di_mutex); + ipu_di_config_clock(di, sig); + div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff; div = div / 16; /* Now divider is integer portion */ @@ -654,7 +621,11 @@ EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel); int ipu_di_enable(struct ipu_di *di) { - int ret = clk_prepare_enable(di->clk_di_pixel); + int ret; + + WARN_ON(IS_ERR(di->clk_di_pixel)); + + ret = clk_prepare_enable(di->clk_di_pixel); if (ret) return ret; @@ -666,6 +637,8 @@ EXPORT_SYMBOL_GPL(ipu_di_enable); int ipu_di_disable(struct ipu_di *di) { + WARN_ON(IS_ERR(di->clk_di_pixel)); + ipu_module_disable(di->ipu, di->module); clk_disable_unprepare(di->clk_di_pixel); @@ -721,13 +694,6 @@ int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id, u32 module, struct clk *clk_ipu) { struct ipu_di *di; - int ret; - const char *di_parent[2]; - struct clk_init_data init = { - .ops = &clk_di_ops, - .num_parents = 2, - .flags = 0, - }; if (id > 1) return -ENODEV; @@ -749,45 +715,16 @@ int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id, if (!di->base) return -ENOMEM; - di_parent[0] = __clk_get_name(di->clk_ipu); - di_parent[1] = __clk_get_name(di->clk_di); - ipu_di_write(di, 0x10, DI_BS_CLKGEN0); - init.parent_names = (const char **)&di_parent; - di->clk_name = kasprintf(GFP_KERNEL, "%s_di%d_pixel", - dev_name(dev), id); - if (!di->clk_name) - return -ENOMEM; - - init.name = di->clk_name; - - di->clk_hw_out.init = &init; - di->clk_di_pixel = clk_register(dev, &di->clk_hw_out); - - if (IS_ERR(di->clk_di_pixel)) { - ret = PTR_ERR(di->clk_di_pixel); - goto failed_clk_register; - } - dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n", id, base, di->base); di->inuse = false; di->ipu = ipu; return 0; - -failed_clk_register: - - kfree(di->clk_name); - - return ret; } void ipu_di_exit(struct ipu_soc *ipu, int id) { - struct ipu_di *di = ipu->di_priv[id]; - - clk_unregister(di->clk_di_pixel); - kfree(di->clk_name); } diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c index 98070dd8c920..45213017fa4b 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c @@ -161,9 +161,6 @@ static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots, "dmfc: using %d slots starting from segment %d for IPU channel %d\n", slots, segment, dmfc->data->ipu_channel); - if (!dmfc) - return -EINVAL; - switch (slots) { case 1: field = DMFC_FIFO_SIZE_64; diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c index 22be104fbda9..a8d017854615 100644 --- a/drivers/staging/imx-drm/ipuv3-crtc.c +++ b/drivers/staging/imx-drm/ipuv3-crtc.c @@ -17,6 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ +#include #include #include #include @@ -284,6 +285,7 @@ static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type, ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT; break; + case DRM_MODE_ENCODER_TMDS: case DRM_MODE_ENCODER_NONE: ipu_crtc->di_clkflags = 0; break; @@ -334,7 +336,7 @@ err_out: } static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, - struct ipu_client_platformdata *pdata) + struct ipu_client_platformdata *pdata, struct drm_device *drm) { struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); int dp = -EINVAL; @@ -348,10 +350,8 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, return ret; } - ret = imx_drm_add_crtc(&ipu_crtc->base, - &ipu_crtc->imx_crtc, - &ipu_crtc_helper_funcs, THIS_MODULE, - ipu_crtc->dev->parent->of_node, pdata->di); + ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc, + &ipu_crtc_helper_funcs, ipu_crtc->dev->of_node); if (ret) { dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret); goto err_put_resources; @@ -399,43 +399,96 @@ err_put_resources: return ret; } -static int ipu_drm_probe(struct platform_device *pdev) +static struct device_node *ipu_drm_get_port_by_id(struct device_node *parent, + int port_id) { - struct ipu_client_platformdata *pdata = pdev->dev.platform_data; + struct device_node *port; + int id, ret; + + port = of_get_child_by_name(parent, "port"); + while (port) { + ret = of_property_read_u32(port, "reg", &id); + if (!ret && id == port_id) + return port; + + do { + port = of_get_next_child(parent, port); + if (!port) + return NULL; + } while (of_node_cmp(port->name, "port")); + } + + return NULL; +} + +static int ipu_drm_bind(struct device *dev, struct device *master, void *data) +{ + struct ipu_client_platformdata *pdata = dev->platform_data; + struct drm_device *drm = data; struct ipu_crtc *ipu_crtc; int ret; - if (!pdata) - return -EINVAL; - - ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; - - ipu_crtc = devm_kzalloc(&pdev->dev, sizeof(*ipu_crtc), GFP_KERNEL); + ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL); if (!ipu_crtc) return -ENOMEM; - ipu_crtc->dev = &pdev->dev; + ipu_crtc->dev = dev; - ret = ipu_crtc_init(ipu_crtc, pdata); + ret = ipu_crtc_init(ipu_crtc, pdata, drm); if (ret) return ret; - platform_set_drvdata(pdev, ipu_crtc); + dev_set_drvdata(dev, ipu_crtc); return 0; } -static int ipu_drm_remove(struct platform_device *pdev) +static void ipu_drm_unbind(struct device *dev, struct device *master, + void *data) { - struct ipu_crtc *ipu_crtc = platform_get_drvdata(pdev); + struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev); imx_drm_remove_crtc(ipu_crtc->imx_crtc); ipu_plane_put_resources(ipu_crtc->plane[0]); ipu_put_resources(ipu_crtc); +} +static const struct component_ops ipu_crtc_ops = { + .bind = ipu_drm_bind, + .unbind = ipu_drm_unbind, +}; + +static int ipu_drm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ipu_client_platformdata *pdata = dev->platform_data; + int ret; + + if (!dev->platform_data) + return -EINVAL; + + if (!dev->of_node) { + /* Associate crtc device with the corresponding DI port node */ + dev->of_node = ipu_drm_get_port_by_id(dev->parent->of_node, + pdata->di + 2); + if (!dev->of_node) { + dev_err(dev, "missing port@%d node in %s\n", + pdata->di + 2, dev->parent->of_node->full_name); + return -ENODEV; + } + } + + ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + return component_add(dev, &ipu_crtc_ops); +} + +static int ipu_drm_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &ipu_crtc_ops); return 0; } diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c index 34b642a12f8b..b0c9b6ce4854 100644 --- a/drivers/staging/imx-drm/ipuv3-plane.c +++ b/drivers/staging/imx-drm/ipuv3-plane.c @@ -72,8 +72,8 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, return -EFAULT; } - dev_dbg(ipu_plane->base.dev->dev, "phys = 0x%x, x = %d, y = %d", - cma_obj->paddr, x, y); + dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d", + &cma_obj->paddr, x, y); cpmem = ipu_get_cpmem(ipu_plane->ipu_ch); ipu_cpmem_set_stride(cpmem, fb->pitches[0]); diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c index 351d61dede00..c60b6c645f42 100644 --- a/drivers/staging/imx-drm/parallel-display.c +++ b/drivers/staging/imx-drm/parallel-display.c @@ -18,10 +18,12 @@ * MA 02110-1301, USA. */ +#include #include #include #include #include +#include #include #include